Просмотр исходного кода

git-svn-id: https://192.168.57.71/svn/qt@15 12fe181a-e57f-b044-8676-16dc139aa63e

xt_yuanxd 9 лет назад
Родитель
Сommit
50690d20f0
100 измененных файлов с 15887 добавлено и 0 удалено
  1. BIN
      jdc/chatServer/trunk/lib/anychat32/AnyChatServerSDK.dll
  2. BIN
      jdc/chatServer/trunk/lib/anychat32/anychatserver4java.dll
  3. BIN
      jdc/chatServer/trunk/lib/anychat64/AnyChatServerSDK.dll
  4. BIN
      jdc/chatServer/trunk/lib/anychat64/anychatserver4java.dll
  5. 297 0
      jdc/chatServer/trunk/pom.xml
  6. 113 0
      jdc/chatServer/trunk/src/main/java/com/bairuitech/anychat/AnyChatObjectDefine.java
  7. 60 0
      jdc/chatServer/trunk/src/main/java/com/bairuitech/anychat/AnyChatOutParam.java
  8. 49 0
      jdc/chatServer/trunk/src/main/java/com/bairuitech/anychat/AnyChatServerEvent.java
  9. 281 0
      jdc/chatServer/trunk/src/main/java/com/bairuitech/anychat/AnyChatServerSDK.java
  10. 18 0
      jdc/chatServer/trunk/src/main/java/com/bairuitech/anychat/AnyChatVerifyUserOutParam.java
  11. 15 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/anon/JsonIgnore.java
  12. 171 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/bean/ChatCmd.java
  13. 65 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/bean/CmdConsts.java
  14. 68 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/bean/MsgBean.java
  15. 35 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/controller/BaseController.java
  16. 42 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/controller/UserController.java
  17. 758 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/core/BusinessServer.java
  18. 32 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/core/CustomObjectMapper.java
  19. 41 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/core/DefaultCustomDateEditor.java
  20. 68 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/core/QuartzServlet.java
  21. 49 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/core/StringEscapeEditor.java
  22. 42 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/core/excel/ExcelData.java
  23. 91 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/core/excel/ExcelExporter.java
  24. 175 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/core/excel/ExcelFiller.java
  25. 129 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/core/excel/ExcelTemplate.java
  26. 75 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/model/GroupModel.java
  27. 201 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/model/MessageModel.java
  28. 146 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/model/TerTrailModel.java
  29. 74 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/model/TerminalModel.java
  30. 126 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/model/Tfile.java
  31. 158 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/model/Tlocation.java
  32. 82 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/model/Tlog.java
  33. 28 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/model/Tusermsg.java
  34. 93 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/model/UserModel.java
  35. 131 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/repository/GroupRepository.java
  36. 37 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/repository/IGroupRepository.java
  37. 40 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/repository/IMsgRepository.java
  38. 35 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/repository/ITerminalRepository.java
  39. 43 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/repository/IUserRepository.java
  40. 103 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/repository/MsgRepository.java
  41. 101 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/repository/TerminalRepository.java
  42. 118 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/repository/UserRepository.java
  43. 165 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/ChatCustomService.java
  44. 37 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/IGroupService.java
  45. 5 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/IMessageService.java
  46. 39 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/IMsgService.java
  47. 35 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/ITerminalService.java
  48. 44 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/IUserService.java
  49. 324 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/ChatCustomServiceImpl.java
  50. 70 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/GroupServiceImpl.java
  51. 29 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/MessageServiceImpl.java
  52. 47 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/MsgServiceImpl.java
  53. 35 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/TerminalServiceImpl.java
  54. 62 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/UserServiceImpl.java
  55. 72 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/task/MessageRemindTask.java
  56. 51 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/task/MessageSendService.java
  57. 17 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/task/base/BaseTask.java
  58. 57 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/task/base/TaskRedoException.java
  59. 73 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/task/base/TaskService.java
  60. 121 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/BeanUtil.java
  61. 230 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/CodeUtil.java
  62. 55 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/CustomGetMethod.java
  63. 397 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/DateUtil.java
  64. 46 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/GsonUtil.java
  65. 44 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/HttpMain.java
  66. 216 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/HttpProxy.java
  67. 32 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/IpUtils.java
  68. 63 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/JsonUtil.java
  69. 151 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/LogUtils.java
  70. 40 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/MsgEnum.java
  71. 29 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/NumberUtil.java
  72. 70 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/ResourceUtil.java
  73. 154 0
      jdc/chatServer/trunk/src/main/java/com/jsjty/util/StringUtil.java
  74. 29 0
      jdc/chatServer/trunk/src/main/resources/config.properties
  75. 32 0
      jdc/chatServer/trunk/src/main/resources/ehcache.xml
  76. 421 0
      jdc/chatServer/trunk/src/main/resources/ehcache.xsd
  77. 166 0
      jdc/chatServer/trunk/src/main/resources/log4j.dtd
  78. 139 0
      jdc/chatServer/trunk/src/main/resources/log4j.xml
  79. 117 0
      jdc/chatServer/trunk/src/main/resources/spring-context.xml
  80. 11 0
      jdc/chatServer/trunk/src/main/resources/spring-ehcache.xml
  81. 43 0
      jdc/chatServer/trunk/src/main/resources/spring-mvc.xml
  82. 13 0
      jdc/chatServer/trunk/src/main/resources/spring-tasks.xml
  83. 61 0
      jdc/chatServer/trunk/src/main/webapp/WEB-INF/web.xml
  84. 229 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/accordion.css
  85. 592 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/accordion.js
  86. 9 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/accordion.min.css
  87. 10 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/accordion.min.js
  88. 276 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/ad.css
  89. 10 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/ad.min.css
  90. 1077 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/api.js
  91. 10 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/api.min.js
  92. 125 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/breadcrumb.css
  93. 10 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/breadcrumb.min.css
  94. 3237 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/button.css
  95. 9 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/button.min.css
  96. 949 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/card.css
  97. 9 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/card.min.css
  98. 588 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/checkbox.css
  99. 706 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/checkbox.js
  100. 9 0
      jdc/chatServer/trunk/src/main/webapp/assets/components/checkbox.min.css

BIN
jdc/chatServer/trunk/lib/anychat32/AnyChatServerSDK.dll


BIN
jdc/chatServer/trunk/lib/anychat32/anychatserver4java.dll


BIN
jdc/chatServer/trunk/lib/anychat64/AnyChatServerSDK.dll


BIN
jdc/chatServer/trunk/lib/anychat64/anychatserver4java.dll


+ 297 - 0
jdc/chatServer/trunk/pom.xml

@@ -0,0 +1,297 @@
+<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">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>com.jsjty</groupId>
+	<artifactId>chatServer</artifactId>
+	<packaging>war</packaging>
+	<version>1.0-SNAPSHOT</version>
+	<name>MobileServer Maven Webapp</name>
+
+	<url>http://maven.apache.org</url>
+	<properties>
+		<jetty.version>8.1.8.v20121106</jetty.version>
+		<org.springframework-version>4.0.0.RELEASE</org.springframework-version>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+
+	<dependencies>
+		<!-- Spring -->
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-context</artifactId>
+			<version>${org.springframework-version}</version>
+
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-webmvc</artifactId>
+			<version>${org.springframework-version}</version>
+		</dependency>
+		<!-- 加入orm依赖包 -->
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-orm</artifactId>
+			<version>${org.springframework-version}</version>
+		</dependency>
+		<!-- ehcache需要的依赖 -->
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-context-support</artifactId>
+			<version>${org.springframework-version}</version>
+		</dependency>
+		<!-- 加入spring测试依赖包 -->
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-test</artifactId>
+			<version>${org.springframework-version}</version>
+		</dependency>
+		<!-- 加入druid数据源依赖包 -->
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>druid</artifactId>
+			<version>0.2.20</version>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+			<version>1.7.7</version>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-log4j12</artifactId>
+			<version>1.7.7</version>
+		</dependency>
+		<dependency>
+			<groupId>log4j</groupId>
+			<artifactId>log4j</artifactId>
+			<version>1.2.17</version>
+		</dependency>
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-core</artifactId>
+			<version>4.2.2.Final</version>
+		</dependency>
+		<dependency>
+			<groupId>com.google.guava</groupId>
+			<artifactId>guava</artifactId>
+			<version>18.0</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.codehaus.jackson</groupId>
+			<artifactId>jackson-core-asl</artifactId>
+			<version>1.9.13</version>
+		</dependency>
+		<dependency>
+			<groupId>org.codehaus.jackson</groupId>
+			<artifactId>jackson-mapper-asl</artifactId>
+			<version>1.9.13</version>
+		</dependency>
+		<!-- 加入junit依赖包 -->
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.11</version>
+			<scope>test</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>net.sf.ehcache</groupId>
+			<artifactId>ehcache</artifactId>
+			<version>2.8.0</version>
+		</dependency>
+
+		<!-- 加入mysql驱动依赖包 -->
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+			<version>5.1.25</version>
+		</dependency>
+		<!-- 加入fastjson依赖包 -->
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>fastjson</artifactId>
+			<version>1.1.31</version>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>2.5</version>
+		</dependency>
+
+		<dependency>
+			<groupId>javax.servlet.jsp</groupId>
+			<artifactId>jsp-api</artifactId>
+			<version>2.1</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.aspectj</groupId>
+			<artifactId>aspectjweaver</artifactId>
+			<version>1.7.2</version>
+		</dependency>
+
+		<dependency>
+			<groupId>commons-net</groupId>
+			<artifactId>commons-net</artifactId>
+			<version>3.3</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-codec</groupId>
+			<artifactId>commons-codec</artifactId>
+			<version>1.6</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.ehcache</groupId>
+			<artifactId>ehcache</artifactId>
+			<version>2.8.0</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-fileupload</groupId>
+			<artifactId>commons-fileupload</artifactId>
+			<version>1.3</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>2.4</version>
+		</dependency>
+		<dependency>
+			<groupId>com.google.code.gson</groupId>
+			<artifactId>gson</artifactId>
+			<version>2.3</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.solr</groupId>
+			<artifactId>solr-solrj</artifactId>
+			<version>4.10.2</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.poi</groupId>
+			<artifactId>poi</artifactId>
+			<version>3.10-FINAL</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
+			<version>4.3</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpmime</artifactId>
+			<version>4.3</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpcore</artifactId>
+			<version>4.3</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-codec</groupId>
+			<artifactId>commons-codec</artifactId>
+			<version>1.10</version>
+		</dependency>
+		<dependency>
+			<groupId>org.quartz-scheduler</groupId>
+			<artifactId>quartz</artifactId>
+			<version>1.8.4</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.shiro</groupId>
+			<artifactId>shiro-core</artifactId>
+			<version>1.2.3</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.json-lib</groupId>
+			<artifactId>json-lib</artifactId>
+			<classifier>jdk15</classifier>
+			<version>2.4</version>
+		</dependency>
+	</dependencies>
+	<build>
+		<finalName>${project.artifactId}</finalName>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>2.3</version>
+				<configuration>
+					<source>1.7</source>
+					<target>1.7</target>
+					<showWarnings>true</showWarnings>
+				</configuration>
+			</plugin>
+
+			<!-- war打包插件, 设定war包名称不带版本号 -->
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-war-plugin</artifactId>
+				<version>2.4</version>
+				<configuration>
+					<warName>${project.artifactId}</warName>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-javadoc-plugin</artifactId>
+				<version>2.10.2</version>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-source-plugin</artifactId>
+				<version>2.4</version>
+			</plugin>
+			<!-- jetty插件, 设定context path与spring profile -->
+			<plugin>
+				<groupId>org.mortbay.jetty</groupId>
+				<artifactId>jetty-maven-plugin</artifactId>
+				<version>${jetty.version}</version>
+				<configuration>
+					<webAppConfig>
+
+						<contextPath>/${project.build.finalName}</contextPath>
+					</webAppConfig>
+				</configuration>
+			</plugin>
+			<!-- tomcat7 插件 -->
+			<plugin>
+				<groupId>org.apache.tomcat.maven</groupId>
+				<artifactId>tomcat7-maven-plugin</artifactId>
+				<version>2.2</version>
+				<configuration>
+					<path>${project.build.finalName}</path>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<version>2.5.3</version>
+				<configuration>
+					<archive>
+						<manifest>
+							<mainClass></mainClass>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-site-plugin</artifactId>
+				<version>3.4</version>
+				<configuration>
+					<locales>zh_CN</locales>
+					<outputEncoding>UTF-8</outputEncoding>
+					<inputEncoding>UTF-8</inputEncoding>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<version>2.12.4</version>
+				<configuration>
+					<skipTests>true</skipTests>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>

+ 113 - 0
jdc/chatServer/trunk/src/main/java/com/bairuitech/anychat/AnyChatObjectDefine.java

@@ -0,0 +1,113 @@
+package com.bairuitech.anychat;
+
+public class AnyChatObjectDefine {
+
+	// 对象类型定义
+	public static final int ANYCHAT_OBJECT_TYPE_AREA		=	4;		///< 服务区域
+	public static final int ANYCHAT_OBJECT_TYPE_QUEUE		=	5;		///< 队列对象
+	public static final int ANYCHAT_OBJECT_TYPE_AGENT		=	6;		///< 客服对象
+	public static final int ANYCHAT_OBJECT_TYPE_CLIENTUSER	=	8;		///< 客户端用户对象,用于与服务器交换数据
+
+	// 通用标识定义
+	public static final int ANYCHAT_OBJECT_FLAGS_CLIENT		=	0;		///< 普通客户
+	public static final int ANYCHAT_OBJECT_FLAGS_AGENT		=	2;		///< 坐席用户
+	public static final int ANYCHAT_OBJECT_FLAGS_MANANGER	=	4;		///< 管理用户
+
+	public static final int ANYCHAT_INVALID_OBJECT_ID		=	-1;		///< 无效的对象ID
+
+	// 坐席服务状态定义
+	public static final int ANYCHAT_AGENT_STATUS_CLOSEED	=	0;		///< 关闭,不对外提供服务
+	public static final int ANYCHAT_AGENT_STATUS_WAITTING	=	1;		///< 等待中,可随时接受用户服务
+	public static final int ANYCHAT_AGENT_STATUS_WORKING	=	2;		///< 工作中,正在为用户服务
+	public static final int ANYCHAT_AGENT_STATUS_PAUSED		=	3;		///< 暂停服务
+
+
+	/**
+	 *	对象属性定义
+	 */
+
+	// 对象公共信息类型定义
+	public static final int ANYCHAT_OBJECT_INFO_FLAGS		=	7;		///< 对象属性标志
+	public static final int ANYCHAT_OBJECT_INFO_NAME		=	8;		///< 对象名称
+	public static final int ANYCHAT_OBJECT_INFO_PRIORITY	=	9;		///< 对象优先级
+	public static final int ANYCHAT_OBJECT_INFO_ATTRIBUTE	=	10;		///< 对象业务属性
+	public static final int ANYCHAT_OBJECT_INFO_DESCRIPTION	=	11;		///< 对象描述
+	public static final int ANYCHAT_OBJECT_INFO_INTTAG		=	12;		///< 对象标签,整型,上层应用自定义
+	public static final int ANYCHAT_OBJECT_INFO_STRINGTAG	=	13;		///< 对象标签,字符串,上层应用自定义
+
+	// 服务区域信息类型定义
+	public static final int ANYCHAT_AREA_INFO_AGENTCOUNT	=	401;	///< 服务区域客服用户数
+	public static final int ANYCHAT_AREA_INFO_GUESTCOUNT	=	402;	///< 服务区域内访客的用户数(没有排入队列的用户)
+	public static final int ANYCHAT_AREA_INFO_QUEUEUSERCOUNT=	403;	///< 服务区域内排队的用户数
+	public static final int ANYCHAT_AREA_INFO_QUEUECOUNT	=	404;	///< 服务区域内队列的数量
+
+	// 队列状态信息类型定义
+	public static final int ANYCHAT_QUEUE_INFO_MYSEQUENCENO	=	501;	///< 自己在该队列中的序号
+	public static final int ANYCHAT_QUEUE_INFO_BEFOREUSERNUM=	502;	///< 排在自己前	面的用户数
+	public static final int ANYCHAT_QUEUE_INFO_MYENTERQUEUETIME=503;	///< 进入队列的时间
+	public static final int ANYCHAT_QUEUE_INFO_LENGTH		=	504;	///< 队列长度(有多少人在排队),整型
+	public static final int ANYCHAT_QUEUE_INFO_WAITTIMESECOND=	508;	///< 自己在队列中的等待时间(排队时长),单位:秒
+
+	// 客服状态信息类型定义
+	public static final int ANYCHAT_AGENT_INFO_SERVICESTATUS=	601;	///< 服务状态,整型
+	public static final int ANYCHAT_AGENT_INFO_SERVICEUSERID=	602;	///< 当前服务的用户ID,整型
+	public static final int ANYCHAT_AGENT_INFO_SERVICEBEGINTIME=603;	///< 当前服务的开始时间,整型
+	public static final int ANYCHAT_AGENT_INFO_SERVICETOTALTIME=604;	///< 累计服务时间,整型,单位:秒
+	public static final int ANYCHAT_AGENT_INFO_SERVICETOTALNUM=	605;	///< 累计服务的用户数,整型
+
+
+	/**
+	 *	对象方法定义
+	 */
+
+	// 对象公共参数控制常量定义
+	public static final int ANYCHAT_OBJECT_CTRL_CREATE		=	2;		///< 创建一个对象
+	public static final int ANYCHAT_OBJECT_CTRL_SYNCDATA	=	3;		///< 同步对象数据给指定用户,dwObjectId=-1,表示同步该类型的所有对象
+	public static final int ANYCHAT_OBJECT_CTRL_DEBUGOUTPUT	=	4;		///< 对象调试信息输出
+
+	// 服务区域控制常量定义
+	public static final int ANYCHAT_AREA_CTRL_USERENTER		=	401;	///< 进入服务区域
+	public static final int ANYCHAT_AREA_CTRL_USERLEAVE		=	402;	///< 离开服务区域
+
+	// 队列参数控制常量定义
+	public static final int ANYCHAT_QUEUE_CTRL_USERENTER	=	501;	///< 进入队列
+	public static final int ANYCHAT_QUEUE_CTRL_USERLEAVE	=	502;	///< 离开队列
+
+	// 客服参数控制常量定义
+	public static final int ANYCHAT_AGENT_CTRL_SERVICESTATUS=	601;	///< 坐席服务状态控制(暂停服务、工作中、关闭)
+	public static final int ANYCHAT_AGENT_CTRL_SERVICEREQUEST=	602;	///< 服务请求
+	public static final int ANYCHAT_AGENT_CTRL_FINISHSERVICE=	604;	///< 结束服务
+	public static final int ANYCHAT_AGENT_CTRL_EVALUATION	=	605;	///< 服务评价,wParam为客服userid,lParam为评分,lpStrValue为留言
+
+
+
+	/**
+	 *	对象异步事件定义
+	 */
+
+	// 对象公共事件常量定义
+	public static final int ANYCHAT_OBJECT_EVENT_UPDATE			= 1;	///< 对象数据更新
+	public static final int ANYCHAT_OBJECT_EVENT_SYNCDATAFINISH = 2;	///< 对象数据同步结束
+
+	// 服务区域事件常量定义
+	public static final int ANYCHAT_AREA_EVENT_STATUSCHANGE	=	401;	///< 服务区域状态变化
+	public static final int ANYCHAT_AREA_EVENT_ENTERRESULT	=	402;	///< 进入服务区域结果
+	public static final int ANYCHAT_AREA_EVENT_USERENTER	=	403;	///< 用户进入服务区域
+	public static final int ANYCHAT_AREA_EVENT_USERLEAVE	=	404;	///< 用户离开服务区域
+	public static final int ANYCHAT_AREA_EVENT_LEAVERESULT	=	405;	///< 离开服务区域结果
+
+	// 队列事件常量定义
+	public static final int ANYCHAT_QUEUE_EVENT_STATUSCHANGE=	501;	///< 队列状态变化
+	public static final int ANYCHAT_QUEUE_EVENT_ENTERRESULT	=	502;	///< 进入队列结果
+	public static final int ANYCHAT_QUEUE_EVENT_USERENTER	=	503;	///< 用户进入队列
+	public static final int ANYCHAT_QUEUE_EVENT_USERLEAVE	=	504;	///< 用户离开队列
+	public static final int ANYCHAT_QUEUE_EVENT_LEAVERESULT	=	505;	///< 离开队列结果
+
+	// 坐席事件常量定义
+	public static final int ANYCHAT_AGENT_EVENT_STATUSCHANGE=	601;	///< 坐席状态变化
+	public static final int ANYCHAT_AGENT_EVENT_SERVICENOTIFY=	602;	///< 坐席服务通知(哪个用户到哪个客服办理业务)
+	public static final int ANYCHAT_AGENT_EVENT_WAITINGUSER	=	603;	///< 暂时没有客户,请等待
+
+	
+	
+}

+ 60 - 0
jdc/chatServer/trunk/src/main/java/com/bairuitech/anychat/AnyChatOutParam.java

@@ -0,0 +1,60 @@
+package com.bairuitech.anychat; // 不能修改包的名称
+
+
+/**
+ * 通用函数返回参数类
+ * AnyChat内核调用Set方法设置参数,上层应用通过Get方法获取值
+ */
+public class AnyChatOutParam {
+    private int iValue = 0;
+    private String szValue = "";
+    private int[] intArray;
+    private byte[] byteArray;
+    private double fValue = 0.0;
+
+    public int GetIntValue() {
+        return iValue;
+    }
+
+    public void SetIntValue(int v) {
+        iValue = v;
+    }
+
+    public double GetFloatValue() {
+        return fValue;
+    }
+
+    public void SetFloatValue(double f) {
+        fValue = f;
+    }
+
+    public String GetStrValue() {
+        return szValue;
+    }
+
+    public void SetStrValue(String s) {
+        szValue = s;
+    }
+
+    @Override
+    public String toString() {
+        return "AnyChatOutParam [iValue=" + iValue + ", szValue=" + szValue + ", intArrayLength=" + intArray.length
+                + ", byteArrayLength=" + byteArray.length + ", fValue=" + fValue + "]";
+    }
+
+    public int[] GetIntArray() {
+        return intArray;
+    }
+
+    public void SetIntArray(int[] a) {
+        intArray = a;
+    }
+
+    public byte[] GetByteArray() {
+        return byteArray;
+    }
+
+    public void SetByteArray(byte[] b) {
+        byteArray = b;
+    }
+}

+ 49 - 0
jdc/chatServer/trunk/src/main/java/com/bairuitech/anychat/AnyChatServerEvent.java

@@ -0,0 +1,49 @@
+package com.bairuitech.anychat;
+
+import com.bairuitech.anychat.AnyChatVerifyUserOutParam;
+
+// 数据传输通知接口
+public interface AnyChatServerEvent {
+	
+	// 服务器应用程序消息回调函数定义
+	public void OnAnyChatServerAppMessageExCallBack(int dwNotifyMessage, int wParam, int lParam);
+	// SDK定时器回调函数定义
+	public void OnAnyChatTimerEventCallBack();
+	
+	// 用户身份验证回调函数定义
+	public int OnAnyChatVerifyUserCallBack(String szUserName, String szPassword, AnyChatVerifyUserOutParam outParam);
+	// 用户登录成功回调函数定义
+	public void OnAnyChatUserLoginActionCallBack(int dwUserId, String szUserName, int dwLevel, String szIpAddr);
+	// 用户注销回调函数定义
+	public void OnAnyChatUserLogoutActionExCallBack(int dwUserId, int dwErrorCode);
+	
+	// 用户申请进入房间回调函数定义
+	public int OnAnyChatPrepareEnterRoomCallBack(int dwUserId, int dwRoomId, String szRoomName, String szPassword);
+	// 用户进入房间回调函数定义
+	public void OnAnyChatUserEnterRoomActionCallBack(int dwUserId, int dwRoomId);
+	// 用户离开房间回调函数定义
+	public void OnAnyChatUserLeaveRoomActionCallBack(int dwUserId, int dwRoomId);
+	
+	// 文件传输回调函数定义
+	public void OnAnyChatTransFile(int dwUserId, String szFileName, String szTempFilePath, int dwFileLength, int wParam, int lParam, int dwTaskId);
+	// 透明通道数据回调函数定义
+	public void OnAnyChatTransBuffer(int dwUserId, byte[] lpBuf, int dwLen);
+	// 扩展透明通道数据回调函数定义
+	public void OnAnyChatTransBufferEx(int dwUserId, byte[] lpBuf, int dwLen, int wParam, int lParam, int dwTaskId);
+	// SDK Filter 通信数据回调函数定义
+	public void OnAnyChatSDKFilterData(int dwUserId, byte[] lpBuf, int dwLen);
+	
+	// 收到用户文字聊天通信数据回调函数定义
+	public void OnAnyChatRecvUserTextMsgCallBack(int dwRoomId, int dwSrcUserId, int dwTarUserId, int bSecret, String szTextMessage, int dwLen);
+	// 服务器录像回调函数定义(扩展)
+	public void OnAnyChatServerRecordExCallBack(int dwUserId, String szRecordFileName, int dwElapse, int dwFlags, int dwParam, String lpUserStr, int dwRecordServerId);
+	
+	// 视频通话消息通知回调函数定义
+	public int OnAnyChatVideoCallEventCallBack(int dwEventType, int dwSrcUserId, int dwTarUserId, int dwErrorCode, int dwFlags, int dwParam, String lpUserStr);
+	
+	// 用户信息控制回调函数定义
+	public int OnAnyChatUserInfoCtrlCallBack(int dwSendUserId, int dwUserId, int dwCtrlCode, int wParam, int lParam, String lpStrValue);
+	
+	// 业务对象事件回调函数定义
+	public int OnAnyChatObjectEventCallBack(int dwObjectType, int dwObjectId, int dwEventType, int dwParam1, int dwParam2, int dwParam3, int dwParam4, String lpStrParam);
+}

+ 281 - 0
jdc/chatServer/trunk/src/main/java/com/bairuitech/anychat/AnyChatServerSDK.java

@@ -0,0 +1,281 @@
+package com.bairuitech.anychat; // 不能修改包的名称
+
+public class AnyChatServerSDK {
+    public static final int BRAS_MESSAGE_CORESERVERCONN = 10; ///< 与核心服务器的连接消息,wParam为errorcode
+    public static final int BRAS_MESSAGE_RECORDSERVERCONN = 11; ///< 与录像服务器的连接消息,wParam为errorcode,lParam为recordserverid
+    public static final int BRAS_MESSAGE_LOGINSERVERCONN = 12; ///< 与登录服务器的连接消息,wParam为errorcode,lParam为loginserverid
+    public static final int BRAS_MESSAGE_ROOMSERVERCONN = 13; ///< 与房间服务器的连接消息,wParam为errorcode,lParam为roomserverid
+    public static final int BRAS_MESSAGE_MEDIASERVERCONN = 14; ///< 与流媒体服务器的连接消息,wParam为errorcode,lParam为mediaserverid
+
+    // 视频呼叫事件类型定义(API:BRAS_VideoCallControl 传入参数、OnVideoCallEvent回调参数)
+    public static final int BRAS_VIDEOCALL_EVENT_REQUEST = 1; ///< 呼叫请求
+    public static final int BRAS_VIDEOCALL_EVENT_REPLY = 2; ///< 呼叫请求回复
+    public static final int BRAS_VIDEOCALL_EVENT_START = 3; ///< 视频呼叫会话开始事件
+    public static final int BRAS_VIDEOCALL_EVENT_FINISH = 4; ///< 挂断(结束)呼叫会话
+
+    // 用户信息控制类型定义(API:BRAS_UserInfoControl 传入参数、OnUserInfoControl回调参数)
+    public static final int BRAS_USERINFO_CTRLCODE_KICKOUT = 1; ///< 将指定用户从系统中踢掉
+    public static final int BRAS_USERINFO_CTRLCODE_SYNCDATA = 2; ///< 将指定用户的数据同步给客户端
+    public static final int BRAS_USERINFO_CTRLCODE_FUNCCTRL = 3; ///< 客户端功能控制,wParam为功能参数组合
+    public static final int BRAS_USERINFO_CTRLCODE_ADDGROUP = 20; ///< 添加用户分组,wParam为分组Id,lpStrValue为分组名称
+    public static final int BRAS_USERINFO_CTRLCODE_DELGROUP = 21; ///< 删除用户分组,wParam为分组Id
+    public static final int BRAS_USERINFO_CTRLCODE_ADDFRIEND = 22; ///< 添加用户好友,wParam为好友Id
+    public static final int BRAS_USERINFO_CTRLCODE_DELFRIEND = 23; ///< 删除用户好友,wParam为好友Id
+    public static final int BRAS_USERINFO_CTRLCODE_SETGROUPRELATION = 24; ///< 设置好友与分组的关联关系,wParam为分组Id,lParam为好友Id,表示好友属于某个分组
+    // 用户分组及好友列表信息
+    public static final int BRAS_USERINFO_CTRLCODE_LISTGROUP = 220; /// 设置用户分组及好友列表
+    public static final int BRAS_USERINFO_CTRLCODE_USERFACE = 221; /// 客户端用,获取用户头像
+
+    // 内核参数控制(API:SetSDKOption 传入参数)
+    public static final int BRAS_SO_GETTRANSBUFTIMESTAMP = 1; ///< 获取透明通道时间戳(传入参数为userid)
+    public static final int BRAS_SO_RECORD_VIDEOBR = 2; ///< 录像视频码率设置(参数为:int型,单位:bps)
+    public static final int BRAS_SO_RECORD_AUDIOBR = 3; ///< 录像音频码率设置(参数为:int型,单位:bps)
+    public static final int BRAS_SO_RECORD_FILETYPE = 4; ///< 录制文件类型设置(参数为:int型, 0 MP4[默认], 1 WMV, 2 FLV, 3 MP3)
+    public static final int BRAS_SO_RECORD_WIDTH = 5; ///< 录制视频宽度设置(参数为:int型,如:320)
+    public static final int BRAS_SO_RECORD_HEIGHT = 6; ///< 录制文件高度设置(参数为:int型,如:240)
+    public static final int BRAS_SO_RECORD_FILENAMERULE = 7; ///< 录制文件名命名规则(参数为:int型)
+    public static final int BRAS_SO_RECORD_CLIPMODE = 8; ///< 录制视频裁剪模式(参数为:int型)
+    public static final int BRAS_SO_CORESDK_WRITELOG = 20; ///< 写入调试信息到日志文件中
+
+    // 初始化标志(API:BRAS_InitSDK 传入参数)
+    public static final int BRAS_INITFLAGS_MULTITHREADS = 1; ///< 多线程模式
+
+    // 录像功能标志定义(API:BRAS_StreamRecordCtrl 传入参数)
+    public static final int ANYCHAT_RECORD_FLAGS_VIDEO = 0x00000001; ///< 录制视频
+    public static final int ANYCHAT_RECORD_FLAGS_AUDIO = 0x00000002; ///< 录制音频
+    public static final int ANYCHAT_RECORD_FLAGS_SERVER = 0x00000004; ///< 服务器端录制
+    public static final int ANYCHAT_RECORD_FLAGS_MIXAUDIO = 0x00000010; ///< 录制音频时,将其它人的声音混音后录制
+    public static final int ANYCHAT_RECORD_FLAGS_MIXVIDEO = 0x00000020; ///< 录制视频时,将其它人的视频迭加后录制
+    public static final int ANYCHAT_RECORD_FLAGS_ABREAST = 0x00000100; ///< 录制视频时,将其它人的视频并列录制
+    public static final int ANYCHAT_RECORD_FLAGS_STEREO = 0x00000200; ///< 录制音频时,将其它人的声音混合为立体声后录制
+    public static final int ANYCHAT_RECORD_FLAGS_SNAPSHOT = 0x00000400; ///< 拍照
+    public static final int ANYCHAT_RECORD_FLAGS_LOCALCB = 0x00000800; ///< 触发本地回调
+
+    // 视频裁剪模式定义
+    public static final int ANYCHAT_VIDEOCLIPMODE_AUTO = 0; ///< 默认模式,以最大比例进行裁剪,然后再整体拉伸,画面保持比例,但被裁剪画面较大
+    public static final int ANYCHAT_VIDEOCLIPMODE_OVERLAP = 1; ///< 重叠模式,只取最大有效部分,对边缘进行裁剪
+    public static final int ANYCHAT_VIDEOCLIPMODE_SHRINK = 2; ///< 缩小模式,缩小到合适的比例,不进行裁剪
+    public static final int ANYCHAT_VIDEOCLIPMODE_STRETCH = 3; ///< 平铺模式,不进行裁剪,但可能导致画面不成比例
+    public static final int ANYCHAT_VIDEOCLIPMODE_DYNAMIC = 4; ///< 动态模式,由上层应用根据分辩率来调整显示表面,保持画面不变形
+
+    AnyChatServerEvent event;
+
+    // 设置事件回调通知接口
+    public void SetServerEvent(AnyChatServerEvent e) {
+        RegisterNotify();
+        this.event = e;
+    }
+
+    // 查询SDK版本信息、编译时间等
+    public native String GetSDKVersion();
+
+    // 注册消息通知
+    public native int RegisterNotify();
+
+    // 注册用户身份验证回调类(部署到Web容器中需要调用)
+    public native int RegisterVerifyUserClass(AnyChatVerifyUserOutParam ParamObject);
+
+    // 初始化SDK
+    public native int InitSDK(int flags);
+
+    // 释放资源
+    public native int Release();
+
+    // 设置SDK定时器回调函数(dwElapse:定时器间隔,单位:ms)
+    public native int SetTimerEventCallBack(int elapse);
+
+    // 传送文件
+    public static native int TransFile(int userid, String filepath, int wparam, int lparam, int flags,
+            AnyChatOutParam outParam);
+
+    // 透明通道传送缓冲区
+    public static native int TransBuffer(int userid, byte[] buf, int len);
+
+    // 透明通道传送缓冲区扩展
+    public static native int TransBufferEx(int userid, byte[] buf, int len, int wparam, int lparam, int flags,
+            AnyChatOutParam outParam);
+
+    // 发送SDK Filter 通信数据
+    public static native int SendSDKFilterData(byte[] buf, int len);
+
+    // 向指定用户发送数据
+    public static native int SendBufToUser(int userid, byte[] buf, int len);
+
+    // 向指定房间发送数据
+    public static native int SendBufToRoom(int roomid, byte[] buf, int len);
+
+    // 中心端录像控制
+    public static native int StreamRecordCtrl(int dwUserId, int bStartRecord, int dwFlags, int dwParam,
+            int dwRecordServerId);
+
+    // 中心端录像控制(扩展)
+    public static native int StreamRecordCtrlEx(int dwUserId, int bStartRecord, int dwFlags, int dwParam,
+            String lpUserStr, int dwRecordServerId);
+
+    // 发送透明通道数据给录像服务器
+    public static native int TransBuffer2RecordServer(int dwUserId, byte[] buf, int len, int dwParam,
+            int dwRecordServerId);
+
+    // 视频呼叫事件控制(请求、回复、挂断等)
+    public static native int VideoCallControl(int dwEventType, int dwUserId, int dwErrorCode, int dwFlags, int dwParam,
+            String lpUserStr);
+
+    // 设置用户的详细信息
+    public static native int SetUserInfo(int dwUserId, int dwInfoId, String lpInfoValue, int dwFlags);
+
+    // 获取用户的详细信息
+    public static native String GetUserInfo(int dwUserId, int dwInfoId);
+
+    // 用户信息控制
+    public static native int UserInfoControl(int dwUserId, int dwCtrlCode, int wParam, int lParam, String lpStrValue);
+
+    // SDK内核参数设置(整型)
+    public static native int SetSDKOptionInt(int optname, int dwValue);
+
+    // SDK内核参数设置(字符串)
+    public static native int SetSDKOptionString(int optname, String lpStrValue);
+
+    // 获取业务对象列表
+    public static native int[] ObjectGetIdList(int dwObjectType);
+
+    // 获取业务对象参数值(整型)
+    public static native int ObjectGetIntValue(int dwObjectType, int dwObjectId, int dwInfoName);
+
+    // 获取业务对象参数值(字符串)
+    public static native String ObjectGetStringValue(int dwObjectType, int dwObjectId, int dwInfoName);
+
+    // 业务对象参数设置(整形)
+    public static native int ObjectSetIntValue(int dwObjectType, int dwObjectId, int dwInfoName, int dwValue);
+
+    // 业务对象参数设置(字符串)
+    public static native int ObjectSetStringValue(int dwObjectType, int dwObjectId, int dwInfoName, String lpStrValue);
+
+    // 业务对象参数控制
+    public static native int ObjectControl(int dwObjectType, int dwObjectId, int dwCtrlCode, int dwParam1,
+            int dwParam2, int dwParam3, int dwParam4, String lpStrValue);
+
+    // 获取在线用户ID列表(dwRoomId=-1时,表示获取系统所有房间的ID列表)
+    public static native int[] GetOnlineUsers(int dwRoomId);
+
+    // 获取房间ID列表(系统所有活动的房间)
+    public static native int[] GetRoomIdList();
+
+    // 向核心服务器动态查询相关信息(整型)
+    public static native int QueryIntInfoFromServer(int dwInfoName, String lpInParam, int dwFlags);
+
+    // 向核心服务器动态查询相关信息(字符串)
+    public static native String QueryStringInfoFromServer(int dwInfoName, String lpInParam, int dwFlags);
+
+    // 服务器应用程序消息回调函数定义
+    private void OnAnyChatServerAppMessageExCallBack(int dwNotifyMessage, int wParam, int lParam) {
+        if (this.event != null) this.event.OnAnyChatServerAppMessageExCallBack(dwNotifyMessage, wParam, lParam);
+    }
+
+    // SDK定时器回调函数定义
+    private void OnAnyChatTimerEventCallBack() {
+        if (this.event != null) this.event.OnAnyChatTimerEventCallBack();
+    }
+
+    // 用户身份验证回调函数定义
+    private int OnAnyChatVerifyUserCallBack(String szUserName, String szPassword, AnyChatVerifyUserOutParam outParam) {
+        int ret = -1;
+        if (this.event != null) ret = this.event.OnAnyChatVerifyUserCallBack(szUserName, szPassword, outParam);
+        return ret;
+    }
+
+    // 用户登录成功回调函数定义
+    private void OnAnyChatUserLoginActionCallBack(int dwUserId, String szUserName, int dwLevel, String szIpAddr) {
+        if (this.event != null) this.event.OnAnyChatUserLoginActionCallBack(dwUserId, szUserName, dwLevel, szIpAddr);
+    }
+
+    // 用户注销回调函数定义
+    private void OnAnyChatUserLogoutActionExCallBack(int dwUserId, int dwErrorCode) {
+        if (this.event != null) this.event.OnAnyChatUserLogoutActionExCallBack(dwUserId, dwErrorCode);
+    }
+
+    // 用户申请进入房间回调函数定义
+    private int OnAnyChatPrepareEnterRoomCallBack(int dwUserId, int dwRoomId, String szRoomName, String szPassword) {
+        int errorcode = -1;
+        if (this.event != null)
+            errorcode = this.event.OnAnyChatPrepareEnterRoomCallBack(dwUserId, dwRoomId, szRoomName, szPassword);
+        return errorcode;
+    }
+
+    // 用户进入房间回调函数定义
+    private void OnAnyChatUserEnterRoomActionCallBack(int dwUserId, int dwRoomId) {
+        if (this.event != null) this.event.OnAnyChatUserEnterRoomActionCallBack(dwUserId, dwRoomId);
+    }
+
+    // 用户离开房间回调函数定义
+    private void OnAnyChatUserLeaveRoomActionCallBack(int dwUserId, int dwRoomId) {
+        if (this.event != null) this.event.OnAnyChatUserLeaveRoomActionCallBack(dwUserId, dwRoomId);
+    }
+
+    // 文件传输回调函数定义
+    private void OnAnyChatTransFileCallBack(int dwUserId, String szFileName, String szTempFilePath, int dwFileLength,
+            int wParam, int lParam, int dwTaskId) {
+        if (this.event != null)
+            this.event.OnAnyChatTransFile(dwUserId, szFileName, szTempFilePath, dwFileLength, wParam, lParam, dwTaskId);
+    }
+
+    // 缓冲区回调函数定义
+    private void OnAnyChatTransBufferCallBack(int dwUserId, byte[] lpBuf, int dwLen) {
+        if (this.event != null) this.event.OnAnyChatTransBuffer(dwUserId, lpBuf, dwLen);
+    }
+
+    // 缓冲区扩展回调函数定义
+    private void OnAnyChatTransBufferExCallBack(int dwUserId, byte[] lpBuf, int dwLen, int wParam, int lParam,
+            int dwTaskId) {
+        if (this.event != null) this.event.OnAnyChatTransBufferEx(dwUserId, lpBuf, dwLen, wParam, lParam, dwTaskId);
+    }
+
+    // 服务器发送的SDK Filter Data数据回调函数定义
+    private void OnAnyChatSDKFilterDataCallBack(int dwUserId, byte[] buf, int len) {
+        if (this.event != null) this.event.OnAnyChatSDKFilterData(dwUserId, buf, len);
+    }
+
+    // 收到用户文字聊天通信数据回调函数定义
+    private void OnAnyChatRecvUserTextMsgCallBack(int dwRoomId, int dwSrcUserId, int dwTarUserId, int bSecret,
+            String szTextMessage, int dwLen) {
+        if (this.event != null)
+            this.event.OnAnyChatRecvUserTextMsgCallBack(dwRoomId, dwSrcUserId, dwTarUserId, bSecret, szTextMessage,
+                    dwLen);
+    }
+
+    // 服务器录像回调函数定义
+    private void OnAnyChatServerRecordExCallBack(int dwUserId, String lpFileName, int dwElapse, int dwFlags,
+            int dwParam, String lpUserStr, int dwRecordServerId) {
+        if (this.event != null)
+            this.event.OnAnyChatServerRecordExCallBack(dwUserId, lpFileName, dwElapse, dwFlags, dwParam, lpUserStr,
+                    dwRecordServerId);
+    }
+
+    // 视频通话消息通知回调函数定义
+    private int OnAnyChatVideoCallEventCallBack(int dwEventType, int dwSrcUserId, int dwTarUserId, int dwErrorCode,
+            int dwFlags, int dwParam, String lpUserStr) {
+        if (this.event != null) return this.event.OnAnyChatVideoCallEventCallBack(dwEventType, dwSrcUserId,
+                dwTarUserId, dwErrorCode, dwFlags, dwParam, lpUserStr);
+        else return -1;
+    }
+
+    // 用户信息控制回调函数定义
+    private int OnAnyChatUserInfoCtrlCallBack(int dwSendUserId, int dwUserId, int dwCtrlCode, int wParam, int lParam,
+            String lpStrValue) {
+        if (this.event != null) return this.event.OnAnyChatUserInfoCtrlCallBack(dwSendUserId, dwUserId, dwCtrlCode,
+                wParam, lParam, lpStrValue);
+        else return -1;
+    }
+
+    // 业务对象事件回调函数定义
+    private int OnAnyChatObjectEventNotifyCallBack(int dwObjectType, int dwObjectId, int dwEventType, int dwParam1,
+            int dwParam2, int dwParam3, int dwParam4, String lpStrParam) {
+        if (this.event != null) return this.event.OnAnyChatObjectEventCallBack(dwObjectType, dwObjectId, dwEventType,
+                dwParam1, dwParam2, dwParam3, dwParam4, lpStrParam);
+        else return -1;
+    }
+
+    static {
+        System.loadLibrary("anychatserver4java");
+    }
+
+}

+ 18 - 0
jdc/chatServer/trunk/src/main/java/com/bairuitech/anychat/AnyChatVerifyUserOutParam.java

@@ -0,0 +1,18 @@
+package com.bairuitech.anychat;		// 不能修改包的名称
+
+
+public class AnyChatVerifyUserOutParam{
+	private int userid;
+	private int userlevel;
+	private String nickname;
+	
+	public int GetUserId()	{ return userid; }
+	public void SetUserId(int id) {	userid = id; }
+	
+	public int GetUserLevel() {	return userlevel;	}
+	public void SetUserLevel(int level)	{	userlevel = level;	}
+	
+	public String GetNickName()	{	return nickname;	}
+	public void SetNickName(String name)	{	nickname = name;	}
+}
+

+ 15 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/anon/JsonIgnore.java

@@ -0,0 +1,15 @@
+package com.jsjty.anon;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * 必须声明在jvm中保留(RetentionPolicy.RUNTIME)
+ * 
+ * @author Administrator
+ * 
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface JsonIgnore {
+
+}

+ 171 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/bean/ChatCmd.java

@@ -0,0 +1,171 @@
+package com.jsjty.bean;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.jsjty.anon.JsonIgnore;
+
+import net.sf.json.JSONObject;
+import net.sf.json.JsonConfig;
+
+/**
+ * anychat交互数据格式
+ * 
+ * @author 袁晓冬
+ *
+ */
+public class ChatCmd implements Serializable {
+    /** serialVersionUID */
+    @JsonIgnore
+    private static final long serialVersionUID = 2170753098968525751L;
+    @JsonIgnore
+    private Logger log = LoggerFactory.getLogger(ChatCmd.class);
+    /** 命令代码 */
+    private String code;
+    /** 异常信息 */
+    private String message;
+    /** 数据内容 */
+    private Object data;
+    /** 如果有多个结果,使用此属性 */
+    private Map<String, Object> attrs = new HashMap<String, Object>();
+
+    /**
+     * 根据属性名称查询属性值
+     * 
+     * @param name
+     *            属性名称
+     * @return Object 属性值
+     */
+    public Object getAttr(String name) {
+        return attrs.get(name);
+    }
+
+    public String getStringAttr(String name) {
+        Object value = getAttr(name);
+        return null == value ? "" : String.valueOf(value);
+    }
+
+    /**
+     * 获取返回结果属性
+     * 
+     * @return Map<String, Object>
+     */
+    public Map<String, Object> getAttrs() {
+        return attrs;
+    }
+
+    /**
+     * 命令代码
+     * 
+     * @return
+     */
+    public String getCode() {
+        return code;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    /**
+     * 获取执行结果返回消息
+     * 
+     * @return String
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    /**
+     * 设置返回结果属性
+     * 
+     * @param name
+     *            属性名称
+     * @param value
+     *            属性值
+     */
+    public void setAttr(String name, Object value) {
+        attrs.put(name, value);
+    }
+
+    /**
+     * 设置返回结果属性,覆盖原有所有属性
+     * 
+     * @param attrs
+     *            Map<String, Object>
+     */
+    public void setAttrs(Map<String, Object> attrs) {
+        this.attrs = attrs;
+    }
+
+    /**
+     * 命令代码
+     * 
+     * @param code
+     */
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+
+    /**
+     * 设置执行结果返回消息
+     * 
+     * @param message
+     *            String
+     */
+    public ChatCmd setMessage(String message) {
+        this.message = message;
+        return this;
+    }
+
+    /**
+     * 获取JSON内容的UTF-8编码字符数组
+     * 
+     * @return
+     * @throws UnsupportedEncodingException
+     */
+    public byte[] toBytes() {
+        String res = toJsonString();
+        try {
+            return res.getBytes("UTF-8");
+        }
+        catch (UnsupportedEncodingException e) {
+            log.error("格式化错误:" + res);
+            return null;
+        }
+    }
+
+    /**
+     * 命名内容转换为JSON字符串
+     * 
+     * @return
+     */
+    public String toJsonString() {
+        JsonConfig config = new JsonConfig();
+        config.addIgnoreFieldAnnotation(JsonIgnore.class);
+        JSONObject jo = JSONObject.fromObject(this, config);
+        return jo.toString();
+    }
+
+    /**
+     * 简单返回错误信息
+     * 
+     * @param code
+     * @return
+     */
+    public static ChatCmd error(String code) {
+        ChatCmd cmd = new ChatCmd();
+        cmd.setCode(code);
+        cmd.setMessage(CmdConsts.getErrorMessage(code));
+        return cmd;
+    }
+}

+ 65 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/bean/CmdConsts.java

@@ -0,0 +1,65 @@
+package com.jsjty.bean;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 命令常量定义
+ * 
+ * @author 袁晓冬
+ *
+ */
+public abstract class CmdConsts {
+    /** 操作成功 */
+    public static final String SUCCESS = "0";
+    /** 1-100 错误代码 */
+    // 一般错误
+    public static final String ERROR_COMMON = "401";
+    // 消息格式错误
+    public static final String ERROR_FORMAT = "402";
+    /** 消息解密错误 */
+    public static final String ERROR_DECODE = "403";
+    /** 1000-1100开始为共通命令 */
+    /** 消息历史查询 */
+    public static final String MSG_HISTROY = "1001";
+    /** 发送消息命令 */
+    public static final String MSG_SEND = "1002";
+    /** 消息接收确认命令 */
+    public static final String MSG_RECV = "1003";
+    /** 消息提醒 */
+    public static final String MSG_REMIND = "1004";
+    /** 增加分组 */
+    public static final String GROUP_ADD = "1011";
+    /** 删除分组 */
+    public static final String GROUP_DEL = "1012";
+    /** 更新分组 */
+    public static final String GROUP_UPD = "1013";
+    /** 查询分组 */
+    public static final String GROUP_FINDALL = "1014";
+    /** 查询好友 */
+    public static final String USER_FIND = "1021";
+    /** 添加好友 */
+    public static final String USER_ADD_TO_GROUP = "1022";
+    /** 把好友移动到指定分组 */
+    public static final String USER_MOV_TO_GROUP = "1023";
+    /** 修改当前用户的名称 */
+    public static final String USER_CHG_NAME = "1030";
+    /** 修改当前用户的手机号 */
+    public static final String USER_CHG_PHONE = "1031";
+    /** 修改当前用户的密码 */
+    public static final String USER_CHG_PWD = "1032";
+    /** 1100开始为手机端代码 */
+    /** 手机端发送位置坐标 */
+    public static final String SEND_LOCATION = "1101";
+    /** 1200开始为客户端代码 */
+    /** 消息信息 */
+    private static Map<String, String> msgMap = new HashMap<String, String>();
+    static {
+        msgMap.put(ERROR_COMMON, "执行错误!");
+        msgMap.put(ERROR_FORMAT, "消息解析错误,请发送utf8编码的json字符串");
+    }
+
+    public static String getErrorMessage(String code) {
+        return msgMap.get(code);
+    }
+}

+ 68 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/bean/MsgBean.java

@@ -0,0 +1,68 @@
+package com.jsjty.bean;
+
+import java.util.Date;
+
+public class MsgBean {
+    private String id;
+
+    // 消息标题
+    private String title;
+
+    // 消息内容s
+    private String content;
+
+    // 发送人ID
+    int chatid;
+    // 发送时间
+    Date sendtime;
+    // 状态
+    String status;
+
+    public int getChatid() {
+        return chatid;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public Date getSendtime() {
+        return sendtime;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setChatid(int chatid) {
+        this.chatid = chatid;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setSendtime(Date sendtime) {
+        this.sendtime = sendtime;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}

+ 35 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/controller/BaseController.java

@@ -0,0 +1,35 @@
+package com.jsjty.controller;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.springframework.web.bind.ServletRequestDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+
+import com.jsjty.core.DefaultCustomDateEditor;
+import com.jsjty.core.StringEscapeEditor;
+
+/**
+ * Created by 马英虎 on 14-3-17.
+ */
+public class BaseController {
+
+
+    @InitBinder
+    public void initBinder(ServletRequestDataBinder binder) {
+        /**
+         * 自动转换日期类型的字段格式
+         */
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        simpleDateFormat.setLenient(true);
+
+        binder.registerCustomEditor(Date.class, new DefaultCustomDateEditor(simpleDateFormat, true));
+        /**
+         * 防止XSS攻击
+         */
+        binder.registerCustomEditor(String.class, new StringEscapeEditor(true, false));
+    }
+
+
+
+}

+ 42 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/controller/UserController.java

@@ -0,0 +1,42 @@
+package com.jsjty.controller;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.shiro.authz.annotation.RequiresGuest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import com.jsjty.service.IUserService;
+
+@Controller
+@RequestMapping("user")
+public class UserController extends BaseController {
+    @Autowired
+    private IUserService userService;
+
+    @RequestMapping("picture/{userid}")
+    @RequiresGuest
+    public void getFaceImage(@PathVariable("userid") String userid, HttpServletRequest request,
+            HttpServletResponse response) {
+        byte[] pic = userService.findUserPicture(userid);
+        if (null == pic) { return; }
+        response.setContentType("image/png");
+        OutputStream stream;
+        try {
+            stream = response.getOutputStream();
+            stream.write(pic);
+            stream.flush();
+            stream.close();
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+        }
+
+    }
+}

+ 758 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/core/BusinessServer.java

@@ -0,0 +1,758 @@
+package com.jsjty.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.ServletConfig;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.shiro.crypto.hash.SimpleHash;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.Cache;
+import org.springframework.cache.Cache.ValueWrapper;
+import org.springframework.cache.ehcache.EhCacheCacheManager;
+import org.springframework.util.StringUtils;
+import org.springframework.web.context.ServletConfigAware;
+
+import com.bairuitech.anychat.AnyChatOutParam;
+import com.bairuitech.anychat.AnyChatServerEvent;
+import com.bairuitech.anychat.AnyChatServerSDK;
+import com.bairuitech.anychat.AnyChatVerifyUserOutParam;
+import com.jsjty.bean.ChatCmd;
+import com.jsjty.bean.CmdConsts;
+import com.jsjty.model.GroupModel;
+import com.jsjty.model.MessageModel;
+import com.jsjty.model.TerminalModel;
+import com.jsjty.model.UserModel;
+import com.jsjty.service.ChatCustomService;
+import com.jsjty.service.IGroupService;
+import com.jsjty.service.IMsgService;
+import com.jsjty.service.ITerminalService;
+import com.jsjty.service.IUserService;
+import com.jsjty.util.StringUtil;
+
+import net.sf.ehcache.Ehcache;
+import net.sf.json.JSONObject;
+
+/**
+ * anychat核心业务逻辑处理<br>
+ * 外部可以通过spring调用此接口,从此接口中可以获取AnyChatServerSDK核心接口调用
+ * 
+ * @author 袁晓冬
+ *
+ */
+public class BusinessServer implements AnyChatServerEvent, ServletConfigAware {
+    private final static Logger logger = LoggerFactory.getLogger(BusinessServer.class);
+    public AnyChatServerSDK anychatserver;
+    public StringBuilder message = new StringBuilder();
+    @Autowired
+    private IUserService userService;
+    @Autowired
+    private IGroupService groupService;
+    @Autowired
+    private ITerminalService terminalService;
+    @Autowired
+    private IMsgService messageService;
+    @Autowired
+    private ChatCustomService chatCustomService;
+    @Value("${file.path}")
+    private String file_path;
+    /** 用户名、设备ID分隔符 */
+    public static final String SEP = "#";
+    /** 保存用户与设备对应关系 */
+    private final Map<String, TerminalModel> deviceMap = new HashMap<String, TerminalModel>();
+    private final Map<String, UserModel> userMap = new HashMap<String, UserModel>();
+    private final String ALGORITHM = "AES";
+    @Autowired
+    private EhCacheCacheManager cacheManager;
+
+    /**
+     * anychatSdk获取,供web端使用
+     * 
+     * @return
+     */
+    public AnyChatServerSDK getAnyChatServerSDK() {
+        return anychatserver;
+    }
+
+    /**
+     * 初始化AnyChat Sdk
+     */
+    public void initSdk() {
+        anychatserver = new AnyChatServerSDK();
+        anychatserver.SetServerEvent(this); // 设置回调
+        anychatserver.InitSDK(0); // 初始化SDK
+        anychatserver.RegisterVerifyUserClass(new AnyChatVerifyUserOutParam());
+        // 初始化所有用户信息,客户端可以查询用户列表
+        initAllUser();
+        System.err.println("<initSdk>初始化Anychat BusinessServer成功!");
+        logger.debug("<initSdk>初始化Anychat BusinessServer成功!");
+    }
+
+    /**
+     * 用户身份验证<br>
+     * 若验证成功,则必须返回0,且分配一个唯一的userid,若验证失败,则返回出错代码,不用分配userid<br>
+     * 201:用户已经登录
+     */
+    public int OnAnyChatVerifyUserCallBack(String szUserName, String szPassword, AnyChatVerifyUserOutParam outParam) {
+        logger.debug("start <OnAnyChatVerifyUserCallBack>用户验证:{}", szUserName);
+        int ret = 1;
+        String[] userDev = szUserName.split(SEP);
+        UserModel user = this.userService.findByAccount(userDev[0]);
+        if (isOnLine(Integer.parseInt(user.getChatid()))) {
+            ret = 201;
+        }
+        else if (StringUtil.isNotEmpty(user)) {
+            SimpleHash hash = new SimpleHash("SHA-256", szPassword, null, 1);
+            if (hash.toHex().equals(user.getPassword())) {
+                boolean devCheck = false;
+                TerminalModel ter = null;
+                if (userDev.length > 1) {
+                    ter = terminalService.findByDeviceId(userDev[1]);
+                }
+                // 传入设备ID时校验设备ID
+                if (userDev.length > 1) {
+                    devCheck = checkUserDev(user, ter);
+                }
+                else {
+                    devCheck = true;
+                }
+                // 设备验证通过
+                if (devCheck) {
+                    if (userDev.length > 1) {
+                        AnyChatServerSDK.SetUserInfo(Integer.parseInt(user.getChatid()), USER_INFO_IMEI,
+                                ter.getDeviceId(), 0);
+                        AnyChatServerSDK.SetUserInfo(Integer.parseInt(user.getChatid()), USER_INFO_IMEI_NAME,
+                                ter.getDeviceName(), 0);
+                        deviceMap.put(user.getChatid(), ter);
+                    }
+                    userMap.put(user.getChatid(), user);
+                    outParam.SetUserId(Integer.parseInt(user.getChatid())); // 若身份验证成功,必须分配一个唯一的userid
+                    outParam.SetUserLevel(0);
+                    outParam.SetNickName(user.getName());
+                    ret = 0;
+                }
+            }
+        }
+        logger.debug("end <OnAnyChatVerifyUserCallBack>用户验证:{},结果:{}", szUserName, ret);
+        return ret;
+    }
+
+    /**
+     * 用户登录成功回调函数定义
+     */
+    public void OnAnyChatUserLoginActionCallBack(int dwUserId, String szUserName, int dwLevel, String szIpAddr) {
+        logger.debug("[begin] <OnAnyChatUserLoginActionCallBack> userid:{}, username{} ", dwUserId, szUserName);
+        //设置好友以及分组信息
+        configFriendAndGroup(dwUserId);
+        //设置用户信息
+        configUserInfo(dwUserId);
+        // 下发同步指令,将前面设置的资料同步给当前客户端
+        AnyChatServerSDK.UserInfoControl(dwUserId, AnyChatServerSDK.BRAS_USERINFO_CTRLCODE_SYNCDATA, 0, 0, "");
+        logger.debug("[end] <OnAnyChatUserLoginActionCallBack> userid:{}, username{} ", dwUserId, szUserName);
+    }
+
+    /**
+     * 用户登出系统<br>
+     * 移除此用户的在线状态
+     * <li>
+     * 刷新其好友列表中此用户的在线状态
+     */
+    public void OnAnyChatUserLogoutActionExCallBack(int dwUserId, int dwErrorCode) {
+        TerminalModel ter = deviceMap.get(String.valueOf(dwUserId));
+        UserModel user = userMap.get(String.valueOf(dwUserId));
+        if (null != user) {
+            userMap.remove(dwUserId);
+        }
+        if (ter != null) {
+            terminalService.deleteTrail(ter.getDeviceId());
+            deviceMap.remove(dwUserId);
+        }
+        logger.debug("<OnUserLogoutActionExCallBack>: userid:{}, errorcode:{}", dwUserId, dwErrorCode);
+        // 核心服务器会通知其它用户(如果是好友),提示好友下线,不需要业务服务器干预
+    }
+
+    /**
+     * 用户准备进入房间验证,如果允许用户进入房间,则必须返回0,则否返回出错代码
+     */
+    public int OnAnyChatPrepareEnterRoomCallBack(int dwUserId, int dwRoomId, String szRoomName, String szPassword) {
+        logger.debug("<OnPrepareEnterRoomCallBack>: userid:{}, roomid: {}", dwUserId, dwRoomId);
+        return 0;
+    }
+
+    /**
+     * 用户进入房间回调函数定义
+     */
+    public void OnAnyChatUserEnterRoomActionCallBack(int dwUserId, int dwRoomId) {
+        // 推送离线消息
+        // 获取用户离线消息
+        List<MessageModel> msgs = chatCustomService.queryOfflineMsg(dwUserId);
+        for (MessageModel msg : msgs) {
+            ChatCmd cmd = chatCustomService.sendMsg(dwUserId, msg.toCmd());
+            AnyChatOutParam outParam = new AnyChatOutParam();
+            byte[] bytes = cmd.toBytes();
+            transBufferEx(msg.getToUserId(), bytes, bytes.length, 0, 0, 0, outParam);
+        }
+        // 发送消息
+        logger.debug("<OnUserEnterRoomActionCallBack>: userid:{},roomid: {}", dwUserId, dwRoomId);
+    }
+
+    /** 用户离开房间 */
+    public void OnAnyChatUserLeaveRoomActionCallBack(int dwUserId, int dwRoomId) {
+        logger.debug("<OnUserLeaveRoomActionCallBack>: userid:{}, roomid: {}", dwUserId, dwRoomId);
+    }
+
+    /**
+     * 接收文件回调
+     */
+    public void OnAnyChatTransFile(int dwUserId, String szFileName, String szTempFilePath, int dwFileLength, int wParam,
+            int lParam, int dwTaskId) {
+        String str = "OnAnyChatTransFile->" + "from:" + dwUserId + ";filename:" + szFileName + "  ;path:"
+                + szTempFilePath + "/wParam:" + wParam + "/lParam:" + lParam;
+        //        String fileName = StringUtils.getFilename(szTempFilePath);
+        try {
+            FileUtils.copyFileToDirectory(new File(szTempFilePath), new File(file_path));
+        }
+        catch (IOException e) {
+            logger.debug(e.toString());
+        }
+        MessageModel filemessage = new MessageModel();
+        filemessage.setFromUserId(dwUserId);
+        filemessage.setToUserId(wParam);
+        filemessage.setSendDate(new Date());
+        //        messageService.addOffline(filemessage);
+        logger.debug(str);
+        logger.debug("文件上传成功" + filemessage.toString());
+
+    }
+
+    /**
+     * 接收透明头道数据回调,
+     */
+    public void OnAnyChatTransBuffer(int dwUserId, byte[] lpBuf, int dwLen) {
+        logger.debug("OnAnyChatTransBuffer:" + " fromUserid:" + dwUserId + " length:" + dwLen);
+    }
+
+    /**
+     * 接收扩展透明头道数据回调,
+     */
+    public void OnAnyChatTransBufferEx(int dwUserId, byte[] lpBuf, int dwLen, int wParam, int lParam, int dwTaskId) {
+        Cipher decodeCipher = getDecodeUserCipher(dwUserId);
+        try {
+            lpBuf = decodeCipher.doFinal(lpBuf);
+        }
+        catch (Exception e) {
+            logger.error("消息解密出错:{},lpBuf:{}", e.getMessage(), StringUtil.parseByte2HexStr(lpBuf));
+            AnyChatOutParam outParam = new AnyChatOutParam();
+            byte[] bytes = ChatCmd.error(CmdConsts.ERROR_DECODE).toBytes();
+            transBufferEx(dwUserId, bytes, bytes.length, 0, 0, 0, outParam);
+            return;
+        }
+        ChatCmd recv = null;
+        try {
+            String str = new String(lpBuf, "UTF-8");
+            logger.debug("OnAnyChatTransBufferEx:" + " from: " + dwUserId + " wParam: " + wParam + " lParam: " + lParam
+                    + " dwTaskId: " + dwTaskId + " length:  " + lpBuf.length + "\n<msg>===> " + str);
+            recv = (ChatCmd) JSONObject.toBean(JSONObject.fromObject(str), ChatCmd.class);
+        }
+        catch (UnsupportedEncodingException e) {
+            ChatCmd send = ChatCmd.error(CmdConsts.ERROR_FORMAT);
+            AnyChatOutParam outParam = new AnyChatOutParam();
+            byte[] bytes = send.toBytes();
+            transBufferEx(dwUserId, bytes, bytes.length, 0, 0, 0, outParam);
+            return;
+        }
+        String code = recv.getCode();
+        ChatCmd send = null;
+        int toUser = dwUserId;
+        if (StringUtils.isEmpty(code)) {
+            send = ChatCmd.error(CmdConsts.ERROR_COMMON);
+            send.setMessage("指令不能为空!");
+        }
+        // 查询聊天记录
+        else if (CmdConsts.MSG_HISTROY.equals(code)) {
+            send = chatCustomService.queryMessageHistory(dwUserId, recv);
+        }
+        // 手机端发送位置信息
+        else if (CmdConsts.SEND_LOCATION.equals(code)) {
+            recv.setAttr("userId", String.valueOf(dwUserId));
+            UserModel u = userMap.get(String.valueOf(dwUserId));
+            if (u != null) {
+                recv.setAttr("userName", u.getName());
+            }
+            TerminalModel ter = deviceMap.get(String.valueOf(dwUserId));
+            if (ter != null) {
+                recv.setAttr("deviceName", ter.getDeviceName());
+                recv.setAttr("imei", ter.getDeviceId());
+            }
+            send = chatCustomService.saveLocation(recv);
+        }
+        // 发送聊天信息
+        else if (CmdConsts.MSG_SEND.equals(code)) {
+            toUser = Integer.parseInt(recv.getStringAttr("dwTarUserId"));
+            if (isOnLine(toUser)) {
+                send = chatCustomService.sendMsg(dwUserId, recv);
+            }
+            else {
+                toUser = -1;// 用户已离线,不发消息
+                MessageModel msg = MessageModel.fromCmd(recv);
+                msg.setSendDate(new Date());
+                msg.setId(StringUtil.getUUID());
+                chatCustomService.saveMsg(msg);
+            }
+        }
+        // 收到聊天信息
+        else if (CmdConsts.MSG_RECV.equals(code)) {
+            toUser = -1;// 无需给客户端发送消息
+            chatCustomService.recvMsg(dwUserId, recv);
+        }
+        // 增加分组
+        else if (CmdConsts.GROUP_ADD.equals(code)) {
+            send = chatCustomService.groupCreate(dwUserId, recv);
+            send.setCode(code);
+        }
+        // 删除分组
+        else if (CmdConsts.GROUP_DEL.equals(code)) {
+            send = chatCustomService.groupDelete(dwUserId, recv);
+            send.setCode(code);
+        }
+        // 更新分组
+        else if (CmdConsts.GROUP_UPD.equals(code)) {
+            send = chatCustomService.groupUpdate(dwUserId, recv);
+            send.setCode(code);
+        }
+        // 查询分组
+        else if (CmdConsts.GROUP_FINDALL.equals(code)) {
+            send = chatCustomService.groupFindAll(dwUserId, recv);
+            send.setCode(code);
+        }
+        // 查询好友,根据好友名称
+        else if (CmdConsts.USER_FIND.equals(code)) {
+            send = chatCustomService.userFind(dwUserId, recv);
+            send.setCode(code);
+        }
+        // 添加好友
+        else if (CmdConsts.USER_ADD_TO_GROUP.equals(code)) {
+            send = chatCustomService.userAddToGroup(dwUserId, recv);
+            send.setCode(code);
+        }
+        // 添加好友
+        else if (CmdConsts.USER_MOV_TO_GROUP.equals(code)) {
+            send = chatCustomService.userMovToGroup(dwUserId, recv);
+            send.setCode(code);
+        }
+        // 修改用户名称
+        else if (CmdConsts.USER_CHG_NAME.equals(code)) {
+            String userId = AnyChatServerSDK.GetUserInfo(dwUserId, USER_INFO_ID);
+            send = chatCustomService.userChangeName(userId, recv);
+            String name = recv.getStringAttr("name");
+            AnyChatServerSDK.SetUserInfo(dwUserId, USER_INFO_NAME, name, 0);
+            // 下发同步指令,将前面设置的资料同步给当前客户端
+            AnyChatServerSDK.UserInfoControl(dwUserId, AnyChatServerSDK.BRAS_USERINFO_CTRLCODE_SYNCDATA, 0, 0, "");
+            send.setCode(code);
+        }
+        // 修改用户手机号
+        else if (CmdConsts.USER_CHG_PHONE.equals(code)) {
+            String userId = AnyChatServerSDK.GetUserInfo(dwUserId, USER_INFO_ID);
+            send = chatCustomService.userChangePhone(userId, recv);
+            String tel = recv.getStringAttr("tel");
+            AnyChatServerSDK.SetUserInfo(dwUserId, USER_INFO_TEL, tel, 0);
+            // 下发同步指令,将前面设置的资料同步给当前客户端
+            AnyChatServerSDK.UserInfoControl(dwUserId, AnyChatServerSDK.BRAS_USERINFO_CTRLCODE_SYNCDATA, 0, 0, "");
+            send.setCode(code);
+        }
+        // 修改用户密码
+        else if (CmdConsts.USER_CHG_PWD.equals(code)) {
+            String userId = AnyChatServerSDK.GetUserInfo(dwUserId, USER_INFO_ID);
+            send = chatCustomService.userChangePwd(userId, recv);
+            send.setCode(code);
+        }
+        // 消息提醒确认
+        else if (CmdConsts.MSG_REMIND.equals(code)) {
+            chatCustomService.confirmMsg(AnyChatServerSDK.GetUserInfo(dwUserId, USER_INFO_ID), recv);
+        }
+        // 发送人ID存在时发送消息
+        if (toUser > 0 && send != null) {
+            AnyChatOutParam outParam = new AnyChatOutParam();
+            byte[] bytes = send.toBytes();
+            transBufferEx(toUser, bytes, bytes.length, 0, 0, 0, outParam);
+        }
+    }
+
+    /**
+     * 接收SDKfilter数据回调<br>
+     * 客户端服务器扩展接口
+     */
+    public void OnAnyChatSDKFilterData(int dwUserId, byte[] lpBuf, int dwLen) {
+        logger.debug("OnAnyChatSDKFilterData:" + " fromUserid:" + dwUserId + " dwLen:" + dwLen);
+    }
+
+    public void OnAnyChatTimerEventCallBack() {
+        logger.debug(getCurrentTime() + "OnTimerEventCallBack");
+
+    }
+
+    /**
+     * 文字消息回调,客户端调用文字发送api会触发该回调
+     * 
+     * @param dwRoomId
+     *            文字消息所对应的房间编号
+     * @param dwSrcUserId
+     *            源用户ID,文字消息发送者
+     * @param dwTarUserId
+     *            目标用户ID,消息接收者,-1表示所有人
+     * @param bSecret
+     *            是否为悄悄话,目标用户ID不为-1时有效
+     * @param szTextMessage
+     *            文字消息内容
+     * @param dwLen
+     *            文字消息长度
+     */
+    public void OnAnyChatRecvUserTextMsgCallBack(int dwRoomId, int dwSrcUserId, int dwTarUserId, int bSecret,
+            String szTextMessage, int dwLen) {
+        logger.debug(getCurrentTime() + "OnAnyChatRecvUserTextMsgCallBack: " + dwSrcUserId + " to " + dwTarUserId + " "
+                + szTextMessage);
+        //
+    }
+
+    /**
+     * 服务器录像(扩展)回调函数,由中心录像服务器触发
+     * 参考:http://bbs.anychat.cn/forum.php?mod=viewthread&tid=20&extra=page%3D1
+     */
+
+    public void OnAnyChatServerRecordExCallBack(int dwUserId, String szRecordFileName, int dwElapse, int dwFlags,
+            int dwParam, String lpUserStr, int dwRecordServerId) {
+        boolean bSnapShotEvent = ((dwFlags & AnyChatServerSDK.ANYCHAT_RECORD_FLAGS_SNAPSHOT) != 0); // 是否为拍照事件
+        String eventStr;
+        if (bSnapShotEvent) eventStr = " ,SnapShot Event";
+        else eventStr = " ,Record Event";
+        String str = "OnAnyChatServerRecordExCallBack: dwUserId" + dwUserId + eventStr + " ,szRecordFileName:"
+                + szRecordFileName + " lpUserStr:" + lpUserStr;
+        logger.debug(getCurrentTime() + str);
+    }
+
+    /**
+     * 视频呼叫事件回调,客户端调用API:BRAC_VideoCallControl会触发该回调
+     */
+    public int OnAnyChatVideoCallEventCallBack(int dwEventType, int dwSrcUserId, int dwTarUserId, int dwErrorCode,
+            int dwFlags, int dwParam, String lpUserStr) {
+        String str = "OnAnyChatVideoCallEventCallBack: dwEventType:" + dwEventType + " dwSrcUserId:" + dwSrcUserId
+                + " dwTarUserId:" + dwTarUserId + " dwErrorCode:" + dwErrorCode + " dwFlags:" + dwFlags + " dwParam:"
+                + dwParam + " lpUserStr:" + lpUserStr;
+        logger.debug(getCurrentTime() + str);
+        return 0;
+    }
+
+    /**
+     * 用户信息控制回调,客户端调用API:BRAC_UserInfoControl会触发该回调
+     */
+    public int OnAnyChatUserInfoCtrlCallBack(int dwSendUserId, int dwUserId, int dwCtrlCode, int wParam, int lParam,
+            String lpStrValue) {
+        String str = "OnAnyChatUserInfoCtrlCallBack: dwSendUserId:" + dwSendUserId + " dwUserId:" + dwUserId
+                + " dwCtrlCode:" + dwCtrlCode + " wParam:" + wParam + " lParam:" + lParam + " lpStrValue:" + lpStrValue;
+        logger.debug(str);
+        return 0;
+    }
+
+    /** 用户信息-用户ID */
+    public static final int USER_INFO_ID = 1;
+    /** 用户信息-用户名称 */
+    public static final int USER_INFO_NAME = 2;
+    /** 用户信息-联系电话 */
+    public static final int USER_INFO_TEL = 3;
+    /** 用户信息-用户分组 */
+    public static final int USER_INFO_GROUP = 4;
+    /** 用户信息-用户是否在线 */
+    public static final int USER_INFO_ONLINE = 5;
+    /** 用户信息-默认房间号 */
+    public static final int USER_INFO_ROOM = 6;
+    /** 用户信息-当前设备IMEI */
+    public static final int USER_INFO_IMEI = 7;
+    /** 用户信息-当前设备名称 */
+    public static final int USER_INFO_IMEI_NAME = 8;
+    /** 用户信息-聊天加密算法 */
+    public static final int USER_INFO_ALGORITHM = 9;
+    /** 默认进入的房间号 */
+    public static final int DEFAULT_ROOM = 1000;
+
+    /**
+     * 配置个人信息
+     * 1:部门编号
+     * 2: 用户类型
+     * 3: 用户名
+     * 
+     * @param dwUserId
+     */
+    private void configUserInfo(int dwUserId) {
+        logger.debug("start configUserInfo");
+        String userId = AnyChatServerSDK.GetUserInfo(dwUserId, USER_INFO_ID);
+        if (StringUtils.isEmpty(userId)) {
+            UserModel user = userService.findById(String.valueOf(dwUserId));
+            addUser(user);
+        }
+        AnyChatServerSDK.SetUserInfo(dwUserId, USER_INFO_ROOM, String.valueOf(DEFAULT_ROOM), 0);
+        AnyChatServerSDK.SetUserInfo(dwUserId, USER_INFO_ALGORITHM, ALGORITHM, 0);
+        logger.debug("end configUserInfo");
+    }
+
+    /**
+     * 配置当前用户的好友以及分组信息
+     * 
+     * @param dwUserId
+     */
+    private void configFriendAndGroup(int dwUserId) {
+        logger.debug(" start configFriendAndGroup");
+        List<GroupModel> groups = groupService.findByUser(dwUserId);
+        // 设置用户分组
+        for (GroupModel g : groups) {
+            //设置分组信息
+            AnyChatServerSDK.UserInfoControl(dwUserId, AnyChatServerSDK.BRAS_USERINFO_CTRLCODE_ADDGROUP, g.getGroupId(),
+                    0, g.getName());
+            List<UserModel> users = userService.findByGroupId(g.getGroupId());
+            // 设置分组下好友
+            for (UserModel u : users) {
+                addUser(u);
+                AnyChatServerSDK.SetUserInfo(Integer.parseInt(u.getChatid()), USER_INFO_ONLINE,
+                        isOnLine(Integer.parseInt(u.getChatid())) ? "1" : "0", 0);
+                AnyChatServerSDK.UserInfoControl(dwUserId, AnyChatServerSDK.BRAS_USERINFO_CTRLCODE_ADDFRIEND,
+                        Integer.parseInt(u.getChatid()), 0, u.getName());
+                AnyChatServerSDK.UserInfoControl(dwUserId, AnyChatServerSDK.BRAS_USERINFO_CTRLCODE_SETGROUPRELATION,
+                        g.getGroupId(), Integer.parseInt(u.getChatid()), "");
+            }
+        }
+        logger.debug(" end configFriendAndGroup");
+    }
+
+    /**
+     * 业务对象事件回调函数定义
+     */
+    @Override
+    public int OnAnyChatObjectEventCallBack(int dwObjectType, int dwObjectId, int dwEventType, int dwParam1,
+            int dwParam2, int dwParam3, int dwParam4, String lpStrParam) {
+        return 0;
+    }
+
+    /**
+     * 向服务器添加用户
+     * 
+     * @param user
+     */
+    private void addUser(UserModel user) {
+        logger.debug("start add user:" + user.getChatid());
+        try {
+            // 设置当前用户信息(用户资料,客户端可以通过API:BRAC_GetUserInfo来获取这些信息)
+            AnyChatServerSDK.SetUserInfo(Integer.parseInt(user.getChatid()), USER_INFO_ID, user.getChatid(), 0);
+            AnyChatServerSDK.SetUserInfo(Integer.parseInt(user.getChatid()), USER_INFO_NAME, user.getName(), 0);
+            AnyChatServerSDK.SetUserInfo(Integer.parseInt(user.getChatid()), USER_INFO_TEL, user.getTel(), 0);
+        }
+        catch (Throwable t) {
+            t.printStackTrace();
+        }
+        logger.debug("end add user:" + user.getChatid());
+    }
+
+    /**
+     * 获取当前时间
+     */
+    public static String getCurrentTime() {
+        Date date = new Date(System.currentTimeMillis());
+        SimpleDateFormat tm = new SimpleDateFormat("MM-dd HH:mm:ss:SSS");
+        String strTime = "";
+        try {
+            strTime = tm.format(date) + "\t";
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+        }
+        return strTime;
+    }
+
+    /**
+     * 判断用户是否在线
+     * 
+     * @param u
+     * @return
+     */
+    private boolean isOnLine(int userid) {
+        int[] onlineusers = AnyChatServerSDK.GetOnlineUsers(-1); // 获取系统在线用户列表
+        for (Integer otheruserid : onlineusers) {
+            if (otheruserid.intValue() == userid) { return true; }
+        }
+        return false;
+    }
+
+    /**
+     * 服务器应用程序消息回调函数定义
+     */
+    public void OnAnyChatServerAppMessageExCallBack(int dwNotifyMessage, int wParam, int lParam) {
+        if (dwNotifyMessage == AnyChatServerSDK.BRAS_MESSAGE_CORESERVERCONN) {
+            if (wParam == 0) logger.debug(getCurrentTime() + "Success connected with anychatcoreserver...");
+            else logger.debug(getCurrentTime() + "ERROR: Disconnected from the anychatcoreserver, errorcode:" + wParam);
+        }
+        else if (dwNotifyMessage == AnyChatServerSDK.BRAS_MESSAGE_RECORDSERVERCONN) {
+            if (wParam == 0)
+                logger.debug(getCurrentTime() + "Success connected with anychatrecordserver(id:" + lParam + ") ...");
+            else logger
+                    .info(getCurrentTime() + "ERROR: Disconnected from the anychatrecordserver, errorcode:" + wParam);
+        }
+        else logger.debug(getCurrentTime() + "OnServerAppMessageExCallBack, dwNotifyMessage:" + dwNotifyMessage
+                + " wParam:" + wParam + " lParam:" + lParam);
+    }
+
+    /**
+     * 初始化所有用户
+     */
+    private void initAllUser() {
+        List<UserModel> users = userService.findAll();
+        for (UserModel u : users) {
+            addUser(u);
+        }
+    }
+
+    /**
+     * 判断设备是否允许使用
+     * 
+     * @param u
+     * @param devId
+     * @return
+     */
+    private boolean checkUserDev(UserModel u, TerminalModel ter) {
+        return ter != null && "Y".equalsIgnoreCase(ter.getValid());
+    }
+
+    @SuppressWarnings("unused")
+    private ServletConfig servletConfig;
+
+    @Override
+    public void setServletConfig(ServletConfig config) {
+        servletConfig = config;
+    }
+
+    /**
+     * 发送离线消息
+     */
+    public void resendMsg() {
+        Cache cache = cacheManager.getCache("messageCache");
+        Ehcache ehcache = (Ehcache) cache.getNativeCache();
+        @SuppressWarnings("unchecked")
+        List<String> keys = ehcache.getKeys();
+        for (String key : keys) {
+            ValueWrapper element = cache.get(key);
+            if (null != element && element.get() != null) {
+                MessageModel msg = (MessageModel) element.get();
+                if (isOnLine(msg.getToUserId())) {
+                    // 用户已离线,持久化到数据库
+                    cache.evict(key);
+                    messageService.saveMsg(msg);
+                }
+                else {
+                    // 用户在线,持久发送消息直到用户确认
+                    ChatCmd sendCmd = msg.toCmd();
+                    sendCmd.setCode(CmdConsts.MSG_SEND);
+                    int toUser = msg.getToUserId();
+                    AnyChatOutParam outParam = new AnyChatOutParam();
+                    byte[] bytes = sendCmd.toBytes();
+                    transBufferEx(toUser, bytes, bytes.length, 0, 0, 0, outParam);
+                }
+
+            }
+        }
+    }
+
+    /**
+     * 获取用户加密算法
+     * 
+     * @param dwUserId
+     * @return
+     */
+    private Cipher getEncodeUserCipher(int dwUserId) {
+        Cache cache = cacheManager.getCache("cipherCache");
+        ValueWrapper vw = cache.get("cipher-encode-" + dwUserId);
+        if (vw != null && vw.get() != null) { return (Cipher) vw.get(); }
+        String key = String.valueOf(dwUserId);
+        if (key.length() > 16) {
+            key = key.substring(0, 16);
+        }
+        while (key.length() < 16) {
+            key += "#";
+        }
+        Cipher cipher = null;
+        try {
+            cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(), ALGORITHM));
+        }
+        catch (Exception e) {
+            logger.error("获取加密算法出错:{}", e.getMessage());
+        }
+        if (null != cipher) {
+            cache.put("cipher-encode-" + dwUserId, cipher);
+        }
+        return cipher;
+    }
+
+    /**
+     * 获取用户解密工具
+     * 
+     * @param dwUserId
+     * @return
+     */
+    private Cipher getDecodeUserCipher(int dwUserId) {
+        Cache cache = cacheManager.getCache("cipherCache");
+        ValueWrapper vw = cache.get("cipher-decode-" + dwUserId);
+        if (vw != null && vw.get() != null) { return (Cipher) vw.get(); }
+        String key = String.valueOf(dwUserId);
+        if (key.length() > 16) {
+            key = key.substring(0, 16);
+        }
+        while (key.length() < 16) {
+            key += "#";
+        }
+        Cipher cipher = null;
+        try {
+            cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(), ALGORITHM));
+        }
+        catch (Exception e) {
+            logger.error("获取加密算法出错:{}", e.getMessage());
+        }
+        if (null != cipher) {
+            cache.put("cipher-decode-" + dwUserId, cipher);
+        }
+        return cipher;
+    }
+
+    /**
+     * 使用透明通道发送加密后的消息
+     * 
+     * @param userid
+     * @param buf
+     * @param len
+     * @param wparam
+     * @param lparam
+     * @param flags
+     * @param outParam
+     */
+    public void transBufferEx(int userid, byte[] buf, int len, int wparam, int lparam, int flags,
+            AnyChatOutParam outParam) {
+        try {
+            Cipher encodeCipher = getEncodeUserCipher(userid);
+            buf = encodeCipher.doFinal(buf);
+            logger.debug("send hex:" + StringUtil.parseByte2HexStr(buf));
+        }
+        catch (Exception e) {
+            logger.debug("消息加密失败:" + e.getMessage());
+        }
+        AnyChatServerSDK.TransBufferEx(userid, buf, buf.length, wparam, lparam, flags, outParam);
+    }
+}

+ 32 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/core/CustomObjectMapper.java

@@ -0,0 +1,32 @@
+package com.jsjty.core;
+
+import com.jsjty.util.DateUtil;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.ser.CustomSerializerFactory;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Created by 马英虎 on 2014/5/17.
+ */
+public class CustomObjectMapper extends ObjectMapper {
+    public CustomObjectMapper(){
+        CustomSerializerFactory factory = new CustomSerializerFactory();
+        factory.addGenericMapping(Date.class, new JsonSerializer<Date>(){
+            @Override
+            public void serialize(Date value,
+                                  JsonGenerator jsonGenerator,
+                                  SerializerProvider provider)
+                    throws IOException {
+                SimpleDateFormat sdf = new SimpleDateFormat(DateUtil.DATE_SECOND_FMT);
+                jsonGenerator.writeString(sdf.format(value));
+            }
+        });
+        this.setSerializerFactory(factory);
+    }
+}

+ 41 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/core/DefaultCustomDateEditor.java

@@ -0,0 +1,41 @@
+package com.jsjty.core;
+
+import org.springframework.beans.propertyeditors.CustomDateEditor;
+import org.springframework.util.StringUtils;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+
+/**
+ * Created by 马英虎 on 2014/5/16.
+ */
+public class DefaultCustomDateEditor extends CustomDateEditor {
+
+    private boolean allowEmpty;
+
+    private DateFormat dateFormat;
+
+    public DefaultCustomDateEditor(DateFormat dateFormat, boolean allowEmpty) {
+        super(dateFormat, allowEmpty);
+        this.allowEmpty = allowEmpty;
+        this.dateFormat = dateFormat;
+    }
+
+    @Override
+    public void setAsText(String text) throws IllegalArgumentException {
+        if (this.allowEmpty && !StringUtils.hasText(text)) {
+            // Treat empty String as null value.
+            setValue(null);
+        } else if (text != null && text.length() < 21) {
+            text += " 00:00:00";
+            try {
+                setValue(this.dateFormat.parse(text));
+            } catch (ParseException ex) {
+                throw new IllegalArgumentException("Could not parse date: "
+                        + ex.getMessage(), ex);
+            }
+        }
+    }
+
+
+}

+ 68 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/core/QuartzServlet.java

@@ -0,0 +1,68 @@
+package com.jsjty.core;
+
+import java.util.Calendar;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+import com.jsjty.bean.MsgBean;
+import com.jsjty.task.MessageRemindTask;
+import com.jsjty.task.MessageSendService;
+import com.jsjty.task.base.TaskService;
+
+/**
+ * 定时任务Servlet
+ * 
+ * @author 袁晓冬
+ *
+ */
+public class QuartzServlet extends HttpServlet {
+
+    /** serialVersionUID */
+    private static final long serialVersionUID = 3137976979537814808L;
+    private AutowireCapableBeanFactory beanFactory;
+    private ScheduledExecutorService executor;
+
+    @Override
+    public void init(ServletConfig servletConfig) throws ServletException {
+        beanFactory = WebApplicationContextUtils.getWebApplicationContext(servletConfig.getServletContext())
+                .getAutowireCapableBeanFactory();
+        executor = Executors.newScheduledThreadPool(5);
+        initAllService();
+    }
+
+    /**
+     * 初始化服务
+     */
+    private void initAllService() {
+        initMessageRemindService();
+    }
+
+    private void initMessageRemindService() {
+        MessageRemindTask service = beanFactory.getBean(MessageRemindTask.class);
+        long delay = 30 * 1000;
+        executor.scheduleAtFixedRate(new TaskService(service, executor, 10), 0, delay, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 获取下个整点间隔
+     * 
+     * @return
+     */
+    static long getHourMillis() {
+        Calendar c = Calendar.getInstance();
+        c.add(Calendar.HOUR, 1);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+        c.set(Calendar.MILLISECOND, 0);
+        return c.getTimeInMillis();
+    }
+}

+ 49 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/core/StringEscapeEditor.java

@@ -0,0 +1,49 @@
+package com.jsjty.core;
+
+import org.springframework.web.util.HtmlUtils;
+import org.springframework.web.util.JavaScriptUtils;
+
+import java.beans.PropertyEditorSupport;
+
+/**
+ * Created by 马英虎 on 14-3-17.
+ * 与spring mvc的@InitBinder结合
+ *
+ * 用于防止XSS攻击
+ */
+public class StringEscapeEditor extends PropertyEditorSupport {
+    private boolean escapeHTML;// 编码HTML
+    private boolean escapeJavaScript;// 编码javascript
+
+    public StringEscapeEditor() {
+        super();
+    }
+
+    public StringEscapeEditor(boolean escapeHTML, boolean escapeJavaScript) {
+        super();
+        this.escapeHTML = escapeHTML;
+        this.escapeJavaScript = escapeJavaScript;
+    }
+
+    @Override
+    public String getAsText() {
+        Object value = getValue();
+        return value != null ? value.toString() : "";
+    }
+
+    @Override
+    public void setAsText(String text) throws IllegalArgumentException {
+        if (text == null) {
+            setValue(null);
+        } else {
+            String value = text;
+            if (escapeHTML) {
+                value = HtmlUtils.htmlEscape(value);
+            }
+            if (escapeJavaScript) {
+                value = JavaScriptUtils.javaScriptEscape(value);
+            }
+            setValue(value);
+        }
+    }
+}

+ 42 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/core/excel/ExcelData.java

@@ -0,0 +1,42 @@
+package com.jsjty.core.excel;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by 马英虎 on 2014/11/21.
+ */
+public class ExcelData {
+
+    public ExcelData(Map<String, Object> parameters, List<Map<String,Object>> fieldsList) {
+        this.parameters = parameters;
+        this.fieldsList = fieldsList;
+    }
+
+    /**
+     * Excel参数元数据对象
+     */
+    private Map<String,Object> parameters;
+
+    /**
+     * Excel集合元对象
+     */
+    private List<Map<String,Object>> fieldsList;
+
+
+    public Map<String, Object> getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(Map<String, Object> parameters) {
+        this.parameters = parameters;
+    }
+
+    public List<Map<String,Object>> getFieldsList() {
+        return fieldsList;
+    }
+
+    public void setFieldsList(List<Map<String,Object>> fieldsList) {
+        this.fieldsList = fieldsList;
+    }
+}

+ 91 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/core/excel/ExcelExporter.java

@@ -0,0 +1,91 @@
+package com.jsjty.core.excel;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+import com.jsjty.util.StringUtil;
+
+/**
+ * Created by 马英虎 on 2014/11/21.
+ */
+public class ExcelExporter {
+
+    private String templatePath;
+    private Map<String, Object> parameters;
+    private List<Map<String,Object>> fieldsList;
+    private String filename = "Excel.xls";
+
+
+    /**
+     * 设置数据
+     *
+     * @param parameters 参数集合
+     * @param pList      字段集合
+     */
+    public void setData(Map<String, Object> parameters, List<Map<String,Object>> pList) {
+        this.parameters = parameters;
+        this.fieldsList = pList;
+    }
+
+    /**
+     * 导出Excel
+     *
+     * @param request
+     * @param response
+     * @throws java.io.IOException
+     */
+    public void export(HttpServletRequest request, HttpServletResponse response) throws IOException {
+        response.setContentType("application/vnd.ms-excel");
+        filename = StringUtil.encodeChineseDownloadFileName(request, getFilename());
+        response.setHeader("Content-Disposition", "attachment; filename=" + filename + ";");
+        ExcelData excelData = new ExcelData(parameters, fieldsList);
+        ExcelTemplate excelTemplate = new ExcelTemplate();
+        excelTemplate.setTemplatePath(getTemplatePath());
+        excelTemplate.parse(request);
+        ExcelFiller excelFiller = new ExcelFiller(excelTemplate, excelData);
+        HSSFWorkbook workbook = excelFiller.fill(request);
+        ServletOutputStream out = response.getOutputStream();
+        workbook.write(out);
+        out.flush();
+    }
+
+
+    public String getTemplatePath() {
+        return templatePath;
+    }
+
+    public void setTemplatePath(String templatePath) {
+        this.templatePath = templatePath;
+    }
+
+    public Map<String, Object> getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(Map<String, Object> parameters) {
+        this.parameters = parameters;
+    }
+
+    public List<Map<String,Object>> getFieldsList() {
+        return fieldsList;
+    }
+
+    public void setFieldsList(List<Map<String,Object>> fieldsList) {
+        this.fieldsList = fieldsList;
+    }
+
+    public String getFilename() {
+        return filename;
+    }
+
+    public void setFilename(String filename) {
+        this.filename = filename;
+    }
+}

+ 175 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/core/excel/ExcelFiller.java

@@ -0,0 +1,175 @@
+package com.jsjty.core.excel;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.log4j.Logger;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+import com.jsjty.util.StringUtil;
+
+/**
+ * Created by 马英虎 on 2014/11/21.
+ */
+public class ExcelFiller {
+
+
+    /**
+     * Excel模板数据类型<br>
+     * number:数字类型
+     */
+    public static final String ExcelTPL_DataType_Number = "number";
+
+    /**
+     * Excel模板数据类型<br>
+     * number:文本类型
+     */
+    public static final String ExcelTPL_DataType_Label = "label";
+
+    private final static Logger logger = Logger.getLogger(ExcelFiller.class);
+
+    private ExcelTemplate excelTemplate = null;
+
+    private ExcelData excelData = null;
+
+    public ExcelFiller() {
+    }
+
+    /**
+     * 构造函数
+     *
+     * @param pExcelTemplate
+     * @param pExcelData
+     */
+    public ExcelFiller(ExcelTemplate pExcelTemplate, ExcelData pExcelData) {
+        setExcelData(pExcelData);
+        setExcelTemplate(pExcelTemplate);
+    }
+
+
+    /**
+     * 数据填充 将ExcelData填入excel模板
+     *
+     * @return HSSFWorkbook
+     */
+    public HSSFWorkbook fill(HttpServletRequest request) {
+        HSSFSheet wSheet = null;
+        HSSFWorkbook workbook = null;
+        try {
+            InputStream is = request.getSession().getServletContext().getResourceAsStream(getExcelTemplate().getTemplatePath());
+            POIFSFileSystem fs = new POIFSFileSystem(is);
+            workbook = new HSSFWorkbook(fs);
+            wSheet = workbook.getSheetAt(0);
+            fillStatics(wSheet);  //静态Cell
+            fillParameters(wSheet); //参数
+            fillFields(wSheet);//列表
+        } catch (Exception e) {
+            logger.error("基于模板生成可写工作表出错了!");
+            e.printStackTrace();
+        }
+        return workbook;
+    }
+
+    /**
+     * 写入表格字段对象
+     *
+     * @throws Exception
+     */
+    private void fillFields(HSSFSheet hssfSheet) throws Exception {
+        List<Map<String, Object>> fieldList = getExcelData().getFieldsList();
+        List<HSSFCell> hssfCells = getExcelTemplate().getFieldObjct();
+        int rowNum = 0;
+        for (int i = 0, len = fieldList.size(); i < len; i++) {
+            Map<String, Object> parameters = fieldList.get(i);
+            rowNum = hssfCells.get(0).getRowIndex() + i;
+            HSSFRow hssfRow = hssfSheet.createRow(rowNum);
+            if (!StringUtil.isEmpty(parameters)) {
+                for (HSSFCell hssfCell : hssfCells) {
+                    String cellValue = hssfCell.getStringCellValue();
+                    String key = getKey(cellValue);
+                    HSSFCell cell = hssfRow.createCell(hssfCell.getColumnIndex(), HSSFCell.CELL_TYPE_STRING);
+                    if (!StringUtil.isEmpty(parameters.get(key))) {
+                        cell.setCellValue(String.valueOf(parameters.get(key)));
+                    } else {
+                        cell.setCellValue("");
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 写入静态对象
+     */
+    private void fillStatics(HSSFSheet hssfSheet) {
+
+        List<HSSFCell> cellList = getExcelTemplate().getStaticObject();
+
+        for (HSSFCell hssfCell : cellList) {
+            HSSFCell cell = hssfSheet.getRow(hssfCell.getRowIndex()).getCell(hssfCell.getColumnIndex());
+            cell.setCellValue(hssfCell.getStringCellValue());
+        }
+    }
+
+    /**
+     * 写入参数对象
+     */
+    private void fillParameters(HSSFSheet hssfSheet) {
+        List<HSSFCell> cellList = getExcelTemplate().getParameterObjct();
+        Map<String, Object> parameters = getExcelData().getParameters();
+        if (parameters != null) {
+            for (HSSFCell hssfCell : cellList) {
+                HSSFCell cell = hssfSheet.getRow(hssfCell.getRowIndex()).getCell(hssfCell.getColumnIndex());
+
+                String cellValue = hssfCell.getStringCellValue();
+                String key = getKey(cellValue);
+                if (!StringUtil.isEmpty(parameters.get(key))) {
+                    cell.setCellValue(parameters.get(key).toString());
+                } else {
+                    cell.setCellValue("");
+                }
+            }
+        }
+
+    }
+
+    /**
+     * 获取模板键名
+     *
+     * @param pKey 模板元标记
+     * @return 键名
+     */
+    private static String getKey(String pKey) {
+        String key = null;
+        int index = pKey.indexOf(":");
+        if (index == -1) {
+            key = pKey.substring(3, pKey.length() - 1);
+        } else {
+            key = pKey.substring(3, index);
+        }
+        return key;
+    }
+
+    public ExcelTemplate getExcelTemplate() {
+        return excelTemplate;
+    }
+
+    public void setExcelTemplate(ExcelTemplate excelTemplate) {
+        this.excelTemplate = excelTemplate;
+    }
+
+    public ExcelData getExcelData() {
+        return excelData;
+    }
+
+    public void setExcelData(ExcelData excelData) {
+        this.excelData = excelData;
+    }
+}

+ 129 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/core/excel/ExcelTemplate.java

@@ -0,0 +1,129 @@
+package com.jsjty.core.excel;
+
+import java.io.InputStream;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.log4j.Logger;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+import com.jsjty.util.StringUtil;
+
+/**
+ * Created by 马英虎 on 2014/11/21.
+ */
+public class ExcelTemplate {
+
+    private final static Logger logger = Logger.getLogger(ExcelTemplate.class);
+
+    private List<HSSFCell> staticObject = null;
+    private List<HSSFCell> parameterObjct = null;
+    private List<HSSFCell> fieldObjct = null;
+    private List<HSSFCell> variableObject = null;
+    private String templatePath = null;
+
+    public ExcelTemplate(String pTemplatePath) {
+        templatePath = pTemplatePath;
+    }
+
+    public ExcelTemplate() {
+    }
+
+
+    /**
+     * 解析Excel模板
+     */
+    public void parse(HttpServletRequest request) {
+        if(StringUtil.isEmpty(templatePath)){
+            logger.error("Excel模板路径不能为空!");
+        }
+        InputStream is = request.getSession().getServletContext().getResourceAsStream(templatePath);
+        if(StringUtil.isEmpty(is)){
+            logger.error("未找到模板文件,请确认模板路径是否正确[" + templatePath + "]");
+        }
+        HSSFWorkbook workbook = null;
+        try {
+            POIFSFileSystem fs = new POIFSFileSystem(is);
+            workbook = new HSSFWorkbook(fs);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        HSSFSheet hssfSheet = workbook.getSheetAt(0);
+        if (StringUtil.isNotEmpty(hssfSheet)) {
+            int rowNum = hssfSheet.getLastRowNum();
+            for (int row = 0; row <= rowNum; row++) {
+                HSSFRow hssfRow = hssfSheet.getRow(row);
+                if(!StringUtil.isEmpty(hssfRow)){
+                    int cellNum = hssfRow.getLastCellNum();
+                    for(int cell = 0; cell < cellNum; cell++){
+                        HSSFCell hssfCell = hssfRow.getCell(cell);
+                        if(!StringUtil.isEmpty(hssfCell)){
+                            String cellValue = hssfCell.getStringCellValue();
+                            if (!StringUtil.isEmpty(cellValue)) {
+                                if (cellValue.indexOf("$P") != -1 || cellValue.indexOf("$p") != -1) {
+                                    addParameterObjct(hssfCell);
+                                }else if (cellValue.indexOf("$F") != -1 || cellValue.indexOf("$f") != -1) {
+                                    addFieldObjct(hssfCell);
+                                } else {
+                                    addStaticObject(hssfCell);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            logger.error("模板工作表对象不能为空!");
+        }
+    }
+
+    /**
+     * 增加一个静态文本对象
+     */
+    public void addStaticObject(HSSFCell cell) {
+        staticObject.add(cell);
+    }
+
+    /**
+     * 增加一个字段对象
+     */
+    public void addFieldObjct(HSSFCell cell) {
+        fieldObjct.add(cell);
+    }
+
+    /**
+     * 增加一个参数对象
+     */
+    public void addParameterObjct(HSSFCell cell) {
+        parameterObjct.add(cell);
+    }
+
+    public List<HSSFCell> getStaticObject() {
+        return staticObject;
+    }
+
+    public List<HSSFCell> getParameterObjct() {
+        return parameterObjct;
+    }
+
+    public List<HSSFCell> getFieldObjct() {
+        return fieldObjct;
+    }
+
+    public List<HSSFCell> getVariableObject() {
+        return variableObject;
+    }
+
+    public String getTemplatePath() {
+        return templatePath;
+    }
+
+    public void setTemplatePath(String templatePath) {
+        this.templatePath = templatePath;
+    }
+}

+ 75 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/model/GroupModel.java

@@ -0,0 +1,75 @@
+package com.jsjty.model;
+
+import java.io.Serializable;
+
+/**
+ * 用户分组模型<br>
+ * 每个用户自行创建多个分组,每个分组中可以管理多个好友
+ * 
+ * @author 袁晓冬
+ *
+ */
+public class GroupModel implements Serializable {
+    /** serialVersionUID */
+    private static final long serialVersionUID = 5314507832418369514L;
+    /** 分组唯一标识 */
+    private String id;
+    /** 分组唯一ID */
+    private int groupId;
+    /** 分组所属用户 */
+    private String user;
+    /** 分组名称 */
+    private String name;
+    /** 分组是否有效 */
+    private String valid;
+    /** 排序号 */
+    private int sortno;
+
+    public int getGroupId() {
+        return groupId;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getSortno() {
+        return sortno;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public String getValid() {
+        return valid;
+    }
+
+    public void setGroupId(int groupId) {
+        this.groupId = groupId;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setSortno(int sortno) {
+        this.sortno = sortno;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public void setValid(String valid) {
+        this.valid = valid;
+    }
+}

+ 201 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/model/MessageModel.java

@@ -0,0 +1,201 @@
+package com.jsjty.model;
+
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import com.jsjty.anon.JsonIgnore;
+import com.jsjty.bean.ChatCmd;
+import com.jsjty.bean.CmdConsts;
+
+/**
+ * 消息模型
+ * 
+ * @author 袁晓冬
+ *
+ */
+public class MessageModel implements Serializable {
+    /** serialVersionUID */
+    @JsonIgnore
+    private static final long serialVersionUID = -6079801638737868315L;
+
+    /**
+     * 通过命令构造消息
+     * 
+     * @param recv
+     * @return
+     */
+    public static final MessageModel fromCmd(ChatCmd recv) {
+        MessageModel msg = new MessageModel();
+        msg.setDwRoomId(Integer.parseInt(recv.getStringAttr("dwRoomId")));
+        msg.setFromUserId(Integer.parseInt(recv.getStringAttr("dwSrcUserId")));
+        msg.setToUserId(Integer.parseInt(recv.getStringAttr("dwTarUserId")));
+        msg.setId(recv.getStringAttr("id"));
+        msg.setMsg(recv.getStringAttr("msg"));
+        msg.setSendDate(new Date());
+        msg.setSecret(recv.getStringAttr("bSecret"));
+        msg.setStatus(0);
+        msg.setFontColor(recv.getStringAttr("fontColor"));
+        msg.setFontFamily(recv.getStringAttr("fontFamily"));
+        msg.setFontSize(recv.getStringAttr("fontSize"));
+        msg.setFontWeight(recv.getStringAttr("fontWeight"));
+        return msg;
+    }
+
+    /** 消息ID,uuid */
+    private String id;
+    /** 消息所在房间号 */
+    private int dwRoomId;
+    /** 消息发送者ID */
+    private Integer fromUserId;
+    /** 消息接收者ID */
+    private Integer toUserId;
+    /** 消息内容 */
+    private String msg;
+    /** 消息接收时间,客户端收到消息后会通知服务器,否则服务器定时重发此消息 */
+    private Date recvDate;
+    /** 消息发送时间,服务器收到消息的时间 */
+    private Date sendDate;
+    /** 是否为悄悄话,暂时不用 */
+    private String secret;
+    /** 字体大小 */
+    private String fontSize;
+    /** 字体颜色 */
+    private String fontColor;
+
+    /** 字体 */
+    private String fontFamily;
+
+    /** 字形 */
+    private String fontWeight;
+
+    /** 记录状态:0离线未接收状态,1已接收状态 */
+    private int status;
+
+    public int getDwRoomId() {
+        return dwRoomId;
+    }
+
+    public String getFontColor() {
+        return fontColor;
+    }
+
+    public String getFontFamily() {
+        return fontFamily;
+    }
+
+    public String getFontSize() {
+        return fontSize;
+    }
+
+    public String getFontWeight() {
+        return fontWeight;
+    }
+
+    public Integer getFromUserId() {
+        return fromUserId;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public Date getRecvDate() {
+        return recvDate;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+
+    public Date getSendDate() {
+        return sendDate;
+    }
+
+    public int getStatus() {
+        return status;
+    }
+
+    public Integer getToUserId() {
+        return toUserId;
+    }
+
+    public void setDwRoomId(int dwRoomId) {
+        this.dwRoomId = dwRoomId;
+    }
+
+    public void setFontColor(String fontColor) {
+        this.fontColor = fontColor;
+    }
+
+    public void setFontFamily(String fontFamily) {
+        this.fontFamily = fontFamily;
+    }
+
+    public void setFontSize(String fontSize) {
+        this.fontSize = fontSize;
+    }
+
+    public void setFontWeight(String fontWeight) {
+        this.fontWeight = fontWeight;
+    }
+
+    public void setFromUserId(Integer fromUserId) {
+        this.fromUserId = fromUserId;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public void setRecvDate(Date recvDate) {
+        this.recvDate = recvDate;
+    }
+
+    public void setSecret(String secret) {
+        this.secret = secret;
+    }
+
+    public void setSendDate(Date sendDate) {
+        this.sendDate = sendDate;
+    }
+
+    public void setStatus(int status) {
+        this.status = status;
+    }
+
+    public void setToUserId(Integer toUserId) {
+        this.toUserId = toUserId;
+    }
+
+    /**
+     * 消息生成命令
+     * 
+     * @return
+     */
+    public ChatCmd toCmd() {
+        ChatCmd sendCmd = new ChatCmd();
+        sendCmd.setCode(CmdConsts.MSG_SEND);
+        sendCmd.setAttr("dwRoomId", this.getDwRoomId());
+        sendCmd.setAttr("dwSrcUserId", this.getFromUserId());
+        sendCmd.setAttr("dwTarUserId", this.getToUserId());
+        sendCmd.setAttr("msg", this.getMsg());
+        sendCmd.setAttr("bSecret", this.getSecret());
+        sendCmd.setAttr("id", this.getId());
+        SimpleDateFormat tm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
+        sendCmd.setAttr("sendDate", tm.format(this.getSendDate()));
+        sendCmd.setAttr("fontColor", this.getFontColor());
+        sendCmd.setAttr("fontFamily", this.getFontFamily());
+        sendCmd.setAttr("fontSize", this.getFontSize());
+        sendCmd.setAttr("fontWeight", this.getFontWeight());
+        return sendCmd;
+    }
+}

+ 146 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/model/TerTrailModel.java

@@ -0,0 +1,146 @@
+package com.jsjty.model;
+
+import java.io.Serializable;
+
+/**
+ * 终端轨迹表
+ * 
+ * @author 袁晓冬
+ *
+ */
+public class TerTrailModel implements Serializable {
+    /** serialVersionUID */
+    private static final long serialVersionUID = 4339140685079104541L;
+    /** 分组唯一标识 */
+    private String id;
+    /** 分组唯一ID */
+    private String deviceId;
+    /** 设备名称 */
+    private String deviceName;
+    /** 分组所属用户 */
+    private int userId;
+    /** 用户名称 */
+    private String userName;
+    /** 坐标-纬度 */
+    private Double lat;
+    /** 坐标-经度 */
+    private Double lon;
+    /** 数据更新时间 */
+    private long updTime;
+    /** 数据接收时间 */
+    private long receiveDate;
+    /** 当前速度 */
+    private String speed;
+    /** 行驶方向 */
+    private String direction;
+    /** 精确 */
+    private String accuracy;
+
+    public long getReceiveDate() {
+        return receiveDate;
+    }
+
+    public void setReceiveDate(long receiveDate) {
+        this.receiveDate = receiveDate;
+    }
+
+    public String getSpeed() {
+        return speed;
+    }
+
+    public void setSpeed(String speed) {
+        this.speed = speed;
+    }
+
+    public String getDirection() {
+        return direction;
+    }
+
+    public void setDirection(String direction) {
+        this.direction = direction;
+    }
+
+    public String getAccuracy() {
+        return accuracy;
+    }
+
+    public void setAccuracy(String accuracy) {
+        this.accuracy = accuracy;
+    }
+
+    public String getAltitude() {
+        return altitude;
+    }
+
+    public void setAltitude(String altitude) {
+        this.altitude = altitude;
+    }
+
+    /** 海拔高度 */
+    private String altitude;
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public Double getLat() {
+        return lat;
+    }
+
+    public Double getLon() {
+        return lon;
+    }
+
+    public long getUpdTime() {
+        return updTime;
+    }
+
+    public int getUserId() {
+        return userId;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setLat(Double lat) {
+        this.lat = lat;
+    }
+
+    public void setLon(Double lon) {
+        this.lon = lon;
+    }
+
+    public void setUpdTime(long updTime) {
+        this.updTime = updTime;
+    }
+
+    public void setUserId(int userId) {
+        this.userId = userId;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+}

+ 74 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/model/TerminalModel.java

@@ -0,0 +1,74 @@
+package com.jsjty.model;
+
+import java.io.Serializable;
+
+/**
+ * 终端信息
+ * 
+ * @author 袁晓冬
+ *
+ */
+public class TerminalModel implements Serializable {
+    /** serialVersionUID */
+    private static final long serialVersionUID = 5421256427020982187L;
+    /** 分组唯一标识 */
+    private String id;
+    /** 终端类型 */
+    private String tertype;
+    /** 设备ID */
+    private String deviceId;
+    /** 设备名称 */
+    private String deviceName;
+    /** 是否允许使用 */
+    private String valid;
+    /** 排序号 */
+    private int sortno;
+
+    public String getId() {
+        return id;
+    }
+
+    public int getSortno() {
+        return sortno;
+    }
+
+    public String getValid() {
+        return valid;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setSortno(int sortno) {
+        this.sortno = sortno;
+    }
+
+    public String getTertype() {
+        return tertype;
+    }
+
+    public void setTertype(String tertype) {
+        this.tertype = tertype;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public void setValid(String valid) {
+        this.valid = valid;
+    }
+}

+ 126 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/model/Tfile.java

@@ -0,0 +1,126 @@
+package com.jsjty.model;
+
+import java.sql.Timestamp;
+
+/**
+ * package com.jsjty.mayh.model
+ * Author  Administrator
+ * Created by 2015/5/14.
+ */
+public class Tfile {
+    private String fileId;
+    private String userId;
+    private String fileName;
+    private String filePath;
+    private Integer fileLength;
+    private Timestamp transTime;
+    private Integer wParam;
+    private Integer lParam;
+    private Integer dwTaskId;
+
+    public String getFileId() {
+        return fileId;
+    }
+
+    public void setFileId(String fileId) {
+        this.fileId = fileId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+
+    public String getFilePath() {
+        return filePath;
+    }
+
+    public void setFilePath(String filePath) {
+        this.filePath = filePath;
+    }
+
+    public Integer getFileLength() {
+        return fileLength;
+    }
+
+    public void setFileLength(Integer fileLength) {
+        this.fileLength = fileLength;
+    }
+
+    public Timestamp getTransTime() {
+        return transTime;
+    }
+
+    public void setTransTime(Timestamp transTime) {
+        this.transTime = transTime;
+    }
+
+    public Integer getwParam() {
+        return wParam;
+    }
+
+    public void setwParam(Integer wParam) {
+        this.wParam = wParam;
+    }
+
+    public Integer getlParam() {
+        return lParam;
+    }
+
+    public void setlParam(Integer lParam) {
+        this.lParam = lParam;
+    }
+
+    public Integer getDwTaskId() {
+        return dwTaskId;
+    }
+
+    public void setDwTaskId(Integer dwTaskId) {
+        this.dwTaskId = dwTaskId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Tfile tfile = (Tfile) o;
+
+        if (fileId != null ? !fileId.equals(tfile.fileId) : tfile.fileId != null) return false;
+        if (userId != null ? !userId.equals(tfile.userId) : tfile.userId != null) return false;
+        if (fileName != null ? !fileName.equals(tfile.fileName) : tfile.fileName != null) return false;
+        if (filePath != null ? !filePath.equals(tfile.filePath) : tfile.filePath != null) return false;
+        if (fileLength != null ? !fileLength.equals(tfile.fileLength) : tfile.fileLength != null) return false;
+        if (transTime != null ? !transTime.equals(tfile.transTime) : tfile.transTime != null) return false;
+        if (wParam != null ? !wParam.equals(tfile.wParam) : tfile.wParam != null) return false;
+        if (lParam != null ? !lParam.equals(tfile.lParam) : tfile.lParam != null) return false;
+        if (dwTaskId != null ? !dwTaskId.equals(tfile.dwTaskId) : tfile.dwTaskId != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = fileId != null ? fileId.hashCode() : 0;
+        result = 31 * result + (userId != null ? userId.hashCode() : 0);
+        result = 31 * result + (fileName != null ? fileName.hashCode() : 0);
+        result = 31 * result + (filePath != null ? filePath.hashCode() : 0);
+        result = 31 * result + (fileLength != null ? fileLength.hashCode() : 0);
+        result = 31 * result + (transTime != null ? transTime.hashCode() : 0);
+        result = 31 * result + (wParam != null ? wParam.hashCode() : 0);
+        result = 31 * result + (lParam != null ? lParam.hashCode() : 0);
+        result = 31 * result + (dwTaskId != null ? dwTaskId.hashCode() : 0);
+        return result;
+    }
+}

+ 158 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/model/Tlocation.java

@@ -0,0 +1,158 @@
+package com.jsjty.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * package com.jsjty.mayh.model
+ * Author  Administrator
+ * Created by 2015/5/14.
+ */
+public class Tlocation implements Serializable{
+    /**serialVersionUID */
+    private static final long serialVersionUID = 8258347932745336409L;
+    private String locationId;
+    private String userId;
+    private String imei;
+    private Double latitude;
+    private Double longtitude;
+    private Float speed;
+    private Float direction;
+    private Float accuracy;
+    private Double altitude;
+    private Date receiveDate;
+
+    public String getLocationId() {
+        return locationId;
+    }
+
+    public void setLocationId(String locationId) {
+        this.locationId = locationId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getImei() {
+        return imei;
+    }
+
+    public void setImei(String imei) {
+        this.imei = imei;
+    }
+
+    public Double getLatitude() {
+        return latitude;
+    }
+
+    public void setLatitude(Double latitude) {
+        this.latitude = latitude;
+    }
+
+    public Double getLongtitude() {
+        return longtitude;
+    }
+
+    public void setLongtitude(Double longtitude) {
+        this.longtitude = longtitude;
+    }
+
+    public Float getSpeed() {
+        return speed;
+    }
+
+    public void setSpeed(Float speed) {
+        this.speed = speed;
+    }
+
+    public Float getDirection() {
+        return direction;
+    }
+
+    public Double getAltitude() {
+        return altitude;
+    }
+
+    public void setAltitude(Double altitude) {
+        this.altitude = altitude;
+    }
+
+    public void setDirection(Float direction) {
+        this.direction = direction;
+    }
+
+    public Float getAccuracy() {
+        return accuracy;
+    }
+
+    public void setAccuracy(Float accuracy) {
+        this.accuracy = accuracy;
+    }
+
+    public Date getReceiveDate() {
+        return receiveDate;
+    }
+
+    public void setReceiveDate(Date receiveDate) {
+        this.receiveDate = receiveDate;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Tlocation tlocation = (Tlocation) o;
+
+        if (accuracy != null ? !accuracy.equals(tlocation.accuracy) : tlocation.accuracy != null) return false;
+        if (altitude != null ? !altitude.equals(tlocation.altitude) : tlocation.altitude != null) return false;
+        if (direction != null ? !direction.equals(tlocation.direction) : tlocation.direction != null) return false;
+        if (imei != null ? !imei.equals(tlocation.imei) : tlocation.imei != null) return false;
+        if (latitude != null ? !latitude.equals(tlocation.latitude) : tlocation.latitude != null) return false;
+        if (locationId != null ? !locationId.equals(tlocation.locationId) : tlocation.locationId != null) return false;
+        if (longtitude != null ? !longtitude.equals(tlocation.longtitude) : tlocation.longtitude != null) return false;
+        if (receiveDate != null ? !receiveDate.equals(tlocation.receiveDate) : tlocation.receiveDate != null)
+            return false;
+        if (speed != null ? !speed.equals(tlocation.speed) : tlocation.speed != null) return false;
+        if (userId != null ? !userId.equals(tlocation.userId) : tlocation.userId != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = locationId != null ? locationId.hashCode() : 0;
+        result = 31 * result + (userId != null ? userId.hashCode() : 0);
+        result = 31 * result + (imei != null ? imei.hashCode() : 0);
+        result = 31 * result + (latitude != null ? latitude.hashCode() : 0);
+        result = 31 * result + (longtitude != null ? longtitude.hashCode() : 0);
+        result = 31 * result + (speed != null ? speed.hashCode() : 0);
+        result = 31 * result + (direction != null ? direction.hashCode() : 0);
+        result = 31 * result + (accuracy != null ? accuracy.hashCode() : 0);
+        result = 31 * result + (altitude != null ? altitude.hashCode() : 0);
+        result = 31 * result + (receiveDate != null ? receiveDate.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer("Tlocation{");
+        sb.append("locationId='").append(locationId).append('\'');
+        sb.append(", userId='").append(userId).append('\'');
+        sb.append(", imei='").append(imei).append('\'');
+        sb.append(", latitude=").append(latitude);
+        sb.append(", longtitude=").append(longtitude);
+        sb.append(", speed=").append(speed);
+        sb.append(", direction=").append(direction);
+        sb.append(", accuracy=").append(accuracy);
+        sb.append(", altitude=").append(altitude);
+        sb.append(", receiveDate=").append(receiveDate);
+        sb.append('}');
+        return sb.toString();
+    }
+}

+ 82 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/model/Tlog.java

@@ -0,0 +1,82 @@
+package com.jsjty.model;
+
+import java.sql.Timestamp;
+
+/**
+ * package com.jsjty.mayh.model
+ * Author  Administrator
+ * Created by 2015/5/14.
+ */
+public class Tlog {
+    private String logId;
+    private Timestamp logTime;
+    private String userId;
+    private Integer operation;
+    private String remark;
+
+    public String getLogId() {
+        return logId;
+    }
+
+    public void setLogId(String logId) {
+        this.logId = logId;
+    }
+
+    public Timestamp getLogTime() {
+        return logTime;
+    }
+
+    public void setLogTime(Timestamp logTime) {
+        this.logTime = logTime;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public Integer getOperation() {
+        return operation;
+    }
+
+    public void setOperation(Integer operation) {
+        this.operation = operation;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Tlog tlog = (Tlog) o;
+
+        if (logId != null ? !logId.equals(tlog.logId) : tlog.logId != null) return false;
+        if (logTime != null ? !logTime.equals(tlog.logTime) : tlog.logTime != null) return false;
+        if (userId != null ? !userId.equals(tlog.userId) : tlog.userId != null) return false;
+        if (operation != null ? !operation.equals(tlog.operation) : tlog.operation != null) return false;
+        if (remark != null ? !remark.equals(tlog.remark) : tlog.remark != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = logId != null ? logId.hashCode() : 0;
+        result = 31 * result + (logTime != null ? logTime.hashCode() : 0);
+        result = 31 * result + (userId != null ? userId.hashCode() : 0);
+        result = 31 * result + (operation != null ? operation.hashCode() : 0);
+        result = 31 * result + (remark != null ? remark.hashCode() : 0);
+        return result;
+    }
+}

+ 28 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/model/Tusermsg.java

@@ -0,0 +1,28 @@
+package com.jsjty.model;
+
+public class Tusermsg {
+	
+	private int from_user_id;
+	private int number;
+	
+	public int getFrom_user_id() {
+		return from_user_id;
+	}
+	public void setFrom_user_id(int from_user_id) {
+		this.from_user_id = from_user_id;
+	}
+	public int getNumber() {
+		return number;
+	}
+	public void setNumber(int number) {
+		this.number = number;
+	}
+	
+	@Override
+	public String toString() {
+		return "Tusermsg [from_user_id=" + from_user_id + ", number=" + number
+				+ "]";
+	}
+	
+
+}

+ 93 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/model/UserModel.java

@@ -0,0 +1,93 @@
+package com.jsjty.model;
+
+import java.io.Serializable;
+
+/**
+ * package com.jsjty.mayh.model
+ * Author Administrator
+ * Created by 2015/5/7.
+ */
+public class UserModel implements Serializable {
+    /** serialVersionUID */
+    private static final long serialVersionUID = -8359499108893136001L;
+    /** ID */
+    private String id;
+    /** 姓名 */
+    private String name;
+    /** 登录账号 */
+    private String uname;
+    /** 聊天用户ID */
+    private String chatid;
+    /** 登录密码 */
+    private String password;
+    /** 是否有效 */
+    private String valid;
+    /** 排序号 */
+    private int sortno = 0;
+    /** 联系电话 */
+    private String tel;
+
+    public String getTel() {
+        return tel;
+    }
+
+    public void setTel(String tel) {
+        this.tel = tel;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public int getSortno() {
+        return sortno;
+    }
+
+    public String getUname() {
+        return uname;
+    }
+
+    public String getValid() {
+        return valid;
+    }
+
+    public String getChatid() {
+        return chatid;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public void setSortno(int sortno) {
+        this.sortno = sortno;
+    }
+
+    public void setUname(String uname) {
+        this.uname = uname;
+    }
+
+    public void setValid(String valid) {
+        this.valid = valid;
+    }
+
+    public void setChatid(String chatid) {
+        this.chatid = chatid;
+    }
+}

+ 131 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/repository/GroupRepository.java

@@ -0,0 +1,131 @@
+package com.jsjty.repository;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.jdbc.core.namedparam.SqlParameterSource;
+import org.springframework.jdbc.support.GeneratedKeyHolder;
+import org.springframework.jdbc.support.KeyHolder;
+import org.springframework.stereotype.Repository;
+
+import com.jsjty.model.GroupModel;
+import com.jsjty.util.StringUtil;
+
+/**
+ * package com.jsjty.repository
+ * Author Administrator
+ * Created by 2015/5/13.
+ */
+@Repository
+public class GroupRepository implements IGroupRepository {
+    private final static Logger log = LoggerFactory.getLogger(GroupRepository.class);
+    @Autowired
+    private NamedParameterJdbcTemplate jdbcTemplate;
+    public static final String TABLE_GROUP = "t_chat_group";
+    BeanPropertyRowMapper<GroupModel> beanPropertyRowMapper = BeanPropertyRowMapper.newInstance(GroupModel.class);
+
+    @Override
+    public GroupModel add(GroupModel group) {
+        String insertSql = "INSERT INTO t_chat_group(ID, USER,NAME,VALID,SORTNO) VALUES (:id, :user,:name,:valid,:sortno)";
+        Map<String, Object> params = new HashMap<String, Object>();
+        group.setId(StringUtil.getUUID());
+        params.put("id", group.getId());
+        params.put("user", group.getUser());
+        params.put("name", group.getName());
+        params.put("valid", "Y");
+        params.put("sortno", 1);
+        KeyHolder keyHolder = new GeneratedKeyHolder();
+        SqlParameterSource ps = new MapSqlParameterSource(params);
+        jdbcTemplate.update(insertSql, ps, keyHolder);
+        group.setGroupId(keyHolder.getKey().intValue());
+        log.debug("新增分组成功成功:" + group.getId());
+        return group;
+    }
+
+    @Override
+    public void update(GroupModel group) {
+        String updSql = "UPDATE t_chat_group SET NAME=:name, VALID=:valid WHERE group_id=:groupId";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("groupId", group.getGroupId());
+        params.put("name", group.getName());
+        params.put("valid", group.getValid());
+        jdbcTemplate.update(updSql, params);
+        log.debug("更新分组成功成功:" + group.getId());
+    }
+
+    @Override
+    public GroupModel findById(String id) {
+        String sql = "SELECT * FROM " + TABLE_GROUP + " WHERE id = :id ";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("id", id);
+        List<GroupModel> tresources = jdbcTemplate.query(sql, params, beanPropertyRowMapper);
+        if (tresources.size() == 0) { return null; }
+        return tresources.get(0);
+    }
+
+    @Override
+    public GroupModel findByGroupId(int groupId) {
+        String sql = "SELECT * FROM " + TABLE_GROUP + " WHERE GROUP_ID = :groupId ";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("groupId", groupId);
+        List<GroupModel> tresources = jdbcTemplate.query(sql, params, beanPropertyRowMapper);
+        if (tresources.size() == 0) { return null; }
+        return tresources.get(0);
+    }
+
+    @Override
+    public List<GroupModel> findByUser(int userid) {
+        String sql = "SELECT * FROM " + TABLE_GROUP + " WHERE USER = :userid and valid='Y' order by sortno asc";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("userid", userid);
+        List<GroupModel> tresources = jdbcTemplate.query(sql, params, beanPropertyRowMapper);
+        return tresources;
+    }
+
+    @Override
+    public List<GroupModel> findAll() {
+        String sql = "SELECT * FROM " + TABLE_GROUP + " WHERE  valid='Y'";
+        Map<String, Object> params = new HashMap<String, Object>();
+        List<GroupModel> tresources = jdbcTemplate.query(sql, params, beanPropertyRowMapper);
+        return tresources;
+    }
+
+    public void addUser(int groupId, int userId) {
+        String updSql = "INSERT INTO t_chat_group_user (GROUP_ID, USER_ID, VALID) VALUES (:groupId,:userId,'Y')";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("groupId", groupId);
+        params.put("userId", userId);
+        jdbcTemplate.update(updSql, params);
+    }
+
+    /**
+     * 好友移动到指定分组<br>
+     * groupId 为负数时删除好友关联关系
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public void userMovToGroup(int dwUserId, int friendId, int groupId) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("groupId", groupId);
+        params.put("userId", dwUserId);
+        params.put("friendId", friendId);
+        String oldGroupSearch = "select gu.group_id from t_chat_group_user gu left join t_chat_group g on gu.group_id=g.group_id where g.user=:userId and gu.user_id=:friendId ";
+        Integer oldId = jdbcTemplate.queryForObject(oldGroupSearch, params, Integer.class);
+        params.put("oldId", oldId);
+        String updSql = null;
+        if(groupId<0) {
+            updSql = "delete from  t_chat_group_user where group_id=:oldId and user_id=:friendId";
+        }else {
+            updSql = "update t_chat_group_user set group_id=:groupId where group_id=:oldId and user_id=:friendId";
+        }
+        jdbcTemplate.update(updSql, params);
+    }
+}

+ 37 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/repository/IGroupRepository.java

@@ -0,0 +1,37 @@
+package com.jsjty.repository;
+
+import java.util.List;
+
+import com.jsjty.model.GroupModel;
+
+/**
+ * 用户分组持久化接口
+ * 
+ * @author 袁晓冬
+ *
+ */
+public interface IGroupRepository {
+
+    GroupModel add(GroupModel group);
+
+    void update(GroupModel group);
+
+    List<GroupModel> findAll();
+
+    GroupModel findById(String id);
+
+    GroupModel findByGroupId(int groupId);
+
+    List<GroupModel> findByUser(int userid);
+
+    void addUser(int groupId, int userId);
+
+    /**
+     * 好友移动到指定分组
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public void userMovToGroup(int dwUserId, int friendId,int groupId);
+}

+ 40 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/repository/IMsgRepository.java

@@ -0,0 +1,40 @@
+/**
+ * lenovo2015年5月19日
+ * IMsgRepository
+ */
+package com.jsjty.repository;
+
+import java.util.List;
+
+import com.jsjty.model.MessageModel;
+
+/**
+ * @author lenovo
+ *
+ */
+public interface IMsgRepository {
+
+    /***
+     * 保存文字聊天记录
+     * 
+     * @param msg
+     */
+    public void saveMsg(MessageModel msg);
+
+    /**
+     * 查询离线消息
+     * 
+     * @param userid
+     * @return
+     */
+    public List<MessageModel> findOfflineMsg(int userid);
+
+    /**
+     * 查询历史消息
+     * 
+     * @param dwSrcUserId
+     * @param dwTarUserId
+     * @return
+     */
+    public List<MessageModel> findHistory(int dwSrcUserId, int dwTarUserId);
+}

+ 35 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/repository/ITerminalRepository.java

@@ -0,0 +1,35 @@
+package com.jsjty.repository;
+
+import com.jsjty.model.TerTrailModel;
+import com.jsjty.model.TerminalModel;
+
+/**
+ * 终端设备信息持久化接口
+ * 
+ * @author 袁晓冬
+ *
+ */
+public interface ITerminalRepository {
+
+    /**
+     * 根据设备ID查询终端信息
+     * 
+     * @param id
+     * @return
+     */
+    TerminalModel findByDeviceId(String id);
+
+    /**
+     * 删除终端实时位置
+     * 
+     * @param deviceId
+     */
+    public void deleteTrail(String deviceId);
+
+    /**
+     * 保存历史轨迹
+     * 
+     * @param trail
+     */
+    void saveTrail(TerTrailModel trail);
+}

+ 43 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/repository/IUserRepository.java

@@ -0,0 +1,43 @@
+package com.jsjty.repository;
+
+import com.jsjty.model.UserModel;
+
+import java.util.List;
+
+/**
+ * package com.jsjty.repository
+ * Author Administrator
+ * Created by 2015/5/13.
+ */
+public interface IUserRepository {
+
+    List<UserModel> findAll();
+
+    /**
+     * 根据好友名称查询好友
+     * 
+     * @return
+     */
+    List<UserModel> findByName(int dwUserId, String name);
+
+    UserModel findById(String userId);
+
+    UserModel findByAccount(String account);
+
+    /**
+     * 根据分组ID查找用户好友列表
+     * 
+     * @param groupId
+     * @return
+     */
+    List<UserModel> findByGroupId(int groupId);
+
+    public byte[] findUserPicture(String userid);
+
+    /**
+     * 更新用户的名称和电话
+     * 
+     * @param user
+     */
+    public void update(UserModel user);
+}

+ 103 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/repository/MsgRepository.java

@@ -0,0 +1,103 @@
+/**
+ * lenovo2015年5月21日
+ * MsgRepository
+ */
+package com.jsjty.repository;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.stereotype.Repository;
+
+import com.jsjty.model.MessageModel;
+
+/**
+ * @author lenovo
+ *
+ */
+@Repository
+public class MsgRepository implements IMsgRepository {
+    private final static Logger log = LoggerFactory.getLogger(MsgRepository.class);
+    @Autowired
+    private NamedParameterJdbcTemplate jdbcTemplate;
+    BeanPropertyRowMapper<MessageModel> beanPropertyRowMapper = BeanPropertyRowMapper.newInstance(MessageModel.class);
+
+    @Override
+    public void saveMsg(MessageModel msg) {
+        /** 存储到历史消息表 */
+        // 查询消息是否已存储
+        String sql = "SELECT count(1) FROM t_chat_msg_his  WHERE id = :id ";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("id", msg.getId());
+        Integer count = jdbcTemplate.queryForObject(sql, params, Integer.class);
+        if (null != count && count > 0) {
+            // 删除离线消息
+            if (msg.getStatus() == 1) {
+                // 更新记录状态和接收时间
+                sql = "update t_chat_msg_his set status=:status,RECVDATE=:recv where id=:id";
+                params.put("recv", msg.getRecvDate());
+                params.put("status", msg.getStatus());
+                jdbcTemplate.update(sql, params);
+                sql = "delete  FROM t_chat_msg_offline  WHERE id = :id ";
+                params.put("status", msg.getStatus());
+                jdbcTemplate.update(sql, params);
+            }
+        }
+        else {// 插入消息
+            sql = "INSERT INTO t_chat_msg_his(ID,DWROOMID,FROMUSERID,TOUSERID,MSG,RECVDATE,SENDDATE,SECRET,STATUS,FONTSIZE,FONTCOLOR,FONTWEIGHT,FONTFAMILY)VALUES(:id,:room,:from,:to,:msg,:recv,:send,:secret,:status,:fontSize,:fontColor,:fontWeight,:fontFamily) ";
+            params.clear();
+            params.put("id", msg.getId());
+            params.put("room", msg.getDwRoomId());
+            params.put("from", msg.getFromUserId());
+            params.put("to", msg.getToUserId());
+            params.put("msg", msg.getMsg());
+            params.put("recv", msg.getRecvDate());
+            params.put("send", msg.getSendDate());
+            params.put("secret", msg.getSecret());
+            params.put("status", msg.getStatus());
+            params.put("fontSize", msg.getFontSize());
+            params.put("fontColor", msg.getFontColor());
+            params.put("fontWeight", msg.getFontWeight());
+            params.put("fontFamily", msg.getFontWeight());
+            jdbcTemplate.update(sql, params);
+            log.debug("新增消息历史数据成功:" + msg.getId());
+            /** 如果消息状态为0,则存储到离线消息表 */
+            if (msg.getStatus() == 0) {
+                sql = "INSERT INTO t_chat_msg_offline(ID,DWROOMID,FROMUSERID,TOUSERID,MSG,RECVDATE,SENDDATE,SECRET,STATUS,FONTSIZE,FONTCOLOR,FONTWEIGHT,FONTFAMILY)VALUES(:id,:room,:from,:to,:msg,:recv,:send,:secret,:status,:fontSize,:fontColor,:fontWeight,:fontFamily) ";
+                jdbcTemplate.update(sql, params);
+                log.debug("新增离线消息数据成功:" + msg.getId());
+            }
+        }
+
+    }
+
+    /**
+     * 查询离线消息
+     * 
+     * @param userid
+     * @return
+     */
+    public List<MessageModel> findOfflineMsg(int userid) {
+        String sql = "SELECT * FROM t_chat_msg_offline  WHERE TOUSERID = :userid ";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("userid", userid);
+        List<MessageModel> offlines = jdbcTemplate.query(sql, params, beanPropertyRowMapper);
+        return offlines;
+    }
+
+    @Override
+    public List<MessageModel> findHistory(int dwSrcUserId, int dwTarUserId) {
+        String sql = "SELECT * FROM t_chat_msg_his  WHERE TOUSERID = :toUser and FROMUSERID=:fromUser ";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("fromUser", dwSrcUserId);
+        params.put("toUser", dwTarUserId);
+        List<MessageModel> offlines = jdbcTemplate.query(sql, params, beanPropertyRowMapper);
+        return offlines;
+    }
+}

+ 101 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/repository/TerminalRepository.java

@@ -0,0 +1,101 @@
+package com.jsjty.repository;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.stereotype.Repository;
+
+import com.jsjty.model.TerTrailModel;
+import com.jsjty.model.TerminalModel;
+import com.jsjty.util.StringUtil;
+
+/**
+ * 终端持久化接口
+ * 
+ * @author 袁晓冬
+ *
+ */
+@Repository
+public class TerminalRepository implements ITerminalRepository {
+    private final Logger log = LoggerFactory.getLogger(TerminalRepository.class);
+    @Autowired
+    private NamedParameterJdbcTemplate jdbcTemplate;
+    public static final String TABLE_TERMINAL = "t_jdc_terminal";
+    BeanPropertyRowMapper<TerminalModel> beanPropertyRowMapper = BeanPropertyRowMapper.newInstance(TerminalModel.class);
+    BeanPropertyRowMapper<TerTrailModel> terTrailModelRowMapper = BeanPropertyRowMapper
+            .newInstance(TerTrailModel.class);
+
+    @Override
+    public TerminalModel findByDeviceId(String deviceId) {
+        String sql = "SELECT * FROM " + TABLE_TERMINAL + " WHERE DEVICE_ID = :deviceId ";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("deviceId", deviceId);
+        List<TerminalModel> tresources = jdbcTemplate.query(sql, params, beanPropertyRowMapper);
+        if (tresources.size() == 0) { return null; }
+        return tresources.get(0);
+    }
+
+    /**
+     * 设备离线时删除设备实时位置
+     * 
+     * @param deviceId
+     */
+    @Override
+    public void deleteTrail(String deviceId) {
+        String sql = "delete from t_jdc_terminal_rt where  DEVICE_ID=:deviceId";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("deviceId", deviceId);
+        jdbcTemplate.update(sql, params);
+    }
+
+    @Override
+    public void saveTrail(TerTrailModel trail) {
+        // 插入轨迹表
+        String sql = "INSERT INTO t_jdc_terminal_trail(ID,DEVICE_ID,DEVICE_NAME,USER_ID,USER_NAME,LON,LAT,UPDTIME,SPEED,DIRECTION,ACCURACY,ALTITUDE,RECVDATE)VALUES(:id,:deviceId,:deviceName,:userId,:userName,:lon,:lat,:updtime,:speed,:direction,:accuracy,:altitude,:recvdate) ";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("id", StringUtil.getUUID());
+        params.put("deviceId", trail.getDeviceId());
+        params.put("deviceName", trail.getDeviceName());
+        params.put("userId", trail.getUserId());
+        params.put("userName", trail.getUserName());
+        params.put("lon", trail.getLon());
+        params.put("lat", trail.getLat());
+        params.put("speed", trail.getSpeed());
+        params.put("direction", trail.getDirection());
+        params.put("accuracy", trail.getAccuracy());
+        params.put("altitude", trail.getAltitude());
+        params.put("recvdate", new Date(trail.getReceiveDate()));
+        DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
+        params.put("updtime", df.format(new Date()));
+        log.debug(sql + "  " + params.toString());
+        int tresources = jdbcTemplate.update(sql, params);
+        log.debug(tresources == 1 ? "新增终端轨迹数据成功" : "新增终端轨迹数据失败");
+        // 插入当前位置表
+        sql = "SELECT * FROM T_JDC_TERMINAL_RT  WHERE DEVICE_ID = :deviceId ";
+        Map<String, Object> params2 = new HashMap<String, Object>();
+        params2.put("deviceId", trail.getDeviceId());
+        List<TerTrailModel> olds = jdbcTemplate.query(sql, params2, terTrailModelRowMapper);
+        if (null == olds || olds.size() == 0) {
+            sql = "INSERT INTO t_jdc_terminal_rt(ID,DEVICE_ID,DEVICE_NAME,USER_ID,USER_NAME,LON,LAT,UPDTIME,SPEED,DIRECTION,ACCURACY,ALTITUDE,RECVDATE)VALUES(:id,:deviceId,:deviceName,:userId,:userName,:lon,:lat,:updtime,:speed,:direction,:accuracy,:altitude,:recvdate) ";
+            tresources = jdbcTemplate.update(sql, params);
+            log.debug(tresources == 1 ? "新增终端实时位置数据成功" : "新增终端实时位置数据失败");
+        }
+        else {
+            sql = "UPDATE t_jdc_terminal_rt SET USER_ID=:userId,LON=:lon,Lat=:lat, UPDTIME=:updtime,user_name=:userName  where ID=:id";
+            params.put("id", olds.get(0).getId());
+            tresources = jdbcTemplate.update(sql, params);
+            log.debug(tresources == 1 ? "更新终端实时位置数据成功" : "更新终端实时位置数据失败");
+        }
+
+    }
+
+}

+ 118 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/repository/UserRepository.java

@@ -0,0 +1,118 @@
+package com.jsjty.repository;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.jdbc.core.namedparam.SqlParameterSource;
+import org.springframework.jdbc.support.lob.LobHandler;
+import org.springframework.stereotype.Repository;
+
+import com.jsjty.model.UserModel;
+import com.jsjty.util.StringUtil;
+
+/**
+ * package com.jsjty.repository
+ * Author Administrator
+ * Created by 2015/5/13.
+ */
+@Repository
+public class UserRepository implements IUserRepository {
+    @Autowired
+    private NamedParameterJdbcTemplate jdbcTemplate;
+
+    @Autowired
+    private LobHandler lobHandler;
+    private static final String ALL_TXT_COLUMN = "ID,NAME,UNAME,ORG,ORG_NAME,CREATETIME,VALID,SORTNO,CHATID,TEL";
+    BeanPropertyRowMapper<UserModel> beanPropertyRowMapper = BeanPropertyRowMapper.newInstance(UserModel.class);
+
+    public List<UserModel> findAll() {
+        String sql = "SELECT " + ALL_TXT_COLUMN + " FROM T_XTFRAME_USER where valid='Y' ";
+        List<UserModel> tresources = jdbcTemplate.query(sql, beanPropertyRowMapper);
+        if (tresources != null) { return tresources; }
+        return Collections.emptyList();
+    }
+
+    /**
+     * 更新用户的名称和电话
+     * 
+     * @param user
+     */
+    public void update(UserModel user) {
+        String updSql = "UPDATE T_XTFRAME_USER SET NAME=:name, TEL=:tel,PASSWORD=:pwd WHERE id=:id";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("name", user.getName());
+        params.put("tel", user.getTel());
+        params.put("id", user.getId());
+        params.put("pwd", user.getPassword());
+        jdbcTemplate.update(updSql, params);
+    }
+
+    public byte[] findUserPicture(String userid) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("userid", userid);
+        byte[] ret = jdbcTemplate.queryForObject(
+                "select b.VALUE from t_xtframe_blob b join T_XTFRAME_USER u on b.id=u.picture where u.id=:userid",
+                params, new RowMapper<byte[]>() {
+                    public byte[] mapRow(ResultSet rs, int rowNum) throws SQLException {
+                        byte[] attach = lobHandler.getBlobAsBytes(rs, 1);
+                        return attach;
+                    }
+                });
+        return ret;
+    }
+
+    public UserModel findById(String userId) {
+        String sql = "SELECT " + ALL_TXT_COLUMN + ",PASSWORD FROM T_XTFRAME_USER WHERE chatid = :id";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("id", userId);
+        List<UserModel> tresources = jdbcTemplate.query(sql, params, beanPropertyRowMapper);
+        if (tresources.size() == 0) { return null; }
+        return tresources.get(0);
+    }
+
+    @Override
+    public UserModel findByAccount(String account) {
+        String sql = "SELECT " + ALL_TXT_COLUMN + ",PASSWORD FROM T_XTFRAME_USER WHERE uname = :account and valid='Y' ";
+        Map<String, Object> params = new HashMap<>();
+        params.put("account", account);
+        List<UserModel> eausers = jdbcTemplate.query(sql, params, beanPropertyRowMapper);
+        if (eausers.size() == 0) { return null; }
+        return eausers.get(0);
+    }
+
+    @Override
+    public List<UserModel> findByGroupId(int groupId) {
+        String sql = "SELECT U.ID,U.NAME,U.UNAME,U.ORG,U.ORG_NAME,U.PASSWORD,U.CREATETIME,U.VALID,U.SORTNO,U.CHATID,U.TEL FROM t_chat_group_user t ,T_XTFRAME_USER u where t.user_id = u.chatid and t.group_id = :groupId and u.valid='Y'";
+        Map<String, Object> params = new HashMap<>();
+        params.put("groupId", groupId);
+        List<UserModel> eausers = jdbcTemplate.query(sql, params, beanPropertyRowMapper);
+        if (StringUtil.isNotEmpty(eausers)) { return eausers; }
+        return Collections.emptyList();
+    }
+
+    /**
+     * 根据好友名称查询好友
+     * 
+     * @return
+     */
+    public List<UserModel> findByName(int dwUserId, String name) {
+        String sql = "SELECT " + ALL_TXT_COLUMN
+                + " FROM T_XTFRAME_USER where valid='Y' and chatid<>:userid and name like :name and not exists(select 1 from t_chat_group_user gu  left join t_chat_group g on gu.group_id=g.group_id where g.user=:userid and g.valid='Y' and gu.valid='Y' and gu.valid='Y' and gu.user_id = chatid)";
+        Map<String, Object> params = new HashMap<>();
+        params.put("userid", dwUserId);
+        params.put("name", "%" + name + "%");
+        SqlParameterSource ps = new MapSqlParameterSource(params);
+        List<UserModel> tresources = jdbcTemplate.query(sql, ps, beanPropertyRowMapper);
+        if (tresources != null) { return tresources; }
+        return Collections.emptyList();
+    }
+}

+ 165 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/ChatCustomService.java

@@ -0,0 +1,165 @@
+package com.jsjty.service;
+
+import java.util.List;
+
+import com.jsjty.bean.ChatCmd;
+import com.jsjty.model.MessageModel;
+
+/**
+ * 聊天自定义服务
+ * 
+ * @author 袁晓冬
+ *
+ */
+public interface ChatCustomService {
+    /**
+     * 保存手机位置
+     * 
+     * @param dwUserId
+     * @param cmd
+     * @return
+     */
+    public ChatCmd saveLocation(ChatCmd cmd);
+
+    /**
+     * 查询消息历史
+     * 
+     * @param dwUserId
+     * @param cmd
+     * @return
+     */
+    public ChatCmd queryMessageHistory(int dwUserId, ChatCmd cmd);
+
+    /**
+     * 保存接收到的消息
+     * 
+     * @param msg
+     * @return
+     */
+    public ChatCmd saveMsg(MessageModel msg);
+
+    /**
+     * 用户发送聊天信息
+     * 
+     * @param dwUserId
+     *            发送人
+     * @param recv
+     *            发送内容
+     * @return
+     */
+    public ChatCmd sendMsg(int dwUserId, ChatCmd recv);
+
+    /**
+     * 用户接收消息确认
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public void recvMsg(int dwUserId, ChatCmd recv);
+
+    /**
+     * 查询离线消息
+     * 
+     * @param userid
+     * @return
+     */
+    public List<MessageModel> queryOfflineMsg(int userid);
+
+    /**
+     * 创建用户好友分组
+     * 
+     * @param dwUserId
+     * @param recv
+     */
+    public ChatCmd groupCreate(int dwUserId, ChatCmd recv);
+
+    /**
+     * 删除好友分组
+     * 
+     * @param dwUserId
+     * @param recv
+     */
+    public ChatCmd groupDelete(int dwUserId, ChatCmd recv);
+
+    /**
+     * 更新好友分组
+     * 
+     * @param dwUserId
+     * @param recv
+     */
+    public ChatCmd groupUpdate(int dwUserId, ChatCmd recv);
+
+    /**
+     * 查询用户所有分组
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public ChatCmd groupFindAll(int dwUserId, ChatCmd recv);
+
+    /**
+     * 查询好友
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public ChatCmd userFind(int dwUserId, ChatCmd recv);
+
+    /**
+     * 添加好友至分组
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public ChatCmd userAddToGroup(int dwUserId, ChatCmd recv);
+
+    /**
+     * 好友移动到指定分组
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public ChatCmd userMovToGroup(int dwUserId, ChatCmd recv);
+
+    /**
+     * 登录用户修改名称
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public ChatCmd userChangeName(String userId, ChatCmd recv);
+
+    /**
+     * 登录用户修改手机
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public ChatCmd userChangePhone(String userId, ChatCmd recv);
+
+    /**
+     * 修改当前用户登录密码
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public ChatCmd userChangePwd(String userId, ChatCmd recv);
+
+    /**
+     * 确认接收提醒消息
+     * 
+     * @param userId
+     * @param recv
+     * @return
+     */
+    public ChatCmd confirmMsg(String userId, ChatCmd recv);
+
+}

+ 37 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/IGroupService.java

@@ -0,0 +1,37 @@
+package com.jsjty.service;
+
+import java.util.List;
+
+import com.jsjty.model.GroupModel;
+
+/**
+ * 用户分组服务
+ * 
+ * @author 袁晓冬
+ *
+ */
+public interface IGroupService {
+
+    GroupModel add(GroupModel group);
+
+    void update(GroupModel group);
+
+    List<GroupModel> findAll();
+
+    GroupModel findById(String id);
+
+    GroupModel findByGroupId(int groupId);
+
+    List<GroupModel> findByUser(int userid);
+
+    void addUser(int groupId, int userId);
+
+    /**
+     * 好友移动到指定分组
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public void userMovToGroup(int dwUserId, int friendId,int groupId);
+}

+ 5 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/IMessageService.java

@@ -0,0 +1,5 @@
+package com.jsjty.service;
+
+public interface IMessageService {
+    public void confirmMsg(String msgid);
+}

+ 39 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/IMsgService.java

@@ -0,0 +1,39 @@
+/**
+ * lenovo2015年5月25日
+ * IMsgService
+ */
+package com.jsjty.service;
+
+import java.util.List;
+
+import com.jsjty.model.MessageModel;
+
+/**
+ * @author lenovo
+ *
+ */
+public interface IMsgService {
+
+    public void saveMsg(MessageModel msg);
+
+    /**
+     * 查询消息历史记录<br>
+     * 
+     * @param dwSrcUserId
+     *            查询人ID
+     * @param dwTarUserId
+     *            查询目标人ID
+     * @return
+     */
+    List<MessageModel> findHistory(int dwSrcUserId, int dwTarUserId);
+
+    /**
+     * 查找离线消息
+     * 
+     * @param dwSrcUserId
+     * @param dwTarUserId
+     * @return
+     */
+    List<MessageModel> findOfflineMsg(int userid);
+
+}

+ 35 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/ITerminalService.java

@@ -0,0 +1,35 @@
+package com.jsjty.service;
+
+import com.jsjty.model.TerTrailModel;
+import com.jsjty.model.TerminalModel;
+
+/**
+ * 终端管理服务
+ * 
+ * @author 袁晓冬
+ *
+ */
+public interface ITerminalService {
+
+    /**
+     * 根据设备ID查询终端信息
+     * 
+     * @param id
+     * @return
+     */
+    TerminalModel findByDeviceId(String id);
+
+    /**
+     * 保存终端历史轨迹和实时位置
+     * 
+     * @param trail
+     */
+    void saveTrail(TerTrailModel trail);
+
+    /**
+     * 删除终端实时位置
+     * 
+     * @param deviceId
+     */
+    public void deleteTrail(String deviceId);
+}

+ 44 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/IUserService.java

@@ -0,0 +1,44 @@
+package com.jsjty.service;
+
+import com.jsjty.model.UserModel;
+
+import java.util.List;
+
+public interface IUserService {
+
+    UserModel findById(String userId);
+
+    UserModel findByAccount(String account);
+
+    List<UserModel> findAll();
+
+    /**
+     * 根据好友名称查询好友
+     * 
+     * @return
+     */
+    List<UserModel> findByName(int dwUserId, String name);
+
+    /**
+     * 根据分组ID查找用户好友列表
+     * 
+     * @param groupId
+     * @return
+     */
+    List<UserModel> findByGroupId(int groupId);
+
+    /**
+     * 获取用户图片
+     * 
+     * @param userid
+     * @return
+     */
+    public byte[] findUserPicture(String userid);
+
+    /**
+     * 更新用户的名称和电话
+     * 
+     * @param user
+     */
+    public void update(UserModel user);
+}

+ 324 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/ChatCustomServiceImpl.java

@@ -0,0 +1,324 @@
+package com.jsjty.service.impl;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.shiro.crypto.hash.SimpleHash;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.Cache;
+import org.springframework.cache.Cache.ValueWrapper;
+import org.springframework.cache.ehcache.EhCacheCacheManager;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import com.jsjty.bean.ChatCmd;
+import com.jsjty.bean.CmdConsts;
+import com.jsjty.model.GroupModel;
+import com.jsjty.model.MessageModel;
+import com.jsjty.model.TerTrailModel;
+import com.jsjty.model.UserModel;
+import com.jsjty.service.ChatCustomService;
+import com.jsjty.service.IGroupService;
+import com.jsjty.service.IMessageService;
+import com.jsjty.service.IMsgService;
+import com.jsjty.service.ITerminalService;
+import com.jsjty.service.IUserService;
+import com.jsjty.util.StringUtil;
+
+@Service("chatCustomService")
+public class ChatCustomServiceImpl implements ChatCustomService {
+    @Autowired
+    private IUserService userService;
+    @Autowired
+    private IMsgService msgService;
+    @Autowired
+    private ITerminalService terminalService;
+    @Autowired
+    private EhCacheCacheManager cacheManager;
+    @Autowired
+    private IGroupService groupService;
+    @Autowired
+    private IMessageService messageService;
+
+    /**
+     * 保存终端位置信息
+     */
+    @Override
+    public ChatCmd saveLocation(ChatCmd cmd) {
+        ChatCmd sendCmd = new ChatCmd();
+        try {
+            Double lon = new Double(String.valueOf(cmd.getAttr("lon")));
+            Double lat = new Double(String.valueOf(cmd.getAttr("lat")));
+            TerTrailModel trail = new TerTrailModel();
+            trail.setDeviceId(String.valueOf(cmd.getAttr("imei")));
+            trail.setDeviceName(String.valueOf(cmd.getAttr("deviceName")));
+            trail.setLat(lat);
+            trail.setLon(lon);
+            trail.setUserId(Integer.parseInt(String.valueOf(cmd.getAttr("userId"))));
+            trail.setUserName(String.valueOf(cmd.getAttr("userName")));
+            trail.setReceiveDate(System.currentTimeMillis());
+            trail.setSpeed(cmd.getStringAttr("speed"));
+            trail.setAccuracy(cmd.getStringAttr("accuracy"));
+            trail.setAltitude(cmd.getStringAttr("altitude"));
+            trail.setDirection(cmd.getStringAttr("direction"));
+            terminalService.saveTrail(trail);
+            sendCmd.setCode(cmd.getCode());
+            sendCmd.setMessage("保存成功!");
+        }
+        catch (Exception e) {
+            sendCmd.setCode(CmdConsts.ERROR_COMMON);
+            sendCmd.setMessage("操作失败:" + e.getMessage());
+        }
+        return sendCmd;
+    }
+
+    /**
+     * 查询历史消息
+     */
+    public ChatCmd queryMessageHistory(int dwUserId, ChatCmd recv) {
+        String targetUser = String.valueOf(recv.getData());
+        if (StringUtils.isEmpty(targetUser)) { return ChatCmd.error(CmdConsts.ERROR_COMMON).setMessage("查询用户ID不能为空!"); }
+        UserModel u = userService.findById(targetUser);
+        if (u == null) { return ChatCmd.error(CmdConsts.ERROR_COMMON).setMessage("data中查询用户ID不能为空!"); }
+        ChatCmd cmd = new ChatCmd();
+        cmd.setCode(recv.getCode());
+        List<MessageModel> historyMsgs = msgService.findHistory(dwUserId, new Integer(targetUser));
+        cmd.setData(historyMsgs);
+        return cmd;
+    }
+
+    /**
+     * 查询离线消息
+     * 
+     * @param userid
+     * @return
+     */
+    public List<MessageModel> queryOfflineMsg(int userid) {
+        return msgService.findOfflineMsg(userid);
+    }
+
+    /**
+     * 保存消息<br>
+     * 仅保存到缓存中,当收到消息确认信息后再持久化到数据库<br>
+     * 定时没收到消息时重发
+     * 
+     * @param msg
+     * @return
+     */
+    public ChatCmd saveMsg(MessageModel msg) {
+        msgService.saveMsg(msg);
+        ChatCmd sendCmd = new ChatCmd();
+        sendCmd.setCode(CmdConsts.MSG_HISTROY);
+        sendCmd.setData(msg.getId());
+        return sendCmd;
+    }
+
+    /**
+     * 用户发送聊天信息
+     * 
+     * @param dwUserId
+     *            发送人
+     * @param recv
+     *            发送内容
+     * @return
+     */
+    public ChatCmd sendMsg(int dwUserId, ChatCmd recv) {
+        MessageModel msg = MessageModel.fromCmd(recv);
+        if (StringUtils.isEmpty(msg.getId())) {
+            msg.setId(StringUtil.getUUID());
+        }
+        msg.setSendDate(new Date());
+        msg.setStatus(0);
+        recv.setAttr("id", msg.getId());
+        Cache cache = cacheManager.getCache("messageCache");
+        cache.put(msg.getId(), msg);
+        return msg.toCmd();
+    }
+
+    /**
+     * 用户接收消息确认
+     */
+    public void recvMsg(int dwUserId, ChatCmd recv) {
+        String id = recv.getStringAttr("id");
+        Cache cache = cacheManager.getCache("messageCache");
+        ValueWrapper ele = cache.get(id);
+        if (null != ele && null != ele.get()) {
+            MessageModel msg = (MessageModel) ele.get();
+            if (msg.getToUserId().intValue() == dwUserId && msg.getStatus() == 0) {
+                msg.setStatus(1);
+                msg.setRecvDate(new Date());
+                msgService.saveMsg(msg);
+                cache.evict(id);
+            }
+        }
+    }
+
+    @Override
+    public ChatCmd groupCreate(int dwUserId, ChatCmd recv) {
+        String name = recv.getStringAttr("name");
+        if (StringUtil.isEmpty(name)) {
+            ChatCmd ret = new ChatCmd();
+            ret.setCode(CmdConsts.ERROR_FORMAT);
+            ret.setMessage("格式错误,分组名称不能为空");
+            return ret;
+        }
+        GroupModel group = new GroupModel();
+        group.setUser(String.valueOf(dwUserId));
+        group.setName(name);
+        group = groupService.add(group);
+        ChatCmd ret = new ChatCmd();
+        ret.setAttr("groupId", group.getGroupId());
+        ret.setAttr("name", group.getName());
+        ret.setMessage("操作成功!");
+        return ret;
+    }
+
+    @Override
+    public ChatCmd groupDelete(int dwUserId, ChatCmd recv) {
+        String groupId = recv.getStringAttr("groupId");
+        if (StringUtil.isEmpty(groupId)) {
+            ChatCmd ret = new ChatCmd();
+            ret.setCode(CmdConsts.ERROR_FORMAT);
+            ret.setMessage("格式错误,分组ID不能为空");
+            return ret;
+        }
+        GroupModel group = groupService.findByGroupId(Integer.parseInt(groupId));
+        group.setValid("N");
+        groupService.update(group);
+        ChatCmd ret = new ChatCmd();
+        ret.setMessage("操作成功!");
+        return ret;
+    }
+
+    @Override
+    public ChatCmd groupUpdate(int dwUserId, ChatCmd recv) {
+        String groupId = recv.getStringAttr("groupId");
+        if (StringUtil.isEmpty(groupId)) {
+            ChatCmd ret = new ChatCmd();
+            ret.setCode(CmdConsts.ERROR_FORMAT);
+            ret.setMessage("格式错误,分组ID不能为空");
+            return ret;
+        }
+        GroupModel group = new GroupModel();
+        group.setName(recv.getStringAttr("name"));
+        group.setValid("Y");
+        group.setGroupId(Integer.parseInt(groupId));
+        groupService.update(group);
+        ChatCmd ret = new ChatCmd();
+        ret.setMessage("操作成功!");
+        return ret;
+    }
+
+    @Override
+    public ChatCmd groupFindAll(int dwUserId, ChatCmd recv) {
+        List<GroupModel> groups = groupService.findByUser(dwUserId);
+        ChatCmd cmd = new ChatCmd();
+        cmd.setData(groups);
+        return cmd;
+    }
+
+    @Override
+    public ChatCmd userFind(int dwUserId, ChatCmd recv) {
+        String name = recv.getStringAttr("name");
+        List<UserModel> users = userService.findByName(dwUserId, name);
+        ChatCmd cmd = new ChatCmd();
+        cmd.setData(users);
+        return cmd;
+    }
+
+    @Override
+    public ChatCmd userAddToGroup(int dwUserId, ChatCmd recv) {
+        String groupId = recv.getStringAttr("groupId");
+        String userId = recv.getStringAttr("userId");
+        if (StringUtil.isEmpty(groupId) || StringUtil.isEmpty(userId)) {
+            ChatCmd ret = new ChatCmd();
+            ret.setCode(CmdConsts.ERROR_FORMAT);
+            ret.setMessage("格式错误,分组ID(groupId)和用户ID(userId)不能为空");
+            return ret;
+        }
+        GroupModel group = groupService.findByGroupId(Integer.parseInt(groupId));
+        if (!group.getUser().equals(String.valueOf(dwUserId))) {
+            ChatCmd ret = new ChatCmd();
+            ret.setCode(CmdConsts.ERROR_FORMAT);
+            ret.setMessage("只能添加到当前用户的分组");
+            return ret;
+        }
+        groupService.addUser(Integer.parseInt(groupId), Integer.parseInt(userId));
+        ChatCmd cmd = new ChatCmd();
+        cmd.setMessage("操作成功!");
+        return cmd;
+    }
+
+    /**
+     * 好友移动到指定分组
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public ChatCmd userMovToGroup(int dwUserId, ChatCmd recv) {
+        String groupId = recv.getStringAttr("groupId");
+        String userId = recv.getStringAttr("userId");
+        if (StringUtil.isEmpty(groupId) || StringUtil.isEmpty(userId)) {
+            ChatCmd ret = new ChatCmd();
+            ret.setCode(CmdConsts.ERROR_FORMAT);
+            ret.setMessage("格式错误,分组ID(groupId)和用户ID(userId)不能为空");
+            return ret;
+        }
+        groupService.userMovToGroup(dwUserId, Integer.parseInt(userId), Integer.parseInt(groupId));
+        ChatCmd cmd = new ChatCmd();
+        cmd.setMessage("操作成功!");
+        return cmd;
+    }
+
+    @Override
+    public ChatCmd userChangeName(String userId, ChatCmd recv) {
+        UserModel um = userService.findById(userId);
+        String name = recv.getStringAttr("name");
+        um.setName(name);
+        userService.update(um);
+        ChatCmd cmd = new ChatCmd();
+        cmd.setMessage("操作成功!");
+        return cmd;
+    }
+
+    @Override
+    public ChatCmd userChangePhone(String userId, ChatCmd recv) {
+        UserModel um = userService.findById(userId);
+        String tel = recv.getStringAttr("tel");
+        um.setTel(tel);
+        userService.update(um);
+        ChatCmd cmd = new ChatCmd();
+        cmd.setCode(recv.getCode());
+        cmd.setMessage("操作成功!");
+        return cmd;
+    }
+
+    @Override
+    public ChatCmd userChangePwd(String userId, ChatCmd recv) {
+        String old = recv.getStringAttr("old");
+        String pwd = recv.getStringAttr("pwd");
+        UserModel um = userService.findById(userId);
+        SimpleHash hash = new SimpleHash("SHA-256", old, null, 1);
+        ChatCmd cmd = new ChatCmd();
+        if (hash.toHex().equals(um.getPassword())) {
+            hash = new SimpleHash("SHA-256", pwd, null, 1);
+            um.setPassword(hash.toHex());
+            userService.update(um);
+            cmd.setCode(recv.getCode());
+            cmd.setMessage("操作成功!");
+        }
+        else {
+            cmd.setCode(CmdConsts.ERROR_COMMON);
+            cmd.setAttr("code", recv.getCode());
+            cmd.setMessage("密码不正确!");
+        }
+        return cmd;
+    }
+
+    @Override
+    public ChatCmd confirmMsg(String userId, ChatCmd recv) {
+        messageService.confirmMsg(recv.getStringAttr("id"));
+        return null;
+    }
+}

+ 70 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/GroupServiceImpl.java

@@ -0,0 +1,70 @@
+package com.jsjty.service.impl;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.jsjty.model.GroupModel;
+import com.jsjty.repository.IGroupRepository;
+import com.jsjty.service.IGroupService;
+
+/**
+ * 用户分组服务
+ * 
+ * @author 袁晓冬
+ *
+ */
+@Service
+public class GroupServiceImpl implements IGroupService {
+    @Autowired
+    private IGroupRepository repository;
+
+    @Override
+    @Transactional
+    public GroupModel add(GroupModel group) {
+        return repository.add(group);
+    }
+
+    @Override
+    public List<GroupModel> findAll() {
+        return repository.findAll();
+    }
+
+    @Override
+    public GroupModel findById(String id) {
+        return repository.findById(id);
+    }
+
+    @Override
+    public GroupModel findByGroupId(int groupId) {
+        return repository.findByGroupId(groupId);
+    }
+
+    @Override
+    public List<GroupModel> findByUser(int userid) {
+        return repository.findByUser(userid);
+    }
+
+    @Override
+    public void update(GroupModel group) {
+        repository.update(group);
+    }
+
+    @Override
+    public void addUser(int groupId, int userId) {
+        repository.addUser(groupId, userId);
+    }
+
+    /**
+     * 好友移动到指定分组
+     * 
+     * @param dwUserId
+     * @param recv
+     * @return
+     */
+    public void userMovToGroup(int dwUserId, int friendId, int groupId) {
+        repository.userMovToGroup(dwUserId, friendId, groupId);
+    }
+}

+ 29 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/MessageServiceImpl.java

@@ -0,0 +1,29 @@
+package com.jsjty.service.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.stereotype.Service;
+
+import com.jsjty.service.IMessageService;
+
+@Service
+public class MessageServiceImpl implements IMessageService {
+    private final static Logger log = LoggerFactory.getLogger(MessageServiceImpl.class);
+    @Autowired
+    private NamedParameterJdbcTemplate jdbcTemplate;
+
+    @Override
+    public void confirmMsg(String msgid) {
+        log.debug("confirm Msg id:{}", msgid);
+        String updSql = "UPDATE t_message set STATUS='2' WHERE ID=:id";
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("id", msgid);
+        jdbcTemplate.update(updSql, params);
+    }
+
+}

+ 47 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/MsgServiceImpl.java

@@ -0,0 +1,47 @@
+/**
+ * lenovo2015年5月25日
+ * MsgServiceImpl
+ */
+package com.jsjty.service.impl;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import com.jsjty.model.MessageModel;
+import com.jsjty.repository.IMsgRepository;
+import com.jsjty.service.IMsgService;
+
+/**
+ * 消息服务
+ * 
+ * @author 袁晓冬
+ *
+ */
+@Service
+public class MsgServiceImpl implements IMsgService {
+    @Value("${image.path}")
+    private String image_path;
+    @Value("${file.path}")
+    private String file_path;
+    @Autowired
+    private IMsgRepository msgRepository;
+
+    @Override
+    public void saveMsg(MessageModel msg) {
+        msgRepository.saveMsg(msg);
+    }
+
+    @Override
+    public List<MessageModel> findHistory(int dwSrcUserId, int dwTarUserId) {
+        return msgRepository.findHistory(dwSrcUserId, dwTarUserId);
+    }
+
+    @Override
+    public List<MessageModel> findOfflineMsg(int userid) {
+        return msgRepository.findOfflineMsg(userid);
+    }
+
+}

+ 35 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/TerminalServiceImpl.java

@@ -0,0 +1,35 @@
+package com.jsjty.service.impl;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.jsjty.model.TerTrailModel;
+import com.jsjty.model.TerminalModel;
+import com.jsjty.repository.ITerminalRepository;
+import com.jsjty.service.ITerminalService;
+
+/**
+ * 用户分组服务
+ * 
+ * @author 袁晓冬
+ *
+ */
+@Service
+public class TerminalServiceImpl implements ITerminalService {
+    @Autowired
+    private ITerminalRepository repository;
+
+    @Override
+    public TerminalModel findByDeviceId(String id) {
+        return repository.findByDeviceId(id);
+    }
+
+    public void saveTrail(TerTrailModel trail) {
+        repository.saveTrail(trail);
+    }
+
+    @Override
+    public void deleteTrail(String deviceId) {
+        repository.deleteTrail(deviceId);
+    }
+}

+ 62 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/service/impl/UserServiceImpl.java

@@ -0,0 +1,62 @@
+package com.jsjty.service.impl;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import com.jsjty.model.UserModel;
+import com.jsjty.repository.IUserRepository;
+import com.jsjty.service.IUserService;
+
+/**
+ * Created by myhnuhai on 2014/8/25.
+ */
+@Service
+public class UserServiceImpl implements IUserService {
+    //    private final static Logger logger = LoggerFactory.getLogger(IUserService.class);
+    @Value("${image.path}")
+    private String image_path;
+    @Value("${file.path}")
+    private String file_path;
+
+    @Autowired
+    private IUserRepository userRepository;
+
+    public UserModel findById(String userId) {
+        return userRepository.findById(userId);
+    }
+
+    public UserModel findByAccount(String account) {
+        return userRepository.findByAccount(account);
+    }
+
+    public List<UserModel> findAll() {
+        return userRepository.findAll();
+    }
+
+    //    @Override
+    public List<UserModel> findByGroupId(int groupId) {
+        return userRepository.findByGroupId(groupId);
+    }
+
+    //
+    public byte[] findUserPicture(String userid) {
+        return userRepository.findUserPicture(userid);
+    }
+
+    @Override
+    public List<UserModel> findByName(int dwUserId, String name) {
+        return userRepository.findByName(dwUserId, name);
+    }
+
+    /**
+     * 更新用户的名称和电话
+     * 
+     * @param user
+     */
+    public void update(UserModel user) {
+        userRepository.update(user);
+    }
+}

+ 72 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/task/MessageRemindTask.java

@@ -0,0 +1,72 @@
+package com.jsjty.task;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.stereotype.Service;
+
+import com.jsjty.bean.ChatCmd;
+import com.jsjty.bean.CmdConsts;
+import com.jsjty.bean.MsgBean;
+import com.jsjty.core.BusinessServer;
+import com.jsjty.task.base.BaseTask;
+
+/**
+ * 天气抓取服务
+ * 
+ * @author 袁晓冬
+ *
+ */
+@Service
+public class MessageRemindTask implements BaseTask {
+    private Logger logger = LoggerFactory.getLogger(MessageRemindTask.class);
+    @Autowired
+    private BusinessServer businessServer;
+    private ScheduledExecutorService executor;
+    @Autowired
+    private NamedParameterJdbcTemplate jdbcTemplate;
+    BeanPropertyRowMapper<MsgBean> beanPropertyRowMapper = BeanPropertyRowMapper.newInstance(MsgBean.class);
+
+    public MessageRemindTask() {
+        executor = Executors.newScheduledThreadPool(5);
+    }
+
+    @Override
+    public int doFetch() {
+        logger.info("消息抓取开始......");
+        String sql = "SELECT ID, CHATID, TITLE, CONTENT, SENDTIME, STATUS FROM T_MESSAGE WHERE STATUS='0' and SENDTIME<CURRENT_TIMESTAMP+300000 ";
+        Map<String, Object> params = new HashMap<String, Object>();
+        List<MsgBean> msgs = jdbcTemplate.query(sql, params, beanPropertyRowMapper);
+        for (MsgBean msg : msgs) {
+            ChatCmd send = new ChatCmd();
+            send.setCode(CmdConsts.MSG_REMIND);
+            if (msg.getChatid() > 0) {
+                send.setData(msg);
+                MessageSendService mss = new MessageSendService();
+                mss.setBusinessServer(businessServer);
+                mss.setMsg(msg);
+                long delay = msg.getSendtime().getTime() - System.currentTimeMillis();
+                if (delay < 0) {
+                    delay = 0;
+                }
+                executor.schedule(mss, delay, TimeUnit.MILLISECONDS);
+            }
+        }
+        logger.info("消息抓取结束。");
+        return msgs.size();
+    }
+
+    @Override
+    public String getName() {
+        return "消息抓取服务";
+    }
+}

+ 51 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/task/MessageSendService.java

@@ -0,0 +1,51 @@
+package com.jsjty.task;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.bairuitech.anychat.AnyChatOutParam;
+import com.jsjty.bean.ChatCmd;
+import com.jsjty.bean.CmdConsts;
+import com.jsjty.bean.MsgBean;
+import com.jsjty.core.BusinessServer;
+
+/**
+ * 消息发送任务
+ * 
+ * @author 袁晓冬
+ *
+ */
+public class MessageSendService implements Runnable {
+
+    private Logger logger = LoggerFactory.getLogger(MessageSendService.class);
+    private BusinessServer businessServer;
+
+    public BusinessServer getBusinessServer() {
+        return businessServer;
+    }
+
+    public void setBusinessServer(BusinessServer businessServer) {
+        this.businessServer = businessServer;
+    }
+
+    private MsgBean msg = null;
+
+    public MsgBean getMsg() {
+        return msg;
+    }
+
+    public void setMsg(MsgBean msg) {
+        this.msg = msg;
+    }
+
+    @Override
+    public void run() {
+        logger.info("run message send to user {} :{}", msg.getChatid(), msg.getId());
+        ChatCmd send = new ChatCmd();
+        send.setCode(CmdConsts.MSG_REMIND);
+        send.setData(msg);
+        AnyChatOutParam outParam = new AnyChatOutParam();
+        byte[] bytes = send.toBytes();
+        businessServer.transBufferEx(msg.getChatid(), bytes, bytes.length, 0, 0, 0, outParam);
+    }
+}

+ 17 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/task/base/BaseTask.java

@@ -0,0 +1,17 @@
+package com.jsjty.task.base;
+
+public interface BaseTask {
+    /**
+     * 执行抓取任务
+     * 
+     * @return
+     */
+    public abstract int doFetch();
+
+    /**
+     * 服务名称
+     * 
+     * @return
+     */
+    public String getName();
+}

+ 57 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/task/base/TaskRedoException.java

@@ -0,0 +1,57 @@
+package com.jsjty.task.base;
+
+import java.util.concurrent.TimeUnit;
+
+public class TaskRedoException extends RuntimeException {
+    /** serialVersionUID */
+    private static final long serialVersionUID = 2836734247983629232L;
+    /** the time from now to delay execution */
+    private long delay;
+    /** the time unit of the delay parameter */
+    private TimeUnit unit;
+    /** 详细信息 */
+    private String msg;
+
+    public String getMsg() {
+        return msg;
+    }
+
+    @Override
+    public String getMessage() {
+        if (msg != null && msg.length() > 0) { return msg; }
+        return super.getMessage();
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public long getDelay() {
+        return delay;
+    }
+
+    public TimeUnit getUnit() {
+        return unit;
+    }
+
+    public TaskRedoException() {
+        super();
+    }
+
+    public TaskRedoException(long delay, TimeUnit unit) {
+        this.delay = delay;
+        this.unit = unit;
+    }
+
+    public TaskRedoException(long delay, TimeUnit unit, Throwable e) {
+        super(e);
+        this.delay = delay;
+        this.unit = unit;
+    }
+
+    public TaskRedoException(long delay, TimeUnit unit, String msg) {
+        this.delay = delay;
+        this.unit = unit;
+        this.msg = msg;
+    }
+}

+ 73 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/task/base/TaskService.java

@@ -0,0 +1,73 @@
+package com.jsjty.task.base;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 抓取任务
+ * 
+ * @author 袁晓冬
+ *
+ */
+public class TaskService implements Runnable {
+    private final static Logger logger = LoggerFactory.getLogger(TaskService.class);
+    private BaseTask service;
+    private ScheduledExecutorService executor;
+    // 剩余重试次数
+    private int count = 0;
+    // 初始重试次数
+    private final int initCount;
+
+    public TaskService(BaseTask service, ScheduledExecutorService executor, int count) {
+        initCount = count;
+        this.service = service;
+        this.executor = executor;
+        this.count = count;
+    }
+
+    public <T extends BaseTask> TaskService(Class<T> serviceClazz, ScheduledExecutorService executor, int count) {
+        try {
+            this.service = serviceClazz.newInstance();
+        }
+        catch (InstantiationException | IllegalAccessException e) {
+            e.printStackTrace();
+            logger.error("创建任务执行对象错误,类型:{},错误消息:{}", serviceClazz.getName(), e.getMessage());
+        }
+        this.executor = executor;
+        this.count = count;
+        initCount = count;
+    }
+
+    @Override
+    public void run() {
+        logger.info("开始执行任务【{}】", service.getName());
+        try {
+            long start = System.currentTimeMillis();
+            int count = service.doFetch();
+            if (logger.isInfoEnabled()) {
+                logger.info("【{}】耗时:{}s,成功执行抓取{}条数据", service.getName(), (System.currentTimeMillis() - start) / 1000.0,
+                        count);
+            }
+        }
+        // 任务延时重新执行
+        catch (TaskRedoException e) {
+            if (count > 0) {
+                executor.schedule(this, e.getDelay(), e.getUnit());
+                count--;
+                logger.error("执行任务【{}】失败:{},延时 {} {} 执行,剩余重试次数:{}", service.getName(), e.getMessage(), e.getDelay(),
+                        e.getUnit(), count);
+            }
+            else {
+                logger.error("执行任务【{}】失败:{},服务接口:{},重试结束", service.getName(), e.getMessage());
+                // 重试结束,重置重试次数
+                count = initCount;
+            }
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+            logger.error("执行任务【{}】失败,错误信息:{}", service.getName(), e.getMessage());
+        }
+    }
+}

+ 121 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/BeanUtil.java

@@ -0,0 +1,121 @@
+package com.jsjty.util;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by 马英虎 on 2014/11/27.
+ */
+
+/**
+ * Map 与 JavaBean相互转换
+ */
+public class BeanUtil {
+    private final static Logger logger = LoggerFactory.getLogger(BeanUtil.class);
+
+    public static Map<String, Object> bean2Map(Object obj) {
+
+        if(obj == null){
+            return null;
+        }
+        Map<String, Object> map = new HashMap<String, Object>();
+        try {
+            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
+            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+            for (PropertyDescriptor property : propertyDescriptors) {
+                String key = property.getName();
+                // 过滤class属性
+                if (!key.equals("class")) {
+                    // 得到property对应的getter方法
+                    Method getter = property.getReadMethod();
+                    Object value = getter.invoke(obj);
+                    map.put(key, value);
+                }
+            }
+        } catch (Exception e) {
+            logger.error("转换出错:" + e);
+        }
+        return map;
+    }
+
+    public static void map2Bean(Map<String, Object> map, Object obj) {
+        try {
+            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
+            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+
+            for (PropertyDescriptor property : propertyDescriptors) {
+                String key = property.getName();
+                if (map.containsKey(key)) {
+                    Object value = map.get(key);
+                    Method setter = property.getWriteMethod();
+                    setter.invoke(obj, value);
+                }
+            }
+        } catch (Exception e) {
+            logger.error("map2Bean Error " + e);
+        }
+    }
+
+    private static PropertyDescriptor[] getPropertyDescriptors(Object target){
+        BeanInfo beanInfo = null;
+        try {
+            beanInfo = Introspector.getBeanInfo(target.getClass());
+            return beanInfo.getPropertyDescriptors();
+        } catch (IntrospectionException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private static PropertyDescriptor getPropertyDescriptor(Object target,String tarName){
+        PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(target);
+        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
+            if(propertyDescriptor.getName().equals(tarName)){
+                return propertyDescriptor;
+            }
+        }
+        return null;
+    }
+
+
+    public static void copyProperties(Object source, Object target )
+    {
+
+        PropertyDescriptor[] targetPds = getPropertyDescriptors(target);
+
+        for (PropertyDescriptor targetPd : targetPds) {
+            Method writeMethod = targetPd.getWriteMethod();
+            if (writeMethod != null) {
+                PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
+                if (sourcePd != null) {
+                    Method readMethod = sourcePd.getReadMethod();
+                    if (readMethod != null &&
+                            writeMethod.getParameterTypes()[0].isAssignableFrom(readMethod.getReturnType())) {
+                        try {
+                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
+                                readMethod.setAccessible(true);
+                            }
+                            Object value = readMethod.invoke(source);
+                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
+                                writeMethod.setAccessible(true);
+                            }
+                            writeMethod.invoke(target, value);
+                        }
+                        catch (Throwable ex) {
+                            ex.printStackTrace();
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 230 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/CodeUtil.java

@@ -0,0 +1,230 @@
+package com.jsjty.util;
+
+import java.io.IOException;
+import java.security.Key;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.DESKeySpec;
+
+import org.apache.commons.codec.binary.Base64;
+
+/**
+ * 加密工具类
+ *
+ * @author myhnuhai
+ */
+public class CodeUtil {
+    /**
+     * 创建Base64对象,用于加密和解密;
+     */
+    private final static Base64 base64 = new Base64();
+
+    /**
+     * 加密时采用的编码方式;
+     */
+    private final static String encoding = "UTF-8";
+
+    /**
+     * DES加密算法密钥<br>
+     * 0:节点属性值方式
+     */
+    public static final String BASE64_KEY = "mowen520";
+
+    /**
+     * 基于MD5算法的非对称加密(无解密算法)
+     *
+     * @param strSrc 明文
+     * @return 返回密文
+     */
+    public static String encryptMd5(String strSrc) {
+        String outString = null;
+        try {
+            MessageDigest md5 = MessageDigest.getInstance("MD5");
+            byte[] outByte = md5.digest(strSrc.getBytes("UTF-8"));
+            outString = outByte.toString();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return outString;
+    }
+
+    /**
+     * 用Base64对加密好的byte数组进行编码,返回字符串
+     *
+     * @param str  需要加密的字符串
+     * @param sKey 加密密钥
+     * @return 经过加密的字符串
+     */
+    public static String encryptBase64(String str, String sKey) {
+        // 声明加密后的结果字符串变量
+        String result = str;
+        if (str != null && str.length() > 0 && sKey != null && sKey.length() >= 8) {
+            try {
+                //调用DES 加密数组的 encrypt方法,返回加密后的byte数组;
+                byte[] encodeByte = encryptBasedDes(str.getBytes(encoding), sKey);
+                // 调用base64的编码方法,返回加密后的字符串;
+                result = base64.encodeToString(encodeByte).trim();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 用Base64对字符串进行编码,返回byte数组
+     *
+     * @param str  需要解密的字符串
+     * @param sKey 解密密钥
+     * @return 经过解密的字符串
+     */
+    public static String decryptBase64(String str, String sKey) {
+        String result = str;
+        if (str != null && str.length() > 0 && sKey != null && sKey.length() >= 8) {
+            try {
+                // 用base64进行编码,返回byte数组
+                byte[] encodeByte = base64.decode(str);
+                // 调用DES 解密数组的decrypte方法,返回解密后的数组;
+                byte[] decoder = decryptBasedDes(encodeByte, sKey);
+                // 对解密后的数组转化成字符串
+                result = new String(decoder, encoding).trim();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 先用DES算法对byte[]数组加密
+     *
+     * @param byteSource 需要加密的数据
+     * @param sKey       加密密钥
+     * @return 经过加密的数据
+     * @throws Exception
+     */
+    private static byte[] encryptBasedDes(byte[] byteSource, String sKey)
+            throws Exception {
+        try {
+            // 声明加密模式;
+            int mode = Cipher.ENCRYPT_MODE;
+            // 创建密码工厂对象;
+            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
+            // 把字符串格式的密钥转成字节数组;
+            byte[] keyData = sKey.getBytes();
+            // 以密钥数组为参数,创建密码规则
+            DESKeySpec keySpec = new DESKeySpec(keyData);
+            // 以密码规则为参数,用密码工厂生成密码
+            Key key = keyFactory.generateSecret(keySpec);
+            // 创建密码对象
+            Cipher cipher = Cipher.getInstance("DES");
+            // 以加密模式和密码为参数对密码对象 进行初始化
+            cipher.init(mode, key);
+            // 完成最终加密
+            byte[] result = cipher.doFinal(byteSource);
+            // 返回加密后的数组
+            return result;
+        } catch (Exception e) {
+            throw e;
+        }
+    }
+
+    /**
+     * 先用DES算法对byte[]数组解密
+     *
+     * @param byteSource 需要解密的数据
+     * @param sKey       解密密钥
+     * @return 经过解密的数据
+     * @throws Exception
+     */
+    private static byte[] decryptBasedDes(byte[] byteSource, String sKey)
+            throws Exception {
+        try {
+            // 声明解密模式;
+            int mode = Cipher.DECRYPT_MODE;
+            // 创建密码工厂对象;
+            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
+            // 把字符串格式的密钥转成字节数组;
+            byte[] keyData = sKey.getBytes();
+            // 以密钥数组为参数,创建密码规则
+            DESKeySpec keySpec = new DESKeySpec(keyData);
+            // 以密码规则为参数,用密码工厂生成密码
+            Key key = keyFactory.generateSecret(keySpec);
+            // 创建密码对象
+            Cipher cipher = Cipher.getInstance("DES");
+            // 以加密模式和密码为参数对密码对象 进行初始化
+            cipher.init(mode, key);
+            // 完成最终解密
+            byte[] result = cipher.doFinal(byteSource);
+            // 返回解密后的数组
+            return result;
+        } catch (Exception e) {
+            throw e;
+        }
+    }
+
+    /**
+     * 测试对称加密算法
+     *
+     * @param args
+     * @throws java.io.IOException
+     */
+    public static void main(String[] args) throws IOException {
+        String sKey = "mowen520";
+        String str = "111111";
+        Date date = new Date(System.currentTimeMillis());
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String strDate = simpleDateFormat.format(date);
+        long start = new Date().getTime();
+        System.out.println("开始时间:" + strDate + "   毫秒数:" + start);
+        for (int i = 0; i < 1; i++) {
+            String strEncrypto = CodeUtil.encryptBase64(str, sKey);
+            System.out.println("被加密的字符串:" + str + "\r\n加密后的结果:" + strEncrypto);
+            String strDecrypto = CodeUtil.decryptBase64(strEncrypto, sKey);
+            System.out.println("解密后的结果:" + strDecrypto);
+        }
+        Date date2 = new Date(System.currentTimeMillis());
+        String strDate2 = simpleDateFormat.format(date2);
+        long start2 = new Date().getTime();
+        System.out.println("结束时间:" + strDate2 + "   毫秒数:" + start2);
+        long time = start2 - start;
+        System.out.println("间隔时间:" + time);
+    }
+
+    /**
+     * md5加密
+     *
+     * @param str
+     * @return
+     */
+    public static String md5(String str) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            md.update(str.getBytes());
+            byte[] byteDigest = md.digest();
+            int i;
+            StringBuffer buf = new StringBuffer("");
+            for (int offset = 0; offset < byteDigest.length; offset++) {
+                i = byteDigest[offset];
+                if (i < 0)
+                    i += 256;
+                if (i < 16)
+                    buf.append("0");
+                buf.append(Integer.toHexString(i));
+            }
+            // 32位加密
+            return buf.toString();
+            // 16位的加密
+            // return buf.toString().substring(8, 24);
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+}

+ 55 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/CustomGetMethod.java

@@ -0,0 +1,55 @@
+package com.jsjty.util;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.zip.GZIPInputStream;
+
+public class CustomGetMethod {
+ 
+	public static String getGzip(HttpResponse response) {
+		try {
+            HttpEntity httpEntity = response.getEntity();
+            if (isGzip(response)) {
+                // For GZip response
+                InputStream is = httpEntity.getContent();
+                GZIPInputStream gzin = new GZIPInputStream(is);
+
+                InputStreamReader isr = new InputStreamReader(gzin, "utf-8");
+                java.io.BufferedReader br = new java.io.BufferedReader(isr);
+                StringBuffer sb = new StringBuffer();
+                String tempbf;
+                while ((tempbf = br.readLine()) != null) {
+                    sb.append(tempbf);
+                }
+                isr.close();
+                gzin.close();
+                return sb.toString();
+            } else {
+                return EntityUtils.toString(httpEntity, "utf-8");
+            }
+        }catch (IOException io){
+            io.printStackTrace();
+            return "";
+        }
+
+	}
+
+	private static boolean isGzip(HttpResponse response) {
+		if (response.containsHeader("Content-Encoding")) {
+			Header[] hs = response.getHeaders("Content-Encoding");
+			for (Header h : hs) {
+				if (h.getValue().toLowerCase().indexOf("gzip") > -1) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+}

+ 397 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/DateUtil.java

@@ -0,0 +1,397 @@
+package com.jsjty.util;
+
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Created by 马英虎 on 2014/5/20.
+ */
+public class DateUtil {
+
+    private final static Locale locale = Locale.CHINA;
+    public final static  int DAY_MILLISECOND = 86400000;
+    private final static SimpleDateFormat sdf = new SimpleDateFormat();// 定义格式,不显示毫秒
+
+    public final static String DATE_DAY_FMT = "yyyy-MM-dd";
+    public final static String DATE_HOUR_FMT = "yyyy-MM-dd HH:00:00";
+    public final static String DATE_MIN_FMT = "yyyy-MM-dd HH:mm:00";
+    public final static String DATE_SECOND_FMT = "yyyy-MM-dd HH:mm:ss";
+    public final static String DATE_TIME = "yyyyMMddHHmmss";
+    public final static String WEEK = "EEEE";
+
+    /**
+     * 将Date类型转换为字符串
+     *
+     * @param date
+     *            日期类型
+     * @return 日期字符串
+     */
+    public static String format(Date date) {
+        return format(date, "yyyy-MM-dd HH:mm:ss");
+    }
+
+    /**
+     * 将Date类型转换为字符串
+     *
+     * @param date
+     *            日期类型
+     * @param pattern
+     *            字符串格式
+     * @return 日期字符串
+     */
+    public static String format(Date date, String pattern) {
+        if (date == null) {
+            return "null";
+        }
+        if (pattern == null || pattern.equals("") || pattern.equals("null")) {
+            pattern = "yyyy-MM-dd HH:mm:ss";
+        }
+        return new java.text.SimpleDateFormat(pattern).format(date);
+    }
+
+    /**
+     * 将字符串转换为Date类型
+     *
+     * @param date
+     *            字符串类型
+     * @return 日期类型
+     */
+    public static Date format(String date) {
+        return format(date, null);
+    }
+
+    /**
+     * 将字符串转换为Date类型
+     *
+     * @param date
+     *            字符串类型
+     * @param pattern
+     *            格式
+     * @return 日期类型
+     */
+    public static Date format(String date, String pattern) {
+        if (pattern == null || pattern.equals("") || pattern.equals("null")) {
+            pattern = "yyyy-MM-dd HH:mm:ss";
+        }
+        if (date == null || date.equals("") || date.equals("null")) {
+            return new Date();
+        }
+        Date d = null;
+        try {
+            d = new java.text.SimpleDateFormat(pattern).parse(date);
+        } catch (ParseException pe) {
+        }
+        return d;
+    }
+
+
+
+    /**
+     * 传入的参数格式为: yyyy-MM-dd HH:mm:ss
+     *
+     * @category 字母 日期或时间元素 表示 示例 <br/>
+     *           G Era 标志符 Text AD <br/>
+     *           y 年 Year 1996; 96 <br/>
+     *           M 年中的月份 Month July; Jul; 07 <br/>
+     *           w 年中的周数 Number 27 <br/>
+     *           W 月份中的周数 Number 2 <br/>
+     *           D 年中的天数 Number 189 <br/>
+     *           d 月份中的天数 Number 10 <br/>
+     *           F 月份中的星期 Number 2 <br/>
+     *           E 星期中的天数 Text Tuesday; Tue <br/>
+     *           a Am/pm 标记 Text PM <br/>
+     *           H 一天中的小时数(0-23) Number 0 <br/>
+     *           k 一天中的小时数(1-24) Number 24 <br/>
+     *           K am/pm 中的小时数(0-11) Number 0 <br/>
+     *           h am/pm 中的小时数(1-12) Number 12 <br/>
+     *           m 小时中的分钟数 Number 30 <br/>
+     *           s 分钟中的秒数 Number 55 <br/>
+     *           S 毫秒数 Number 978 <br/>
+     *           z 时区 General time zone Pacific Standard Time; PST; GMT-08:00 <br/>
+     *           Z 时区 RFC 822 time zone -0800 <br/>
+     *
+     * @param date
+     * @return Timestamp
+     */
+    public static Timestamp str2Timestamp(String date) {
+        Timestamp returnt = Timestamp.valueOf(date);
+        return returnt;
+    }
+
+    /**
+     * Timestamp转换为String形式输出
+     *
+     * @param timestamp
+     * @param dfm
+     * @return String
+     * @category 转字符串的时候如果传入的参数dformat为null,则默认以yyyy-MM-dd
+     *           HH:mm:ss格式转换。否则按传入格式转。
+     *
+     */
+    public static String timestamp2Str(Timestamp timestamp, String dfm) {
+        String returnstr = "";
+        if (dfm == null) {
+            sdf.applyPattern(DATE_SECOND_FMT);
+        } else {
+            sdf.applyPattern(dfm);
+        }
+        returnstr = sdf.format(timestamp);
+        return returnstr;
+    }
+
+    /**
+     * Date 转为 String形式输出
+     *
+     * @param date
+     * @param dfm
+     * @return String
+     * @category 转字符串的时候如果传入的参数dformat为null,则默认以yyyy-MM-dd
+     *           HH:mm:ss格式转换。否则按传入格式转。
+     */
+    public static String date2Str(Date date, String dfm) {
+        if (dfm == null) {
+            sdf.applyPattern(DATE_SECOND_FMT);
+        } else {
+            sdf.applyPattern(dfm);
+        }
+        String returnstr = sdf.format(date);
+        return returnstr;
+    }
+
+    /**
+     * 获取今天是周几,也就是一星期中的第几天。
+     *
+     * @return int
+     */
+    public static int getWeek() {
+
+        Calendar calendar = Calendar.getInstance(locale);
+        int dayofweek = calendar.get(Calendar.DAY_OF_WEEK);
+
+        dayofweek = (dayofweek == 1) ? 7 : (dayofweek - 1);
+        return dayofweek;
+    }
+
+    /**
+     * 获取今天是一年中的第几周。从年初开始算。
+     *
+     * @return int
+     */
+    public static int getWeekofYear() {
+        Calendar c = Calendar.getInstance(locale);
+        c.setTime(new Date());
+
+        int returnint = c.get(Calendar.WEEK_OF_YEAR);
+        return returnint;
+    }
+
+    /**
+     * 获取年份
+     *
+     * @return int
+     */
+
+    public static int getYear() {
+        Calendar c = Calendar.getInstance(locale);
+        c.setTime(new Date());
+        int returnint = c.get(Calendar.YEAR);
+        return returnint;
+    }
+
+    /**
+     * 获取月份
+     *
+     * @return int
+     */
+    public static int getMonth() {
+        Calendar c = Calendar.getInstance(locale);
+
+        c.setTime(new Date());
+
+        int returnint = c.get(Calendar.MONTH) + 1;
+        return returnint;
+    }
+
+    /**
+     * 字符串转Date
+     * @param date
+     * @param fmt
+     * @return
+     */
+    public static Date str2Date(String date, String fmt) {
+
+        if (fmt == null) {
+            sdf.applyPattern(DATE_SECOND_FMT);
+        } else {
+            sdf.applyPattern(fmt);
+        }
+        try {
+            return sdf.parse(date);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 获取当前季度
+     * @return
+     */
+    public static Integer getQuarter() {
+        Calendar calendar = Calendar.getInstance(locale);
+        int month = calendar.get(Calendar.MONDAY) + 1;
+
+        if (month == 1 || month == 2 || month == 3) {
+            return 1;
+        }
+        if (month == 4 || month == 5 || month == 6) {
+            return 2;
+        }
+        if (month == 7 || month == 8 || month == 9) {
+            return 3;
+        }
+        return 4;
+    }
+
+    public static Date getFirstDayOfMonth(){
+        Calendar calendar = Calendar.getInstance(locale);
+        calendar.add(Calendar.MONTH, 0);
+        calendar.set(Calendar.DAY_OF_MONTH,1);//设置为1号,当前日期既为本月第一天
+
+        return calendar.getTime();
+    }
+
+    public static Date getFirstDay(int year,int month){
+        Calendar calendar = Calendar.getInstance(locale);
+        calendar.set(Calendar.YEAR,year);
+        calendar.set(Calendar.MONTH, month - 1);
+        calendar.set(Calendar.DAY_OF_MONTH,1);//设置为1号,当前日期既为本月第一天
+
+        return calendar.getTime();
+    }
+
+    public static Date getLastDay(int year,int month){
+        Calendar calendar = Calendar.getInstance(locale);
+        calendar.set(Calendar.YEAR,year);
+        calendar.set(Calendar.MONTH,month);
+        calendar.set(Calendar.DAY_OF_MONTH, 1);
+        calendar.add(Calendar.DAY_OF_MONTH, -1);
+        return calendar.getTime();
+    }
+
+    /**
+     * 获取上周周一的日期
+     * @return
+     */
+    public static Date getPreviouFirstWeek(){
+        Calendar calendar = Calendar.getInstance(locale);
+        calendar.setFirstDayOfWeek(Calendar.MONDAY);
+        calendar.set(Calendar.DAY_OF_WEEK,  Calendar.MONDAY);
+        calendar.add(Calendar.DAY_OF_WEEK, -7);
+        return calendar.getTime();
+    }
+
+    /**
+     * 获取本周周一的日期
+     * @return
+     */
+    public static Date getFirstOfWeek(){
+        Calendar calendar = Calendar.getInstance(locale);
+        calendar.setFirstDayOfWeek(Calendar.MONDAY);
+        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
+        return calendar.getTime();
+    }
+
+    /**
+     * 获取今天的日期
+     * @return
+     */
+    public static Date getToDay(){
+        return Calendar.getInstance(locale).getTime();
+    }
+
+
+    /**
+     * 当前季度的开始时间,即2012-01-1 00:00:00
+     *
+     * @return
+     */
+    public static   Date getCurrentQuarterStartTime() {
+        Calendar c = Calendar.getInstance();
+        int currentMonth = c.get(Calendar.MONTH) + 1;
+        try {
+            if (currentMonth >= 1 && currentMonth <= 3)
+                c.set(Calendar.MONTH, 0);
+            else if (currentMonth >= 4 && currentMonth <= 6)
+                c.set(Calendar.MONTH, 3);
+            else if (currentMonth >= 7 && currentMonth <= 9)
+                c.set(Calendar.MONTH, 4);
+            else if (currentMonth >= 10 && currentMonth <= 12)
+                c.set(Calendar.MONTH, 9);
+            c.set(Calendar.DATE, 1);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return c.getTime();
+    }
+
+
+    public static Date getPreviouQuarterStartTime() {
+        Calendar c = Calendar.getInstance();
+        int currentMonth = c.get(Calendar.MONTH) + 1;
+        try {
+            if (currentMonth >= 1 && currentMonth <= 3){
+                c.set(Calendar.MONTH, 9);
+                c.add(Calendar.YEAR,-1);
+            }else if (currentMonth >= 4 && currentMonth <= 6)
+                c.set(Calendar.MONTH, 0);
+            else if (currentMonth >= 7 && currentMonth <= 9)
+                c.set(Calendar.MONTH, 3);
+            else if (currentMonth >= 10 && currentMonth <= 12)
+                c.set(Calendar.MONTH, 6);
+            c.set(Calendar.DATE, 1);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return c.getTime();
+    }
+    //获得当天24点时间
+    public static Date getTimesnight(){
+        Calendar cal = Calendar.getInstance();
+        cal.set(Calendar.HOUR_OF_DAY, 24);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MINUTE, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        return new Date(cal.getTime().getTime() - DAY_MILLISECOND);
+    }
+
+
+    public static void main(String[] args) {
+
+        int month = 2;
+        int year = 2015;
+        System.out.println(date2Str(getFirstDayOfMonth(),DATE_DAY_FMT));
+        System.out.println(date2Str(getFirstDay(year, month),DATE_DAY_FMT));
+
+        System.out.println(date2Str(getLastDay(year, month),DATE_DAY_FMT));
+        System.out.println(getYear());
+        System.out.println(getMonth());
+        System.out.println("昨天:" + date2Str(new Date(getToDay().getTime() - DAY_MILLISECOND), DATE_DAY_FMT) + " - "+date2Str(new Date(getToDay().getTime()), DATE_DAY_FMT));
+        System.out.println("天:" + date2Str(getToDay(), DATE_DAY_FMT) + " - "+date2Str(new Date(getToDay().getTime()+DAY_MILLISECOND), DATE_DAY_FMT));
+        System.out.println("周:"+date2Str(getFirstOfWeek(),DATE_DAY_FMT) + " - " + date2Str(new Date(getToDay().getTime()+DAY_MILLISECOND),DATE_DAY_FMT));
+        System.out.println("上周:"+date2Str(getPreviouFirstWeek(),DATE_DAY_FMT) + " - " + date2Str(getFirstOfWeek(),DATE_DAY_FMT));
+        System.out.println("本季度:"+date2Str(getCurrentQuarterStartTime(),DATE_DAY_FMT));
+        System.out.println("上季度:"+date2Str(getPreviouQuarterStartTime(),DATE_DAY_FMT));
+
+        System.out.println(date2Str(str2Date("2014-02","yyyy-MM"),DATE_DAY_FMT));
+        String deptid = "001005002001";
+        System.out.println(deptid.substring(0,6));
+        System.out.println(date2Str(getTimesnight(), DATE_SECOND_FMT));
+        System.out.println(date2Str(new Date(),DATE_SECOND_FMT));
+        System.out.println(new Date().getTime() > getTimesnight().getTime());
+    }
+}

+ 46 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/GsonUtil.java

@@ -0,0 +1,46 @@
+package com.jsjty.util;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+
+/**
+ * Created by myhnuhai on 2014/9/5.
+ */
+public class GsonUtil {
+    private final  static Gson bean2Gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
+    private final static Gson gson2Bean = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
+
+    /**Object转String
+     *
+     * @param obj 对象
+     * @return java.lang.String
+     */
+    public static String bean2gson(Object obj){
+
+        return bean2Gson.toJson(obj);
+    }
+
+    /**
+     * String转Object
+     * @param gson
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    public static <T> T gson2Bean(String gson,Class<T> clazz){
+        return gson2Bean.fromJson(gson,clazz);
+    }
+
+    /**
+     * String 转复杂对象
+     * @param gson
+     * @param typeToken
+     * @param <T>
+     * @return
+     */
+    public static  <T> T gson2Bean(String gson,TypeToken<T> typeToken){
+
+        return gson2Bean.fromJson(gson, typeToken.getType());
+    }
+}

+ 44 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/HttpMain.java

@@ -0,0 +1,44 @@
+package com.jsjty.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class HttpMain extends HttpProxy {
+
+    public String air_url = "http://bma.data.fr24.com/zones/fcgi/feed.js"; // 请求航班信息数据
+    public String basic_url = "http://218.2.208.140:8091/JSWeb/searchpoi";// 请求基础数据参考basicType
+    public String event_url = "http://218.2.208.140:8091/JSWeb/servlet/custService";// 事件数据查询
+
+    public String tianyan_url = "http://tianyan.baidu.com/api/get_flight_detail_by_no";
+
+    public String[] title = new String[] { "编号", "纬度", "经度", "方向", "高度", "速度", "应答机编码", "雷达", "飞机型号", "注册号", "时间",
+            "起飞机场", "降落机场", "航班号", "attr1", "垂直速度", "航班号", "attr2" };
+
+    public String[] basicType = new String[] { "客运站", "火车站", "机场", "港区", "船闸", "跨江大桥", "长江汽渡", "隧道", "收费站", "服务区",
+            "加油站", "停车场", "汽修站", "检测站", "售票处", "驾校", "水上服务区" };
+
+    public String[] basicTable = new String[] { "navi_keyunzhan", "navi_rail_js", "navi_jichang", "navi_gangqu",
+            "navi_chuanzha", "navi_kjdq", "navi_cjqd", "navi_suidao", "navi_shoufeizhan", "navi_fwq",
+            "navi_jiancezhan", "navi_ssfwq" };
+
+    public String[] evenType = new String[] { "tfsjchk", "yhsgchk" }; // 突发事件,养护施工
+
+    public int pageSize = 50;
+
+    public static HttpMain httpMain = new HttpMain();
+
+    /**
+     * 获取航班信息
+     * 
+     * @param airplane
+     * @return
+     */
+    public String getAirPlane(String airplane) {
+
+        Map<String, Object> param = new HashMap<String, Object>();
+        param.put("_", new java.util.Date().getTime());
+        param.put("flight_no", airplane);
+        return http_get_json(tianyan_url, param);
+    }
+
+}

+ 216 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/HttpProxy.java

@@ -0,0 +1,216 @@
+package com.jsjty.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HTTP;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@SuppressWarnings("deprecation")
+public class HttpProxy {
+    private final static Logger logger = LoggerFactory.getLogger(HttpProxy.class);
+    private final static int TIMEOUT_CONNECTION = 20000;
+    private final static int TIMEOUT_SOCKET = 50000;
+
+    protected static String _MakeURL(String p_url, Map<String, Object> params) {
+        StringBuilder url = new StringBuilder(p_url);
+        if (url.indexOf("?") < 0) url.append('?');
+
+        if (params != null) {
+            for (String name : params.keySet()) {
+                url.append('&');
+                url.append(name);
+                url.append('=');
+                url.append(String.valueOf(params.get(name)));
+            }
+        }
+        return url.toString().replace("?&", "?");
+    }
+
+    /**
+     * get请求URL
+     *
+     * @param url
+     * @throws com.jsjty.app.AppException
+     */
+    protected static InputStream http_get_inputStream(String url) throws Exception {
+        String responseBody = http_get_json(url);
+        return new ByteArrayInputStream(responseBody.getBytes());
+    }
+
+    /**
+     * get请求URL
+     *
+     * @param url
+     * @throws com.jsjty.app.AppException
+     */
+    protected static InputStream http_get_inputStream(String url, Map<String, Object> params) throws Exception {
+        String responseBody = http_get_json(url, params);
+        return new ByteArrayInputStream(responseBody.getBytes());
+    }
+
+    /**
+     * post请求URL
+     *
+     * @param url
+     * @param params
+     * @return
+     * @throws com.jsjty.app.AppException
+     */
+    protected static InputStream http_post_inputstream(String url, Map<String, Object> params) throws Exception {
+
+        String response = http_post_json(url, params);
+        return new ByteArrayInputStream(response.getBytes());
+    }
+
+    /**
+     * get请求URL 返回Json格式数据
+     *
+     * @param path
+     * @return
+     */
+    protected static String http_get_json(String path) {
+        logger.info(path);
+        // 新建HttpGet对象
+        HttpGet httpGet = new HttpGet(path);
+        return invoke(httpGet);
+    }
+
+    private static DefaultHttpClient getHttpClient() {
+
+        HttpParams params = new BasicHttpParams();
+        HttpConnectionParams.setConnectionTimeout(params, TIMEOUT_CONNECTION); // 设置连接超时
+        HttpConnectionParams.setSoTimeout(params, TIMEOUT_SOCKET); // 设置请求超时
+        DefaultHttpClient defaultHttpClient = new DefaultHttpClient(params);
+
+        return defaultHttpClient;
+    }
+
+    protected static String http_get_json(String path, Map<String, Object> params) {
+        String urls = _MakeURL(path, params);
+        //System.out.println(urls);
+        return http_get_json(urls);
+    }
+
+    /**
+     * 公用post方法
+     *
+     * @param path
+     * @param params
+     * @return
+     */
+    protected static String http_post_json(String path, List<NameValuePair> params) {
+        try {
+            logger.info(path);
+            // 新建HttpPost对象
+            HttpPost httpPost = new HttpPost(path);
+            HttpEntity entity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
+            // 设置参数实体
+            httpPost.setEntity(entity);
+
+            return invoke(httpPost);
+        }
+        catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    protected static String http_post_json(String path, Map<String, Object> params) {
+        return http_post_json(path, postParams(params));
+    }
+
+    private static String invoke(HttpPost httppost) {
+        try {
+            // 获取HttpClient对象
+            DefaultHttpClient httpclient = getHttpClient();
+            HttpResponse response = httpclient.execute(httppost);
+            return responseParams(response);
+        }
+        catch (ClientProtocolException e) {
+            e.printStackTrace();
+            return null;
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    private static String invoke(HttpGet httpget) {
+        try {
+            // 获取HttpClient对象
+            DefaultHttpClient httpclient = getHttpClient();
+            HttpResponse response = httpclient.execute(httpget);
+            return responseParams(response);
+        }
+        catch (Exception e) {
+            System.out.println(e.getMessage());
+            return null;
+        }
+    }
+
+    private static String responseParams(HttpResponse response) {
+        // 判断是够请求成功
+        if (response.getStatusLine().getStatusCode() == 200) {
+            // 获取返回的数据
+
+            System.out.println("Response Status: " + response.getStatusLine() + "--数据请求成功");
+
+            return CustomGetMethod.getGzip(response);
+
+        }
+
+        return null;
+
+    }
+
+    private static List<NameValuePair> postParams(Map<String, Object> params) {
+        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
+        Set<String> keySet = params.keySet();
+        for (String key : keySet) {
+            nvps.add(new BasicNameValuePair(key, params.get(key).toString()));
+        }
+
+        return nvps;
+    }
+
+    protected static InputStream getNetFile(String urlStr) {
+        try {
+            URL url = new URL(urlStr);
+            URLConnection con = url.openConnection();// 打开连接
+            return con.getInputStream();// 输入流
+        }
+        catch (MalformedURLException e) {
+            e.printStackTrace();
+            return null;
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+}

+ 32 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/IpUtils.java

@@ -0,0 +1,32 @@
+package com.jsjty.util;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class IpUtils {
+    private IpUtils() {
+    }
+
+    public static String getIpAddr(HttpServletRequest request) {
+        if (request == null) {
+            return "unknown";
+        }
+        String ip = request.getHeader("x-forwarded-for");
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("X-Forwarded-For");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("X-Real-IP");
+        }
+
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+        }
+        return ip;
+    }
+}

+ 63 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/JsonUtil.java

@@ -0,0 +1,63 @@
+package com.jsjty.util;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+public class JsonUtil {
+    // for Object to json
+    private static ObjectMapper objectMapper = new ObjectMapper();
+    // for json to Object
+    private static ObjectMapper objectMapper2 = new ObjectMapper();
+
+    public static String bean2Json(Object o) {
+        StringWriter sw = new StringWriter();
+        try {
+            JsonGenerator generator = objectMapper.getJsonFactory().createJsonGenerator(sw);
+            objectMapper.writeValue(generator, o);
+            sw.close();
+            return sw.toString();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static <T> T json2Bean(String json, Class<T> cls) {
+        try {
+            objectMapper2.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+            return objectMapper2.readValue(json, cls);
+        } catch (JsonParseException e) {
+            e.printStackTrace();
+        } catch (JsonMappingException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    public static <T> T json2Bean(String json,
+                                  TypeReference<T> typeReference) {
+        try {
+            objectMapper2.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
+
+            return objectMapper2.readValue(json, typeReference);
+        } catch (JsonParseException e) {
+            e.printStackTrace();
+        } catch (JsonMappingException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+}

+ 151 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/LogUtils.java

@@ -0,0 +1,151 @@
+package com.jsjty.util;
+
+import com.alibaba.fastjson.JSON;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+public class LogUtils {
+
+    public static final Logger ERROR_LOG = LoggerFactory.getLogger("es-error");
+    public static final Logger ACCESS_LOG = LoggerFactory.getLogger("es-access");
+
+    /**
+     * 记录访问日志
+     * [username][jsessionid][ip][accept][UserAgent][url][params][Referer]
+     *
+     * @param request
+     */
+    public static void logAccess(HttpServletRequest request) {
+        String username = getUsername();
+        String jsessionId = request.getRequestedSessionId();
+        String ip = IpUtils.getIpAddr(request);
+        String accept = request.getHeader("accept");
+        String userAgent = request.getHeader("User-Agent");
+        String url = request.getRequestURI();
+        String params = getParams(request);
+        String headers = getHeaders(request);
+
+        StringBuilder s = new StringBuilder();
+        s.append(getBlock(username));
+        s.append(getBlock(jsessionId));
+        s.append(getBlock(ip));
+        s.append(getBlock(accept));
+        s.append(getBlock(userAgent));
+        s.append(getBlock(url));
+        s.append(getBlock(params));
+        s.append(getBlock(headers));
+        s.append(getBlock(request.getHeader("Referer")));
+        getAccessLog().info(s.toString());
+    }
+
+    /**
+     * 记录异常错误
+     * 格式 [exception]
+     *
+     * @param message
+     * @param e
+     */
+    public static void logError(String message, Throwable e) {
+        String username = getUsername();
+        StringBuilder s = new StringBuilder();
+        s.append(getBlock("exception"));
+        s.append(getBlock(username));
+        s.append(getBlock(message));
+        ERROR_LOG.error(s.toString(), e);
+    }
+
+    /**
+     * 记录页面错误
+     * 错误日志记录 [page/eception][username][statusCode][errorMessage][servletName][uri][exceptionName][ip][exception]
+     *
+     * @param request
+     */
+    public static void logPageError(HttpServletRequest request) {
+        String username = getUsername();
+
+        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
+        String message = (String) request.getAttribute("javax.servlet.error.message");
+        String uri = (String) request.getAttribute("javax.servlet.error.request_uri");
+        Throwable t = (Throwable) request.getAttribute("javax.servlet.error.exception");
+
+
+        if (statusCode == null) {
+            statusCode = 0;
+        }
+
+        StringBuilder s = new StringBuilder();
+        s.append(getBlock(t == null ? "page" : "exception"));
+        s.append(getBlock(username));
+        s.append(getBlock(statusCode));
+        s.append(getBlock(message));
+        s.append(getBlock(IpUtils.getIpAddr(request)));
+
+        s.append(getBlock(uri));
+        s.append(getBlock(request.getHeader("Referer")));
+        StringWriter sw = new StringWriter();
+
+        while (t != null) {
+            t.printStackTrace(new PrintWriter(sw));
+            t = t.getCause();
+        }
+        s.append(getBlock(sw.toString()));
+        getErrorLog().error(s.toString());
+
+    }
+
+
+    public static String getBlock(Object msg) {
+        if (msg == null) {
+            msg = "";
+        }
+        return "[" + msg.toString() + "]";
+    }
+
+
+
+    @SuppressWarnings("unchecked")
+    protected static String getParams(HttpServletRequest request) {
+        Map<String, String[]> params = request.getParameterMap();
+        return JSON.toJSONString(params);
+    }
+
+
+    @SuppressWarnings("unchecked")
+    private static String getHeaders(HttpServletRequest request) {
+        Map<String, List<String>> headers = Maps.newHashMap();
+        Enumeration<String> namesEnumeration = request.getHeaderNames();
+        while(namesEnumeration.hasMoreElements()) {
+            String name = namesEnumeration.nextElement();
+            Enumeration<String> valueEnumeration = request.getHeaders(name);
+            List<String> values = Lists.newArrayList();
+            while(valueEnumeration.hasMoreElements()) {
+                values.add(valueEnumeration.nextElement());
+            }
+            headers.put(name, values);
+        }
+        return JSON.toJSONString(headers);
+    }
+
+
+    protected static String getUsername() {
+        return "";
+    }
+
+    public static Logger getAccessLog() {
+        return ACCESS_LOG;
+    }
+
+    public static Logger getErrorLog() {
+        return ERROR_LOG;
+    }
+
+}

+ 40 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/MsgEnum.java

@@ -0,0 +1,40 @@
+package com.jsjty.util;
+
+/**
+ * package com.jsjty.mayh.jdc
+ * Author  Administrator
+ * Created by 2015/4/14.
+ */
+public enum MsgEnum {
+    UNLOGIN_ERROR               ("用户未登录",-1),
+    LOGIN_SUCCESS              ("用户登录成功",0),
+    USERNAME_OR_PASSWORD_ERROR  ("用户名或密码错误",1),
+    OTHER_ERROR                 ("其他错误",2),
+    NEW_ADD                     ("新增",3),
+    NEW_ADD_SUCCESS             ("新增成功",4),
+    EDIT                        ("修改",5),
+    EDIT_SUCCESS                ("修改成功",6),
+    DEL                         ("删除",7),
+    DEL_SUCCESS                 ("删除成功",8),
+    EDIT_PASSWORD               ("修改密码",9),
+    EDIT_PASSWORD_SUCCESS       ("修改密码成功",10),
+    DEVICE_UNAUTHORIZATION        ("设备未授权",11);
+
+
+    private String info;
+    private int code;
+    private MsgEnum(String info,int code) {
+        this.info = info;
+        this.code = code;
+    }
+
+    public String getInfo() {
+        return info;
+    }
+
+
+    public int getCode() {
+        return code;
+    }
+
+}

+ 29 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/NumberUtil.java

@@ -0,0 +1,29 @@
+package com.jsjty.util;
+
+import java.text.DecimalFormat;
+
+/**
+ * Created by 马英虎 on 2014/12/3.
+ */
+public class NumberUtil {
+
+
+
+    public static final String DECIMAL_1 = "#.0";
+    public static final String DECIMAL_2 = "#.00";
+    public static final String DECIMAL_3 = "#.000";
+    public static final String DECIMAL_4 = "#.0000";
+
+    private static DecimalFormat decimalFormat;
+
+    static {
+        decimalFormat = new DecimalFormat(DECIMAL_4);
+    }
+
+    public static Double format(Double num,String pattern){
+        if(pattern != null && pattern.length() > 0){
+            decimalFormat = new DecimalFormat(pattern);
+        }
+        return Double.parseDouble(decimalFormat.format(num));
+    }
+}

+ 70 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/ResourceUtil.java

@@ -0,0 +1,70 @@
+package com.jsjty.util;
+
+import java.util.ResourceBundle;
+
+/**
+ * 项目参数工具类
+ */
+public abstract class ResourceUtil {
+
+	private static final ResourceBundle bundle = ResourceBundle.getBundle("config");
+
+
+	/**
+	 * 获得sessionInfo名字
+	 * 
+	 * @return
+	 */
+	public static final String getSessionInfoName() {
+		return bundle.getString("sessionInfoName");
+	}
+
+	/**
+	 * 获得上传表单域的名称
+	 * 
+	 * @return
+	 */
+	public static final String getUploadFieldName() {
+		return bundle.getString("uploadFieldName");
+	}
+
+	/**
+	 * 获得上传文件的最大大小限制
+	 * 
+	 * @return
+	 */
+	public static final long getUploadFileMaxSize() {
+		return Long.valueOf(bundle.getString("uploadFileMaxSize"));
+	}
+
+	/**
+	 * 获得允许上传文件的扩展名
+	 * 
+	 * @return
+	 */
+	public static final String getUploadFileExts() {
+		return bundle.getString("uploadFileExts");
+	}
+
+	/**
+	 * 获得上传文件要放到那个目录
+	 * 
+	 * @return
+	 */
+	public static final String getUploadDirectory() {
+		return bundle.getString("uploadDirectory");
+	}
+
+
+    public static String get(String name){
+        return bundle.getString(name);
+    }
+
+
+    public final static String AIRWAY = "AIRWAY";             //航道报表
+    public final static String HARBOR = "HARBOR";             //港口报表
+    public final static String LARGEBRIDGE = "LARGEBRIDGE";        //独立的特大桥梁建设报表
+    public final static String HIGHWAY = "HIGHWAY";          //高速公路建设报表
+    public final static String ROUTECONNHIGHWAY = "ROUTECONNHIGHWAY";  //普通国省干线公路及连接公路项目建设基本信息填报
+
+}

+ 154 - 0
jdc/chatServer/trunk/src/main/java/com/jsjty/util/StringUtil.java

@@ -0,0 +1,154 @@
+package com.jsjty.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class StringUtil {
+
+    private final static SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss");
+
+    public static String formatDate(Date date) {
+
+        return dateformat.format(date);
+    }
+
+    public static String formatTimestamp(Timestamp timestamp) {
+
+        return dateformat.format(timestamp);
+    }
+
+    /**
+     * 获取错误日志详细信息
+     * 
+     * @param t
+     * @return String
+     */
+    public static String getTrace(Throwable t) {
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter writer = new PrintWriter(stringWriter);
+        t.printStackTrace(writer);
+        StringBuffer buffer = stringWriter.getBuffer();
+        return buffer.toString();
+    }
+
+    public static String[] str2Array(String params) {
+
+        if (params != null) { return params.split(","); }
+        return null;
+    }
+
+    /**
+     * 对文件流输出下载的中文文件名进行编码 屏蔽各种浏览器版本的差异性
+     */
+    public static String encodeChineseDownloadFileName(HttpServletRequest request, String pFileName) {
+        String agent = request.getHeader("USER-AGENT");
+        try {
+            if (null != agent && -1 != agent.indexOf("MSIE")) {
+                pFileName = URLEncoder.encode(pFileName, "utf-8");
+            }
+            else {
+                pFileName = new String(pFileName.getBytes("utf-8"), "iso8859-1");
+            }
+        }
+        catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return pFileName;
+    }
+
+    /**
+     * 判断对象是否Empty(null或元素为0)<br>
+     * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
+     *
+     * @param pObj
+     *            待检查对象
+     * @return boolean 返回的布尔值
+     */
+    @SuppressWarnings("rawtypes")
+    public static boolean isEmpty(Object pObj) {
+        if (pObj == null) return true;
+        if (pObj == "") return true;
+        if (pObj instanceof String) {
+            if (((String) pObj).length() == 0) { return true; }
+        }
+        else if (pObj instanceof Collection) {
+            if (((Collection) pObj).size() == 0) { return true; }
+        }
+        else if (pObj instanceof Map) {
+            if (((Map) pObj).size() == 0) { return true; }
+        }
+        return false;
+    }
+
+    /**
+     * 判断对象是否为NotEmpty(!null或元素>0)<br>
+     * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
+     *
+     * @param pObj
+     *            待检查对象
+     * @return boolean 返回的布尔值
+     */
+    @SuppressWarnings("rawtypes")
+    public static boolean isNotEmpty(Object pObj) {
+        if (pObj == null) return false;
+        if (pObj == "") return false;
+        if (pObj instanceof String) {
+            if (((String) pObj).length() == 0) { return false; }
+        }
+        else if (pObj instanceof Collection) {
+            if (((Collection) pObj).size() == 0) { return false; }
+        }
+        else if (pObj instanceof Map) {
+            if (((Map) pObj).size() == 0) { return false; }
+        }
+        return true;
+    }
+
+    public static String getUUID() {
+        return UUID.randomUUID().toString().replace("-", "");
+    }
+
+    public static String parseByte2HexStr(byte buf[]) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < buf.length; i++) {
+            String hex = Integer.toHexString(buf[i] & 0xFF);
+            if (hex.length() == 1) {
+                hex = '0' + hex;
+            }
+            sb.append(hex.toUpperCase());
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 把16进制字符串转换成字节数组
+     * 
+     * @param hexString
+     * @return byte[]
+     */
+    public static byte[] hexStringToByte(String hex) {
+        int len = (hex.length() / 2);
+        byte[] result = new byte[len];
+        char[] achar = hex.toCharArray();
+        for (int i = 0; i < len; i++) {
+            int pos = i * 2;
+            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
+        }
+        return result;
+    }
+
+    private static int toByte(char c) {
+        byte b = (byte) "0123456789ABCDEF".indexOf(c);
+        return b;
+    }
+}

+ 29 - 0
jdc/chatServer/trunk/src/main/resources/config.properties

@@ -0,0 +1,29 @@
+connection.url=jdbc:mysql://10.21.2.224:3306/jdc?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
+connection.username=root
+connection.password=mysql
+#druid datasource
+druid.initialSize=10
+druid.minIdle=10
+druid.maxActive=50
+druid.maxWait=60000
+druid.timeBetweenEvictionRunsMillis=60000
+druid.minEvictableIdleTimeMillis=300000
+druid.validationQuery=SELECT 'x'
+druid.testWhileIdle=true
+druid.testOnBorrow=false
+druid.testOnReturn=false
+druid.poolPreparedStatements=false
+druid.maxPoolPreparedStatementPerConnectionSize=20
+druid.filters=wall,stat,config
+
+image=gif,jpg,jpeg,png,bmp
+flash=swf,flv
+media=swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb
+file=doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2
+maxFileSize=102400
+
+file.path=D:\\logs\\file
+image.path=D:\\logs\\image
+
+
+sessionInfoName=sessionInfo

+ 32 - 0
jdc/chatServer/trunk/src/main/resources/ehcache.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false"
+	monitoring="autodetect" dynamicConfig="true">
+
+	<diskStore path="java.io.tmpdir" />
+	<!-- <diskStore path="E:/cachetmpdir" /> -->
+
+	<!-- name:Cache的唯一标识 maxElementsInMemory:内存中最大缓存对象数 maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大 
+		eternal:Element是否永久有效,一但设置了,timeout将不起作用 overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中 
+		timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大 
+		timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大 
+		diskPersistent:是否缓存虚拟机重启期数据 diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒 
+		diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区 
+		memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用) -->
+
+	<defaultCache maxElementsInMemory="10000" eternal="false"
+		timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
+		maxElementsOnDisk="10000000" diskPersistent="false"
+		diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" />
+
+	<cache name="messageCache" maxElementsInMemory="10000"
+		maxElementsOnDisk="10000" eternal="true" overflowToDisk="true"
+		diskSpoolBufferSizeMB="20" timeToIdleSeconds="300" timeToLiveSeconds="600"
+		memoryStoreEvictionPolicy="LFU" />
+
+	<cache name="cipherCache" maxElementsInMemory="10000"
+		maxElementsOnDisk="10000" eternal="false" overflowToDisk="false"
+		diskSpoolBufferSizeMB="20" timeToIdleSeconds="300" timeToLiveSeconds="600"
+		memoryStoreEvictionPolicy="LFU" />
+
+</ehcache>

+ 421 - 0
jdc/chatServer/trunk/src/main/resources/ehcache.xsd

@@ -0,0 +1,421 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="1.7">
+
+    <xs:element name="ehcache">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element maxOccurs="1" minOccurs="0" ref="diskStore"/>
+                <xs:element maxOccurs="1" minOccurs="0" ref="sizeOfPolicy"/>
+                <xs:element maxOccurs="1" minOccurs="0" ref="transactionManagerLookup"/>
+                <xs:element maxOccurs="1" minOccurs="0" ref="cacheManagerEventListenerFactory"/>
+                <xs:element maxOccurs="1" minOccurs="0" ref="managementRESTService"/>
+                <xs:element maxOccurs="unbounded" minOccurs="0" ref="cacheManagerPeerProviderFactory"/>
+                <xs:element maxOccurs="unbounded" minOccurs="0" ref="cacheManagerPeerListenerFactory"/>
+                <xs:element maxOccurs="1" minOccurs="0" ref="terracottaConfig"/>
+                <xs:element maxOccurs= "1" minOccurs="0" ref="defaultCache"/>
+                <xs:element maxOccurs="unbounded" minOccurs="0" ref="cache"/>
+            </xs:sequence>
+            <xs:attribute name="name" use="optional"/>
+            <xs:attribute default="true" name="updateCheck" type="xs:boolean" use="optional"/>
+            <xs:attribute default="autodetect" name="monitoring" type="monitoringType" use="optional"/>
+            <xs:attribute default="true" name="dynamicConfig" type="xs:boolean" use="optional"/>
+            <xs:attribute default="15" name="defaultTransactionTimeoutInSeconds" type="xs:integer" use="optional"/>
+            <xs:attribute default="0" name="maxBytesLocalHeap" type="memoryUnitOrPercentage" use="optional"/>
+            <xs:attribute default="0" name="maxBytesLocalOffHeap" type="memoryUnit" use="optional"/>
+            <xs:attribute default="0" name="maxBytesLocalDisk" type="memoryUnit" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="managementRESTService">
+        <xs:complexType>
+            <xs:attribute name="enabled" type="xs:boolean" use="optional"/>
+            <xs:attribute name="bind" use="optional"/>
+            <xs:attribute name="securityServiceLocation" use="optional"/>
+            <xs:attribute name="securityServiceTimeout" use="optional" type="xs:integer"/>
+            <xs:attribute name="sslEnabled" use="optional" type="xs:boolean"/>
+            <xs:attribute name="needClientAuth" use="optional" type="xs:boolean"/>
+            <xs:attribute name="sampleHistorySize" use="optional" type="xs:integer"/>
+            <xs:attribute name="sampleIntervalSeconds" use="optional" type="xs:integer"/>
+            <xs:attribute name="sampleSearchIntervalSeconds" use="optional" type="xs:integer"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="diskStore">
+        <xs:complexType>
+            <xs:attribute name="path" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="transactionManagerLookup">
+        <xs:complexType>
+            <xs:attribute name="class" use="required"/>
+            <xs:attribute name="properties" use="optional"/>
+            <xs:attribute name="propertySeparator" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="cacheManagerEventListenerFactory">
+        <xs:complexType>
+            <xs:attribute name="class" use="required"/>
+            <xs:attribute name="properties" use="optional"/>
+            <xs:attribute name="propertySeparator" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="cacheManagerPeerProviderFactory">
+        <xs:complexType>
+            <xs:attribute name="class" use="required"/>
+            <xs:attribute name="properties" use="optional"/>
+            <xs:attribute name="propertySeparator" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="cacheManagerPeerListenerFactory">
+        <xs:complexType>
+            <xs:attribute name="class" use="required"/>
+            <xs:attribute name="properties" use="optional"/>
+            <xs:attribute name="propertySeparator" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="terracottaConfig">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element maxOccurs="1" minOccurs="0" name="tc-config">
+                    <xs:complexType>
+                        <xs:sequence>
+                            <xs:any maxOccurs="unbounded" minOccurs="0" processContents="skip"/>
+                        </xs:sequence>
+                    </xs:complexType>
+                </xs:element>
+            </xs:sequence>
+            <xs:attribute default="localhost:9510" name="url" use="optional"/>
+            <xs:attribute name="rejoin" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="wanEnabledTSA" type="xs:boolean" use="optional" default="false"/>
+        </xs:complexType>
+    </xs:element>
+    <!-- add clone support for addition of cacheExceptionHandler. Important! -->
+    <xs:element name="defaultCache">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
+                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
+                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
+                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheDecoratorFactory"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="pinning"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriter"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="copyStrategy"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="elementValueComparator"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="sizeOfPolicy"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="persistence"/>
+            </xs:sequence>
+            <xs:attribute name="diskExpiryThreadIntervalSeconds" type="xs:integer" use="optional"/>
+            <xs:attribute name="diskSpoolBufferSizeMB" type="xs:integer" use="optional"/>
+            <xs:attribute name="diskPersistent" type="xs:boolean" use="optional"/>
+            <xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
+            <xs:attribute name="eternal" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="maxElementsInMemory" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="maxEntriesLocalHeap" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="clearOnFlush" type="xs:boolean" use="optional"/>
+            <xs:attribute name="memoryStoreEvictionPolicy" type="xs:string" use="optional"/>
+            <xs:attribute name="overflowToDisk" type="xs:boolean" use="optional"/>
+            <xs:attribute name="timeToIdleSeconds" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="timeToLiveSeconds" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="maxElementsOnDisk" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="maxEntriesLocalDisk" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="transactionalMode" type="transactionalMode" use="optional" default="off"/>
+            <xs:attribute name="statistics" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="copyOnRead" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="copyOnWrite" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="cacheLoaderTimeoutMillis" type="xs:integer" use="optional" default="0"/>
+            <xs:attribute name="overflowToOffHeap" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="maxMemoryOffHeap" type="xs:string" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="cache">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
+                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
+                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
+                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheDecoratorFactory"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="pinning"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriter"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="copyStrategy"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="searchable"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="elementValueComparator"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="sizeOfPolicy"/>
+                <xs:element minOccurs="0" maxOccurs="1" ref="persistence"/>
+            </xs:sequence>
+            <xs:attribute name="diskExpiryThreadIntervalSeconds" type="xs:integer" use="optional"/>
+            <xs:attribute name="diskSpoolBufferSizeMB" type="xs:integer" use="optional"/>
+            <xs:attribute name="diskPersistent" type="xs:boolean" use="optional"/>
+            <xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
+            <xs:attribute name="eternal" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="maxElementsInMemory" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="maxEntriesLocalHeap" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="memoryStoreEvictionPolicy" type="xs:string" use="optional"/>
+            <xs:attribute name="clearOnFlush" type="xs:boolean" use="optional"/>
+            <xs:attribute name="name" type="xs:string" use="required"/>
+            <xs:attribute name="overflowToDisk" type="xs:boolean" use="optional"/>
+            <xs:attribute name="timeToIdleSeconds" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="timeToLiveSeconds" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="maxElementsOnDisk" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="maxEntriesLocalDisk" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="maxEntriesInCache" type="xs:nonNegativeInteger" use="optional"/>
+            <xs:attribute name="transactionalMode" type="transactionalMode" use="optional" default="off" />
+            <xs:attribute name="statistics" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="copyOnRead" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="copyOnWrite" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="logging" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="cacheLoaderTimeoutMillis" type="xs:integer" use="optional" default="0"/>
+            <xs:attribute name="overflowToOffHeap" type="xs:boolean" use="optional" default="false"/>
+            <xs:attribute name="maxMemoryOffHeap" type="xs:string" use="optional"/>
+            <xs:attribute default="0" name="maxBytesLocalHeap" type="memoryUnitOrPercentage" use="optional"/>
+            <xs:attribute default="0" name="maxBytesLocalOffHeap" type="memoryUnitOrPercentage" use="optional"/>
+            <xs:attribute default="0" name="maxBytesLocalDisk" type="memoryUnitOrPercentage" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="cacheEventListenerFactory">
+        <xs:complexType>
+            <xs:attribute name="class" use="required"/>
+            <xs:attribute name="properties" use="optional"/>
+            <xs:attribute name="propertySeparator" use="optional"/>
+            <xs:attribute name="listenFor" use="optional" type="notificationScope" default="all"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="bootstrapCacheLoaderFactory">
+        <xs:complexType>
+            <xs:attribute name="class" use="required"/>
+            <xs:attribute name="properties" use="optional"/>
+            <xs:attribute name="propertySeparator" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="cacheExtensionFactory">
+        <xs:complexType>
+            <xs:attribute name="class" use="required"/>
+            <xs:attribute name="properties" use="optional"/>
+            <xs:attribute name="propertySeparator" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="cacheExceptionHandlerFactory">
+        <xs:complexType>
+            <xs:attribute name="class" use="required"/>
+            <xs:attribute name="properties" use="optional"/>
+            <xs:attribute name="propertySeparator" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="cacheLoaderFactory">
+        <xs:complexType>
+            <xs:attribute name="class" use="required"/>
+            <xs:attribute name="properties" use="optional"/>
+            <xs:attribute name="propertySeparator" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="cacheDecoratorFactory">
+        <xs:complexType>
+            <xs:attribute name="class" use="required"/>
+            <xs:attribute name="properties" use="optional"/>
+            <xs:attribute name="propertySeparator" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="searchAttribute">
+        <xs:complexType>
+        	<xs:attribute name="name" use="required" type="xs:string" />
+        	<xs:attribute name="expression" type="xs:string" />
+        	<xs:attribute name="class" type="xs:string" />
+        	<xs:attribute name="type" type="xs:string" use="optional"/>
+        	<xs:attribute name="properties" use="optional" />
+        	<xs:attribute name="propertySeparator" use="optional" />
+        </xs:complexType>
+    </xs:element>
+
+    <xs:element name="searchable">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element minOccurs="0" maxOccurs="unbounded" ref="searchAttribute"/>
+        </xs:sequence>
+        <xs:attribute name="keys" use="optional" type="xs:boolean" default="true"/>
+        <xs:attribute name="values" use="optional" type="xs:boolean" default="true"/>
+      </xs:complexType>
+    </xs:element>
+
+    <xs:element name="pinning">
+        <xs:complexType>
+            <xs:attribute name="store" use="required" type="pinningStoreType"/>
+        </xs:complexType>
+    </xs:element>
+
+    <xs:element name="terracotta">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element minOccurs="0" maxOccurs="1" ref="nonstop"/>
+            </xs:sequence>
+            <xs:attribute name="clustered" use="optional" type="xs:boolean" default="true"/>
+            <xs:attribute name="coherentReads" use="optional" type="xs:boolean" default="true"/>
+            <xs:attribute name="localKeyCache" use="optional" type="xs:boolean" default="false"/>
+            <xs:attribute name="localKeyCacheSize" use="optional" type="xs:positiveInteger" default="300000"/>
+            <xs:attribute name="orphanEviction" use="optional" type="xs:boolean" default="true"/>
+            <xs:attribute name="orphanEvictionPeriod" use="optional" type="xs:positiveInteger" default="4"/>
+            <xs:attribute name="copyOnRead" use="optional" type="xs:boolean" default="false"/>
+            <xs:attribute name="coherent" use="optional" type="xs:boolean" default="false"/>
+            <xs:attribute name="consistency" use="optional" type="consistencyType" default="eventual"/>
+            <xs:attribute name="synchronousWrites" use="optional" type="xs:boolean" default="false"/>
+            <xs:attribute name="concurrency" use="optional" type="xs:nonNegativeInteger" default="0"/>
+            <xs:attribute name="localCacheEnabled" use="optional" type="xs:boolean" default="true"/>
+            <xs:attribute name="compressionEnabled" use="optional" type="xs:boolean" default="false"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:simpleType name="consistencyType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="strong" />
+            <xs:enumeration value="eventual" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="nonstop">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element minOccurs="0" maxOccurs="1" ref="timeoutBehavior"/>
+            </xs:sequence>
+            <xs:attribute name="enabled" use="optional" type="xs:boolean" default="true"/>
+            <xs:attribute name="immediateTimeout" use="optional" type="xs:boolean" default="false"/>
+            <xs:attribute name="timeoutMillis" use="optional" type="xs:positiveInteger" default="30000"/>
+            <xs:attribute name="searchTimeoutMillis" use="optional" type="xs:positiveInteger" default="30000"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="timeoutBehavior">
+        <xs:complexType>
+            <xs:attribute name="type" use="optional" type="timeoutBehaviorType" default="exception"/>
+            <xs:attribute name="properties" use="optional" default=""/>
+            <xs:attribute name="propertySeparator" use="optional" default=","/>
+        </xs:complexType>
+    </xs:element>
+    <xs:simpleType name="timeoutBehaviorType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="noop" />
+            <xs:enumeration value="exception" />
+            <xs:enumeration value="localReads" />
+            <xs:enumeration value="localReadsAndExceptionOnWrite" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="monitoringType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="autodetect"/>
+            <xs:enumeration value="on"/>
+            <xs:enumeration value="off"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="pinningStoreType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="localMemory" />
+            <xs:enumeration value="inCache" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="terracottaCacheValueType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="serialization" />
+            <xs:enumeration value="identity" />
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="transactionalMode">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="off"/>
+            <xs:enumeration value="xa_strict"/>
+            <xs:enumeration value="xa"/>
+            <xs:enumeration value="local"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:element name="cacheWriter">
+        <xs:complexType>
+            <xs:sequence >
+                <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriterFactory"/>
+            </xs:sequence>
+            <xs:attribute name="writeMode" use="optional" type="writeModeType" default="write-through"/>
+            <xs:attribute name="notifyListenersOnException" use="optional" type="xs:boolean" default="false"/>
+            <xs:attribute name="minWriteDelay" use="optional" type="xs:nonNegativeInteger" default="1"/>
+            <xs:attribute name="maxWriteDelay" use="optional" type="xs:nonNegativeInteger" default="1"/>
+            <xs:attribute name="rateLimitPerSecond" use="optional" type="xs:nonNegativeInteger" default="0"/>
+            <xs:attribute name="writeCoalescing" use="optional" type="xs:boolean" default="false"/>
+            <xs:attribute name="writeBatching" use="optional" type="xs:boolean" default="false"/>
+            <xs:attribute name="writeBatchSize" use="optional" type="xs:positiveInteger" default="1"/>
+            <xs:attribute name="retryAttempts" use="optional" type="xs:nonNegativeInteger" default="0"/>
+            <xs:attribute name="retryAttemptDelaySeconds" use="optional" type="xs:nonNegativeInteger" default="1"/>
+            <xs:attribute name="writeBehindConcurrency" use="optional" type="xs:nonNegativeInteger" default="1"/>
+            <xs:attribute name="writeBehindMaxQueueSize" use="optional" type="xs:nonNegativeInteger" default="0"/>
+        </xs:complexType>
+    </xs:element>
+    <xs:simpleType name="writeModeType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="write-through" />
+            <xs:enumeration value="write-behind" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="cacheWriterFactory">
+        <xs:complexType>
+            <xs:attribute name="class" use="required"/>
+            <xs:attribute name="properties" use="optional"/>
+            <xs:attribute name="propertySeparator" use="optional"/>
+        </xs:complexType>
+    </xs:element>
+
+    <xs:element name="copyStrategy">
+        <xs:complexType>
+            <xs:attribute name="class" use="required" type="xs:string" />
+        </xs:complexType>
+    </xs:element>
+
+    <xs:element name="elementValueComparator">
+        <xs:complexType>
+            <xs:attribute name="class" use="required" type="xs:string" />
+        </xs:complexType>
+    </xs:element>
+
+    <xs:element name="sizeOfPolicy">
+        <xs:complexType>
+            <xs:attribute name="maxDepth" use="required" type="xs:integer" />
+            <xs:attribute name="maxDepthExceededBehavior" use="optional" default="continue" type="maxDepthExceededBehavior" />
+        </xs:complexType>
+    </xs:element>
+
+	<xs:element name="persistence">
+	    <xs:complexType>
+            <xs:attribute name="strategy" use="required" type="persistenceStrategy"/>
+            <xs:attribute name="synchronousWrites" use="optional" default="false" type="xs:boolean"/>
+	    </xs:complexType>
+	</xs:element>
+	
+	<xs:simpleType name="persistenceStrategy">
+	    <xs:restriction base="xs:string">
+	        <xs:enumeration value="localTempSwap"/>
+	        <xs:enumeration value="localRestartable"/>
+	        <xs:enumeration value="none"/>
+	        <xs:enumeration value="distributed"/>
+	    </xs:restriction>
+	</xs:simpleType>
+	
+    <xs:simpleType name="maxDepthExceededBehavior">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="continue"/>
+            <xs:enumeration value="abort"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="notificationScope">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="local"/>
+            <xs:enumeration value="remote"/>
+            <xs:enumeration value="all"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="memoryUnit">
+        <xs:restriction base="xs:token">
+            <xs:pattern value="[0-9]+[bBkKmMgG]?"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="memoryUnitOrPercentage">
+        <xs:restriction base="xs:token">
+            <xs:pattern value="([0-9]+[bBkKmMgG]?|100%|[0-9]{1,2}%)"/>
+        </xs:restriction>
+    </xs:simpleType>
+</xs:schema>

+ 166 - 0
jdc/chatServer/trunk/src/main/resources/log4j.dtd

@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- Authors: Chris Taylor, Ceki Gulcu. -->
+
+<!-- Version: 1.2 -->
+
+<!-- A configuration element consists of optional renderer
+elements,appender elements, categories and an optional root
+element. -->
+
+<!ELEMENT log4j:configuration (renderer*, appender*,(category|logger)*,root?,
+                               categoryFactory?)>
+
+<!-- The "threshold" attribute takes a level value such that all -->
+<!-- logging statements with a level equal or below this value are -->
+<!-- disabled. -->
+
+<!-- Setting the "debug" enable the printing of internal log4j logging   -->
+<!-- statements.                                                         -->
+
+<!-- By default, debug attribute is "null", meaning that we not do touch -->
+<!-- internal log4j logging settings. The "null" value for the threshold -->
+<!-- attribute can be misleading. The threshold field of a repository	 -->
+<!-- cannot be set to null. The "null" value for the threshold attribute -->
+<!-- simply means don't touch the threshold field, the threshold field   --> 
+<!-- keeps its old value.                                                -->
+     
+<!ATTLIST log4j:configuration
+  xmlns:log4j              CDATA #FIXED "http://jakarta.apache.org/log4j/" 
+  threshold                (all|debug|info|warn|error|fatal|off|null) "null"
+  debug                    (true|false|null)  "null"
+>
+
+<!-- renderer elements allow the user to customize the conversion of  -->
+<!-- message objects to String.                                       -->
+
+<!ELEMENT renderer EMPTY>
+<!ATTLIST renderer
+  renderedClass  CDATA #REQUIRED
+  renderingClass CDATA #REQUIRED
+>
+
+<!-- Appenders must have a name and a class. -->
+<!-- Appenders may contain an error handler, a layout, optional parameters -->
+<!-- and filters. They may also reference (or include) other appenders. -->
+<!ELEMENT appender (errorHandler?, param*, layout?, filter*, appender-ref*)>
+<!ATTLIST appender
+  name 		ID 	#REQUIRED
+  class 	CDATA	#REQUIRED
+>
+
+<!ELEMENT layout (param*)>
+<!ATTLIST layout
+  class		CDATA	#REQUIRED
+>
+
+<!ELEMENT filter (param*)>
+<!ATTLIST filter
+  class		CDATA	#REQUIRED
+>
+
+<!-- ErrorHandlers can be of any class. They can admit any number of -->
+<!-- parameters. -->
+
+<!ELEMENT errorHandler (param*, root-ref?, logger-ref*,  appender-ref?)> 
+<!ATTLIST errorHandler
+   class        CDATA   #REQUIRED 
+>
+
+<!ELEMENT root-ref EMPTY>
+
+<!ELEMENT logger-ref EMPTY>
+<!ATTLIST logger-ref
+  ref IDREF #REQUIRED
+>
+
+<!ELEMENT param EMPTY>
+<!ATTLIST param
+  name		CDATA   #REQUIRED
+  value		CDATA	#REQUIRED
+>
+
+
+<!-- The priority class is org.apache.log4j.Level by default -->
+<!ELEMENT priority (param*)>
+<!ATTLIST priority
+  class   CDATA	#IMPLIED
+  value	  CDATA #REQUIRED
+>
+
+<!-- The level class is org.apache.log4j.Level by default -->
+<!ELEMENT level (param*)>
+<!ATTLIST level
+  class   CDATA	#IMPLIED
+  value	  CDATA #REQUIRED
+>
+
+
+<!-- If no level element is specified, then the configurator MUST not -->
+<!-- touch the level of the named category. -->
+<!ELEMENT category (param*,(priority|level)?,appender-ref*)>
+<!ATTLIST category
+  class         CDATA   #IMPLIED
+  name		CDATA	#REQUIRED
+  additivity	(true|false) "true"  
+>
+
+<!-- If no level element is specified, then the configurator MUST not -->
+<!-- touch the level of the named logger. -->
+<!ELEMENT logger (level?,appender-ref*)>
+<!ATTLIST logger
+  name		ID	#REQUIRED
+  additivity	(true|false) "true"  
+>
+
+
+<!ELEMENT categoryFactory (param*)>
+<!ATTLIST categoryFactory 
+   class        CDATA #REQUIRED>
+
+<!ELEMENT appender-ref EMPTY>
+<!ATTLIST appender-ref
+  ref IDREF #REQUIRED
+>
+
+<!-- If no priority element is specified, then the configurator MUST not -->
+<!-- touch the priority of root. -->
+<!-- The root category always exists and cannot be subclassed. -->
+<!ELEMENT root (param*, (priority|level)?, appender-ref*)>
+
+
+<!-- ==================================================================== -->
+<!--                       A logging event                                -->
+<!-- ==================================================================== -->
+<!ELEMENT log4j:eventSet (log4j:event*)>
+<!ATTLIST log4j:eventSet
+  xmlns:log4j             CDATA #FIXED "http://jakarta.apache.org/log4j/" 
+  version                (1.1|1.2) "1.2" 
+  includesLocationInfo   (true|false) "true"
+>
+
+
+
+<!ELEMENT log4j:event (log4j:message, log4j:NDC?, log4j:throwable?, 
+                       log4j:locationInfo?) >
+
+<!-- The timestamp format is application dependent. -->
+<!ATTLIST log4j:event
+    logger     CDATA #REQUIRED
+    level      CDATA #REQUIRED
+    thread     CDATA #REQUIRED
+    timestamp  CDATA #REQUIRED
+>
+
+<!ELEMENT log4j:message (#PCDATA)>
+<!ELEMENT log4j:NDC (#PCDATA)>
+
+<!ELEMENT log4j:throwable (#PCDATA)>
+
+<!ELEMENT log4j:locationInfo EMPTY>
+<!ATTLIST log4j:locationInfo
+  class  CDATA	#REQUIRED
+  method CDATA	#REQUIRED
+  file   CDATA	#REQUIRED
+  line   CDATA	#REQUIRED
+>

+ 139 - 0
jdc/chatServer/trunk/src/main/resources/log4j.xml

@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?> 
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
+
+	<!-- org.apache.log4j.ConsoleAppender (输出到控制台) -->
+	<!-- org.apache.log4j.FileAppender (输出到文件) -->
+	<!-- org.apache.log4j.DailyRollingFileAppender (每天输出产生一个日志文件) -->
+	<!-- org.apache.log4j.RollingFileAppender (文件大小到达指定尺寸的时候产生一个新的文件), 可通过 log4j.appender.R.MaxFileSize=100KB 
+		设置文件大小, 还可通过 log4j.appender.R.MaxBackupIndex=1设置为保存一个备份文件。 -->
+	<!-- org.apache.log4j.WriterAppender (将日志信息以流格式发送到任意指定的地方) -->
+
+	<!--输出通道"STDOUT",输出所有信息到控制台 (也就是System.out.println()) -->
+	<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
+		<!-- 输出自定义内容的LOG -->
+		<layout class="org.apache.log4j.PatternLayout">
+			<!-- 输出时Log内容的具体定义 -->
+			<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss,SSS}][%c] %-5p %m%n" />
+		</layout>
+	</appender>
+
+	<!--输出通道"DEBUG",输出方式是:只输出DEBUG级别的LOG,并文件大小到达指定大小时产 生新的Log文件 -->
+	<appender name="DEBUG" class="org.apache.log4j.RollingFileAppender">
+		<!-- 输出Log文件的路径和文件名 -->
+		<param name="File" value="${webapp.root}/logs/app_debug.log" />
+
+		<!-- TOMCAT等WEB服务器重新启动时,是否插入到原有的LOG文件里,true 插入false 新 建 -->
+		<param name="Append" value="true" />
+
+		<!-- 只输出定义的级别以上的LOG,因为在下面过滤LOG信息所以屏蔽 -->
+		<!-- param name="Threshold" value="info"/ -->
+
+		<!-- 因选择了RollingFileAppender了才有下面两个 MaxFileSize,MaxBackupIndex 选项 -->
+		<!-- MaxFileSize是一个LOG文件的最大的文件大小,当LOG文件超过这个值时,自动转成 *.log.1的LOG文件 -->
+		<param name="MaxFileSize" value="5000KB" />
+
+		<!-- MaxBackupIndex生成自动转成 *.log.1的LOG文件的个数,设置3时最多生成3个LOG 备份文件,它们是[*.log.1][*.log.2][*.log.3] -->
+		<param name="MaxBackupIndex" value="3" />
+
+		<!-- 输出时Log内容的具体定义 -->
+		<layout class="org.apache.log4j.PatternLayout">
+			<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss,SSS}][%-20c{1}] %-5p %m%n" />
+		</layout>
+
+		<!-- 过滤输出时Log内容,在这里,LevelMin,LevelMax都定义了DEBUG, 所以只输出DEBUG 级别LOG的数据 -->
+		<filter class="org.apache.log4j.varia.LevelRangeFilter">
+			<param name="LevelMin" value="DEBUG" />
+			<param name="LevelMax" value="DEBUG" />
+		</filter>
+	</appender>
+
+	<!-- 输出通道"INFO",输出方式是:只输出INFO级别的LOG,并文件大小到达指定大小时产生 新的Log文件 -->
+	<appender name="INFO" class="org.apache.log4j.RollingFileAppender">
+		<param name="File" value="${webapp.root}/logs/app_info.log" />
+		<param name="Append" value="true" />
+		<param name="MaxFileSize" value="5000KB" />
+		<param name="MaxBackupIndex" value="3" />
+		<layout class="org.apache.log4j.PatternLayout">
+			<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss,SSS}][%-20c{1}] %-5p %m%n" />
+		</layout>
+		<filter class="org.apache.log4j.varia.LevelRangeFilter">
+			<param name="LevelMin" value="INFO" />
+			<param name="LevelMax" value="INFO" />
+		</filter>
+	</appender>
+
+	<!-- 输出通道"WARN",输出方式是:只输出WARN级别的LOG,并文件大小到达指定大小时产 生新的Log文件 -->
+	<appender name="WARN" class="org.apache.log4j.RollingFileAppender">
+		<param name="File" value="${webapp.root}/logs/app_warn.log" />
+		<param name="Append" value="true" />
+		<param name="MaxFileSize" value="5000KB" />
+		<param name="MaxBackupIndex" value="3" />
+		<layout class="org.apache.log4j.PatternLayout">
+			<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss,SSS}][%-20c{1}] %-5p %m%n" />
+		</layout>
+		<filter class="org.apache.log4j.varia.LevelRangeFilter">
+			<param name="LevelMin" value="WARN" />
+			<param name="LevelMax" value="WARN" />
+		</filter>
+	</appender>
+
+	<!-- 输出通道"ERROR",输出方式是:只输出ERROR级别的LOG,并文件大小到达指定大小时 产生新的Log文件 -->
+	<appender name="ERROR" class="org.apache.log4j.RollingFileAppender">
+		<param name="File" value="${webapp.root}/logs/app_error.log" />
+		<param name="Append" value="true" />
+		<param name="MaxFileSize" value="5000KB" />
+		<param name="MaxBackupIndex" value="3" />
+		<layout class="org.apache.log4j.PatternLayout">
+			<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss,SSS}][%-20c{1}] %-5p %m%n" />
+		</layout>
+		<filter class="org.apache.log4j.varia.LevelRangeFilter">
+			<param name="LevelMin" value="ERROR" />
+			<param name="LevelMax" value="ERROR" />
+		</filter>
+	</appender>
+
+	<!-- 输出通道"FATAL",输出方式是:只输出INFO级别的LOG,并文件大小到达指定大小时产生 新的Log文件 -->
+	<appender name="FATAL" class="org.apache.log4j.RollingFileAppender">
+		<param name="File" value="${webapp.root}/logs/app_fatal.log" />
+		<param name="Append" value="true" />
+		<param name="MaxFileSize" value="5000KB" />
+		<param name="MaxBackupIndex" value="3" />
+		<layout class="org.apache.log4j.PatternLayout">
+			<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss,SSS}][%-20c{1}] %-5p %m%n" />
+		</layout>
+		<filter class="org.apache.log4j.varia.LevelRangeFilter">
+			<param name="LevelMin" value="FATAL" />
+			<param name="LevelMax" value="FATAL" />
+		</filter>
+	</appender>
+
+	<!-- 输出通道"EVERYDAY",输出方式是:输出所有级别的LOG,并每天一个日志文件 -->
+	<appender name="EVERYDAY" class="org.apache.log4j.DailyRollingFileAppender">
+		<param name="File" value="${webapp.root}/logs/app_everyday/everyday.log" />
+		<param name="Append" value="true" />
+		<!-- 以日为单位输出LOG文件,每日输出一个LOG文件 -->
+		<param name="DatePattern" value="'.'yyyy-MM-dd" />
+		<layout class="org.apache.log4j.PatternLayout">
+			<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss,SSS}][%-20c{1}] %-5p %m%n" />
+		</layout>
+		<!-- 过滤输出时Log内容,在这里,LevelMin是DEBUG,LevelMax都FATAL, 所以输出DEBUG 级别到FATAL级别的LOG数据 -->
+		<filter class="org.apache.log4j.varia.LevelRangeFilter">
+			<param name="LevelMin" value="ERROR" />
+			<param name="LevelMax" value="FATAL" />
+		</filter>
+	</appender>
+
+	<root>
+		<!-- 设置输出范围,默认只输出ERROR以上的,ERROR级别, FATAL级别的LOG -->
+		<priority value="ERROR" />
+		<!-- 上边设置的输出通道,使用的在这里定义 -->
+		<appender-ref ref="STDOUT" />
+		<appender-ref ref="DEBUG" />
+		<appender-ref ref="INFO" />
+		<appender-ref ref="WARN" />
+		<appender-ref ref="ERROR" />
+		<appender-ref ref="FATAL" />
+		<appender-ref ref="EVERYDAY" />
+	</root>
+</log4j:configuration>

+ 117 - 0
jdc/chatServer/trunk/src/main/resources/spring-context.xml

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
+	xmlns:beans="http://www.springframework.org/schema/beans"
+	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.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">
+
+	<context:property-placeholder location="classpath:config.properties" />
+
+	<!-- 扫描注解Bean -->
+	<context:component-scan base-package="com.jsjty">
+		<context:exclude-filter type="annotation"
+			expression="org.springframework.stereotype.Controller" />
+	</context:component-scan>
+
+	<!-- 开启AOP监听 只对当前配置文件有效 -->
+	<aop:aspectj-autoproxy expose-proxy="true" />
+
+
+	<!-- 数据源 -->
+	<!--see https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_DruidDataSource%E5%8F%82%E8%80%83%E9%85%8D%E7%BD%AE -->
+	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
+		init-method="init" destroy-method="close">
+		<!-- 基本属性 url、user、password -->
+		<property name="url" value="${connection.url}" />
+		<property name="username" value="${connection.username}" />
+		<property name="password" value="${connection.password}" />
+
+		<!-- 配置初始化大小、最小、最大 -->
+		<property name="initialSize" value="${druid.initialSize}" />
+		<property name="minIdle" value="${druid.minIdle}" />
+		<property name="maxActive" value="${druid.maxActive}" />
+
+		<!-- 配置获取连接等待超时的时间 -->
+		<property name="maxWait" value="${druid.maxWait}" />
+		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
+		<property name="timeBetweenEvictionRunsMillis" value="${druid.timeBetweenEvictionRunsMillis}" />
+
+		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
+		<property name="minEvictableIdleTimeMillis" value="${druid.minEvictableIdleTimeMillis}" />
+
+		<property name="validationQuery" value="${druid.validationQuery}" />
+		<property name="testWhileIdle" value="${druid.testWhileIdle}" />
+		<property name="testOnBorrow" value="${druid.testOnBorrow}" />
+		<property name="testOnReturn" value="${druid.testOnReturn}" />
+
+		<!-- 打开PSCache,并且指定每个连接上PSCache的大小 如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。 -->
+		<property name="poolPreparedStatements" value="${druid.poolPreparedStatements}" />
+		<!-- <property name="maxPoolPreparedStatementPerConnectionSize" value="${druid.maxPoolPreparedStatementPerConnectionSize}" 
+			/> -->
+
+		<!-- 配置监控统计拦截的filters -->
+		<property name="filters" value="${druid.filters}" />
+		<!--数据库登陆密码加密后 需要添加该选项用于解密 -->
+		<!--<property name="connectionProperties" value="config.decrypt=true" /> -->
+	</bean>
+
+	<bean id="dataSourceProxy"
+		class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
+		<property name="targetDataSource" ref="dataSource" />
+	</bean>
+
+	<bean id="jdbcTemplate"
+		class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
+		<constructor-arg name="dataSource" ref="dataSourceProxy" />
+	</bean>
+	<bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler"
+		lazy-init="true" />
+
+	<!--事务管理器配置 -->
+	<bean id="transactionManager"
+		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
+		<property name="dataSource" ref="dataSourceProxy" />
+	</bean>
+
+	<tx:advice id="txAdvice" transaction-manager="transactionManager">
+		<tx:attributes>
+			<tx:method name="add*" propagation="REQUIRED" />
+			<tx:method name="append*" propagation="REQUIRED" />
+			<tx:method name="save*" propagation="REQUIRED" />
+			<tx:method name="update*" propagation="REQUIRED" />
+			<tx:method name="modify*" propagation="REQUIRED" />
+			<tx:method name="edit*" propagation="REQUIRED" />
+			<tx:method name="delete*" propagation="REQUIRED" />
+			<tx:method name="remove*" propagation="REQUIRED" />
+			<tx:method name="init" propagation="REQUIRED" />
+			<tx:method name="delAndInit" propagation="REQUIRED" />
+
+			<tx:method name="get*" propagation="REQUIRED" read-only="true" />
+			<tx:method name="find*" propagation="REQUIRED" read-only="true" />
+			<tx:method name="load*" propagation="REQUIRED" read-only="true" />
+			<tx:method name="search*" propagation="REQUIRED" read-only="true" />
+			<tx:method name="datagrid*" propagation="REQUIRED"
+				read-only="true" />
+			<tx:method name="*" propagation="REQUIRED" />
+		</tx:attributes>
+	</tx:advice>
+
+	<aop:config expose-proxy="true" proxy-target-class="true">
+		<!-- 只对业务逻辑层实施事务 -->
+		<aop:pointcut id="txPointcut"
+			expression="execution(* com.jsjty.service..*+.*(..))" />
+		<aop:advisor id="txAdvisor" advice-ref="txAdvice"
+			pointcut-ref="txPointcut" />
+	</aop:config>
+
+
+	<import resource="classpath:spring-ehcache.xml" />
+	<!-- 删除飞机数据获取 <import resource="classpath:spring-tasks.xml"/> -->
+	<!--:加载anychat业务服务器 -->
+	<bean id="businessServer" lazy-init="false"  scope="singleton"
+		class="com.jsjty.core.BusinessServer" init-method="initSdk" />
+
+</beans>

+ 11 - 0
jdc/chatServer/trunk/src/main/resources/spring-ehcache.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	   xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p"
+	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+		http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
+
+	<!-- 开启spring缓存 -->
+	<cache:annotation-driven cache-manager="cacheManager" />
+	<bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:ehcache.xml" p:shared="false" />
+	<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="cacheManagerFactory" />
+</beans>

+ 43 - 0
jdc/chatServer/trunk/src/main/resources/spring-mvc.xml

@@ -0,0 +1,43 @@
+<beans:beans xmlns="http://www.springframework.org/schema/mvc"
+             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+             xmlns:beans="http://www.springframework.org/schema/beans"
+             xmlns:context="http://www.springframework.org/schema/context"
+             xmlns:mvc="http://www.springframework.org/schema/mvc"
+             xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
+		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
+    <!--Date 转 Json-->
+    <beans:bean id="customObjectMapper" class="com.jsjty.core.CustomObjectMapper"></beans:bean>
+    <context:component-scan base-package="com.jsjty.controller"/>
+    <mvc:annotation-driven>
+        <message-converters>
+            <beans:ref bean="mappingJacksonHttpMessageConverter"/>
+        </message-converters>
+    </mvc:annotation-driven>
+
+    <beans:bean id="mappingJacksonHttpMessageConverter"
+                class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
+        <beans:property name="supportedMediaTypes">
+            <beans:list>
+                <beans:value>text/html;charset=UTF-8</beans:value>
+                <beans:value>application/json;charset=UTF-8</beans:value>
+            </beans:list>
+        </beans:property>
+        <beans:property name="objectMapper" ref="customObjectMapper"></beans:property>
+    </beans:bean>
+    <beans:bean id="requestMappingHandlerAdapter"
+                class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
+        <beans:property name="messageConverters">
+            <beans:list>
+                <beans:ref bean="mappingJacksonHttpMessageConverter"/>
+            </beans:list>
+        </beans:property>
+    </beans:bean>
+
+    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
+        <beans:property name="prefix" value="/WEB-INF/view/"/>
+        <beans:property name="contentType" value="text/html; charset=UTF-8" />
+        <beans:property name="suffix" value=".jsp"/>
+    </beans:bean>
+</beans:beans>

+ 13 - 0
jdc/chatServer/trunk/src/main/resources/spring-tasks.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:task="http://www.springframework.org/schema/task"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
+
+    <!-- 每天晚上23点59分59秒修复一下数据库,修复白天大家测试后造成的数据错乱 -->
+    <task:scheduled-tasks scheduler="scheduler">
+        <task:scheduled ref="businessServer" method="resendMsg" cron="*/3 * * * * ?"/>
+    </task:scheduled-tasks>
+    <task:scheduler id="scheduler" pool-size="20" />
+</beans>

+ 61 - 0
jdc/chatServer/trunk/src/main/webapp/WEB-INF/web.xml

@@ -0,0 +1,61 @@
+<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
+	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+	<display-name>MobileTunnel</display-name>
+	<context-param>
+		<param-name>contextConfigLocation</param-name>
+		<param-value>classpath:spring-context.xml</param-value>
+	</context-param>
+	<context-param>
+		<param-name>log4jConfigLocation</param-name>
+		<param-value>classpath:log4j.xml</param-value>
+	</context-param>
+	<context-param>
+		<param-name>log4jRefreshInterval</param-name>
+		<param-value>3000</param-value>
+	</context-param>
+	<listener>
+		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+	</listener>
+	<listener>
+		<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
+	</listener>
+	<!-- 配置字符集过滤器 -->
+	<filter>
+		<filter-name>encodingFilter</filter-name>
+		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
+		<init-param>
+			<param-name>encoding</param-name>
+			<param-value>UTF-8</param-value>
+		</init-param>
+	</filter>
+	<!-- 配置项目的编码mapping -->
+	<filter-mapping>
+		<filter-name>encodingFilter</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
+	<welcome-file-list>
+		<welcome-file>index.jsp</welcome-file>
+	</welcome-file-list>
+	<servlet>
+		<servlet-name>quartzServlet</servlet-name>
+		<servlet-class>com.jsjty.core.QuartzServlet</servlet-class>
+		<load-on-startup>3</load-on-startup>
+	</servlet>
+	<servlet>
+		<servlet-name>mvc-dispatcher</servlet-name>
+		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+		<init-param>
+			<param-name>contextConfigLocation</param-name>
+			<param-value>classpath:spring-mvc.xml</param-value>
+		</init-param>
+		<load-on-startup>1</load-on-startup>
+	</servlet>
+
+	<servlet-mapping>
+		<servlet-name>mvc-dispatcher</servlet-name>
+		<url-pattern>/</url-pattern>
+	</servlet-mapping>
+</web-app>

Разница между файлами не показана из-за своего большого размера
+ 229 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/accordion.css


+ 592 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/accordion.js

@@ -0,0 +1,592 @@
+/*!
+ * # Semantic UI 2.0.0 - Accordion
+ * http://github.com/semantic-org/semantic-ui/
+ *
+ *
+ * Copyright 2015 Contributors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ */
+
+;(function ($, window, document, undefined) {
+
+"use strict";
+
+$.fn.accordion = function(parameters) {
+  var
+    $allModules     = $(this),
+
+    time            = new Date().getTime(),
+    performance     = [],
+
+    query           = arguments[0],
+    methodInvoked   = (typeof query == 'string'),
+    queryArguments  = [].slice.call(arguments, 1),
+
+    requestAnimationFrame = window.requestAnimationFrame
+      || window.mozRequestAnimationFrame
+      || window.webkitRequestAnimationFrame
+      || window.msRequestAnimationFrame
+      || function(callback) { setTimeout(callback, 0); },
+
+    returnedValue
+  ;
+  $allModules
+    .each(function() {
+      var
+        settings        = ( $.isPlainObject(parameters) )
+          ? $.extend(true, {}, $.fn.accordion.settings, parameters)
+          : $.extend({}, $.fn.accordion.settings),
+
+        className       = settings.className,
+        namespace       = settings.namespace,
+        selector        = settings.selector,
+        error           = settings.error,
+
+        eventNamespace  = '.' + namespace,
+        moduleNamespace = 'module-' + namespace,
+        moduleSelector  = $allModules.selector || '',
+
+        $module  = $(this),
+        $title   = $module.find(selector.title),
+        $content = $module.find(selector.content),
+
+        element  = this,
+        instance = $module.data(moduleNamespace),
+        observer,
+        module
+      ;
+
+      module = {
+
+        initialize: function() {
+          module.debug('Initializing', $module);
+          module.bind.events();
+          module.observeChanges();
+          module.instantiate();
+        },
+
+        instantiate: function() {
+          instance = module;
+          $module
+            .data(moduleNamespace, module)
+          ;
+        },
+
+        destroy: function() {
+          module.debug('Destroying previous instance', $module);
+          $module
+            .off(eventNamespace)
+            .removeData(moduleNamespace)
+          ;
+        },
+
+        refresh: function() {
+          $title   = $module.find(selector.title);
+          $content = $module.find(selector.content);
+        },
+
+        observeChanges: function() {
+          if('MutationObserver' in window) {
+            observer = new MutationObserver(function(mutations) {
+              module.debug('DOM tree modified, updating selector cache');
+              module.refresh();
+            });
+            observer.observe(element, {
+              childList : true,
+              subtree   : true
+            });
+            module.debug('Setting up mutation observer', observer);
+          }
+        },
+
+        bind: {
+          events: function() {
+            module.debug('Binding delegated events');
+            $module
+              .on(settings.on + eventNamespace, selector.trigger, module.event.click)
+            ;
+          }
+        },
+
+        event: {
+          click: function() {
+            module.toggle.call(this);
+          }
+        },
+
+        toggle: function(query) {
+          var
+            $activeTitle = (query !== undefined)
+              ? (typeof query === 'number')
+                ? $title.eq(query)
+                : $(query).closest(selector.title)
+              : $(this).closest(selector.title),
+            $activeContent = $activeTitle.next($content),
+            isAnimating = $activeContent.hasClass(className.animating),
+            isActive    = $activeContent.hasClass(className.active),
+            isOpen      = (isActive && !isAnimating),
+            isOpening   = (!isActive && isAnimating)
+          ;
+          module.debug('Toggling visibility of content', $activeTitle);
+          if(isOpen || isOpening) {
+            if(settings.collapsible) {
+              module.close.call($activeTitle);
+            }
+            else {
+              module.debug('Cannot close accordion content collapsing is disabled');
+            }
+          }
+          else {
+            module.open.call($activeTitle);
+          }
+        },
+
+        open: function(query) {
+          var
+            $activeTitle = (query !== undefined)
+              ? (typeof query === 'number')
+                ? $title.eq(query)
+                : $(query).closest(selector.title)
+              : $(this).closest(selector.title),
+            $activeContent = $activeTitle.next($content),
+            isAnimating = $activeContent.hasClass(className.animating),
+            isActive    = $activeContent.hasClass(className.active),
+            isOpen      = (isActive || isAnimating)
+          ;
+          if(isOpen) {
+            module.debug('Accordion already open, skipping', $activeContent);
+            return;
+          }
+          module.debug('Opening accordion content', $activeTitle);
+          settings.onOpening.call($activeContent);
+          if(settings.exclusive) {
+            module.closeOthers.call($activeTitle);
+          }
+          $activeTitle
+            .addClass(className.active)
+          ;
+          $activeContent
+            .stop(true, true)
+            .addClass(className.animating)
+          ;
+          if(settings.animateChildren) {
+            if($.fn.transition !== undefined && $module.transition('is supported')) {
+              $activeContent
+                .children()
+                  .transition({
+                    animation   : 'fade in',
+                    queue       : false,
+                    useFailSafe : true,
+                    debug       : settings.debug,
+                    verbose     : settings.verbose,
+                    duration    : settings.duration
+                  })
+              ;
+            }
+            else {
+              $activeContent
+                .children()
+                  .stop(true, true)
+                  .animate({
+                    opacity: 1
+                  }, settings.duration, module.resetOpacity)
+              ;
+            }
+          }
+          $activeContent
+            .slideDown(settings.duration, settings.easing, function() {
+              $activeContent
+                .removeClass(className.animating)
+                .addClass(className.active)
+              ;
+              module.reset.display.call(this);
+              settings.onOpen.call(this);
+              settings.onChange.call(this);
+            })
+          ;
+        },
+
+        close: function(query) {
+          var
+            $activeTitle = (query !== undefined)
+              ? (typeof query === 'number')
+                ? $title.eq(query)
+                : $(query).closest(selector.title)
+              : $(this).closest(selector.title),
+            $activeContent = $activeTitle.next($content),
+            isAnimating    = $activeContent.hasClass(className.animating),
+            isActive       = $activeContent.hasClass(className.active),
+            isOpening      = (!isActive && isAnimating),
+            isClosing      = (isActive && isAnimating)
+          ;
+          if((isActive || isOpening) && !isClosing) {
+            module.debug('Closing accordion content', $activeContent);
+            settings.onClosing.call($activeContent);
+            $activeTitle
+              .removeClass(className.active)
+            ;
+            $activeContent
+              .stop(true, true)
+              .addClass(className.animating)
+            ;
+            if(settings.animateChildren) {
+              if($.fn.transition !== undefined && $module.transition('is supported')) {
+                $activeContent
+                  .children()
+                    .transition({
+                      animation   : 'fade out',
+                      queue       : false,
+                      useFailSafe : true,
+                      debug       : settings.debug,
+                      verbose     : settings.verbose,
+                      duration    : settings.duration
+                    })
+                ;
+              }
+              else {
+                $activeContent
+                  .children()
+                    .stop(true, true)
+                    .animate({
+                      opacity: 0
+                    }, settings.duration, module.resetOpacity)
+                ;
+              }
+            }
+            $activeContent
+              .slideUp(settings.duration, settings.easing, function() {
+                $activeContent
+                  .removeClass(className.animating)
+                  .removeClass(className.active)
+                ;
+                module.reset.display.call(this);
+                settings.onClose.call(this);
+                settings.onChange.call(this);
+              })
+            ;
+          }
+        },
+
+        closeOthers: function(index) {
+          var
+            $activeTitle = (index !== undefined)
+              ? $title.eq(index)
+              : $(this).closest(selector.title),
+            $parentTitles    = $activeTitle.parents(selector.content).prev(selector.title),
+            $activeAccordion = $activeTitle.closest(selector.accordion),
+            activeSelector   = selector.title + '.' + className.active + ':visible',
+            activeContent    = selector.content + '.' + className.active + ':visible',
+            $openTitles,
+            $nestedTitles,
+            $openContents
+          ;
+          if(settings.closeNested) {
+            $openTitles   = $activeAccordion.find(activeSelector).not($parentTitles);
+            $openContents = $openTitles.next($content);
+          }
+          else {
+            $openTitles   = $activeAccordion.find(activeSelector).not($parentTitles);
+            $nestedTitles = $activeAccordion.find(activeContent).find(activeSelector).not($parentTitles);
+            $openTitles   = $openTitles.not($nestedTitles);
+            $openContents = $openTitles.next($content);
+          }
+          if( ($openTitles.length > 0) ) {
+            module.debug('Exclusive enabled, closing other content', $openTitles);
+            $openTitles
+              .removeClass(className.active)
+            ;
+            $openContents
+              .removeClass(className.animating)
+              .stop(true, true)
+            ;
+            if(settings.animateChildren) {
+              if($.fn.transition !== undefined && $module.transition('is supported')) {
+                $openContents
+                  .children()
+                    .transition({
+                      animation   : 'fade out',
+                      useFailSafe : true,
+                      debug       : settings.debug,
+                      verbose     : settings.verbose,
+                      duration    : settings.duration
+                    })
+                ;
+              }
+              else {
+                $openContents
+                  .children()
+                    .stop(true, true)
+                    .animate({
+                      opacity: 0
+                    }, settings.duration, module.resetOpacity)
+                ;
+              }
+            }
+            $openContents
+              .slideUp(settings.duration , settings.easing, function() {
+                $(this).removeClass(className.active);
+                module.reset.display.call(this);
+              })
+            ;
+          }
+        },
+
+        reset: {
+
+          display: function() {
+            module.verbose('Removing inline display from element', this);
+            $(this).css('display', '');
+            if( $(this).attr('style') === '') {
+              $(this)
+                .attr('style', '')
+                .removeAttr('style')
+              ;
+            }
+          },
+
+          opacity: function() {
+            module.verbose('Removing inline opacity from element', this);
+            $(this).css('opacity', '');
+            if( $(this).attr('style') === '') {
+              $(this)
+                .attr('style', '')
+                .removeAttr('style')
+              ;
+            }
+          },
+
+        },
+
+        setting: function(name, value) {
+          module.debug('Changing setting', name, value);
+          if( $.isPlainObject(name) ) {
+            $.extend(true, settings, name);
+          }
+          else if(value !== undefined) {
+            settings[name] = value;
+          }
+          else {
+            return settings[name];
+          }
+        },
+        internal: function(name, value) {
+          module.debug('Changing internal', name, value);
+          if(value !== undefined) {
+            if( $.isPlainObject(name) ) {
+              $.extend(true, module, name);
+            }
+            else {
+              module[name] = value;
+            }
+          }
+          else {
+            return module[name];
+          }
+        },
+        debug: function() {
+          if(settings.debug) {
+            if(settings.performance) {
+              module.performance.log(arguments);
+            }
+            else {
+              module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
+              module.debug.apply(console, arguments);
+            }
+          }
+        },
+        verbose: function() {
+          if(settings.verbose && settings.debug) {
+            if(settings.performance) {
+              module.performance.log(arguments);
+            }
+            else {
+              module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
+              module.verbose.apply(console, arguments);
+            }
+          }
+        },
+        error: function() {
+          module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
+          module.error.apply(console, arguments);
+        },
+        performance: {
+          log: function(message) {
+            var
+              currentTime,
+              executionTime,
+              previousTime
+            ;
+            if(settings.performance) {
+              currentTime   = new Date().getTime();
+              previousTime  = time || currentTime;
+              executionTime = currentTime - previousTime;
+              time          = currentTime;
+              performance.push({
+                'Name'           : message[0],
+                'Arguments'      : [].slice.call(message, 1) || '',
+                'Element'        : element,
+                'Execution Time' : executionTime
+              });
+            }
+            clearTimeout(module.performance.timer);
+            module.performance.timer = setTimeout(module.performance.display, 500);
+          },
+          display: function() {
+            var
+              title = settings.name + ':',
+              totalTime = 0
+            ;
+            time = false;
+            clearTimeout(module.performance.timer);
+            $.each(performance, function(index, data) {
+              totalTime += data['Execution Time'];
+            });
+            title += ' ' + totalTime + 'ms';
+            if(moduleSelector) {
+              title += ' \'' + moduleSelector + '\'';
+            }
+            if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
+              console.groupCollapsed(title);
+              if(console.table) {
+                console.table(performance);
+              }
+              else {
+                $.each(performance, function(index, data) {
+                  console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
+                });
+              }
+              console.groupEnd();
+            }
+            performance = [];
+          }
+        },
+        invoke: function(query, passedArguments, context) {
+          var
+            object = instance,
+            maxDepth,
+            found,
+            response
+          ;
+          passedArguments = passedArguments || queryArguments;
+          context         = element         || context;
+          if(typeof query == 'string' && object !== undefined) {
+            query    = query.split(/[\. ]/);
+            maxDepth = query.length - 1;
+            $.each(query, function(depth, value) {
+              var camelCaseValue = (depth != maxDepth)
+                ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
+                : query
+              ;
+              if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
+                object = object[camelCaseValue];
+              }
+              else if( object[camelCaseValue] !== undefined ) {
+                found = object[camelCaseValue];
+                return false;
+              }
+              else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
+                object = object[value];
+              }
+              else if( object[value] !== undefined ) {
+                found = object[value];
+                return false;
+              }
+              else {
+                module.error(error.method, query);
+                return false;
+              }
+            });
+          }
+          if ( $.isFunction( found ) ) {
+            response = found.apply(context, passedArguments);
+          }
+          else if(found !== undefined) {
+            response = found;
+          }
+          if($.isArray(returnedValue)) {
+            returnedValue.push(response);
+          }
+          else if(returnedValue !== undefined) {
+            returnedValue = [returnedValue, response];
+          }
+          else if(response !== undefined) {
+            returnedValue = response;
+          }
+          return found;
+        }
+      };
+      if(methodInvoked) {
+        if(instance === undefined) {
+          module.initialize();
+        }
+        module.invoke(query);
+      }
+      else {
+        if(instance !== undefined) {
+          instance.invoke('destroy');
+        }
+        module.initialize();
+      }
+    })
+  ;
+  return (returnedValue !== undefined)
+    ? returnedValue
+    : this
+  ;
+};
+
+$.fn.accordion.settings = {
+
+  name            : 'Accordion',
+  namespace       : 'accordion',
+
+  debug           : false,
+  verbose         : false,
+  performance     : true,
+
+  on              : 'click',
+
+  exclusive       : true,
+  collapsible     : true,
+  closeNested     : false,
+  animateChildren : true,
+
+  duration        : 350,
+  easing          : 'easeOutQuad',
+
+
+  onOpening       : function(){},
+  onOpen          : function(){},
+  onClosing       : function(){},
+  onClose         : function(){},
+  onChange        : function(){},
+
+  error: {
+    method : 'The method you called is not defined'
+  },
+
+  className   : {
+    active    : 'active',
+    animating : 'animating'
+  },
+
+  selector    : {
+    accordion : '.accordion',
+    title     : '.title',
+    trigger   : '.title',
+    content   : '.content'
+  }
+
+};
+
+// Adds easing
+$.extend( $.easing, {
+  easeOutQuad: function (x, t, b, c, d) {
+    return -c *(t/=d)*(t-2) + b;
+  }
+});
+
+})( jQuery, window , document );
+

Разница между файлами не показана из-за своего большого размера
+ 9 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/accordion.min.css


Разница между файлами не показана из-за своего большого размера
+ 10 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/accordion.min.js


+ 276 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/ad.css

@@ -0,0 +1,276 @@
+/*!
+ * # Semantic UI 2.0.0 - Ad
+ * http://github.com/semantic-org/semantic-ui/
+ *
+ *
+ * Copyright 2013 Contributors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ */
+
+
+/*******************************
+         Advertisement
+*******************************/
+
+.ui.ad {
+  display: block;
+  overflow: hidden;
+  margin: 1em 0em;
+}
+.ui.ad:first-child {
+  margin: 0em;
+}
+.ui.ad:last-child {
+  margin: 0em;
+}
+.ui.ad iframe {
+  margin: 0em;
+  padding: 0em;
+  border: none;
+  overflow: hidden;
+}
+
+/*--------------
+     Common
+---------------*/
+
+
+/* Leaderboard */
+.ui.leaderboard.ad {
+  width: 728px;
+  height: 90px;
+}
+
+/* Medium Rectangle */
+.ui[class*="medium rectangle"].ad {
+  width: 300px;
+  height: 250px;
+}
+
+/* Large Rectangle */
+.ui[class*="large rectangle"].ad {
+  width: 336px;
+  height: 280px;
+}
+
+/* Half Page */
+.ui[class*="half page"].ad {
+  width: 300px;
+  height: 600px;
+}
+
+/*--------------
+     Square
+---------------*/
+
+
+/* Square */
+.ui.square.ad {
+  width: 250px;
+  height: 250px;
+}
+
+/* Small Square */
+.ui[class*="small square"].ad {
+  width: 200px;
+  height: 200px;
+}
+
+/*--------------
+    Rectangle
+---------------*/
+
+
+/* Small Rectangle */
+.ui[class*="small rectangle"].ad {
+  width: 180px;
+  height: 150px;
+}
+
+/* Vertical Rectangle */
+.ui[class*="vertical rectangle"].ad {
+  width: 240px;
+  height: 400px;
+}
+
+/*--------------
+     Button
+---------------*/
+
+.ui.button.ad {
+  width: 120px;
+  height: 90px;
+}
+.ui[class*="square button"].ad {
+  width: 125px;
+  height: 125px;
+}
+.ui[class*="small button"].ad {
+  width: 120px;
+  height: 60px;
+}
+
+/*--------------
+   Skyscrapers
+---------------*/
+
+
+/* Skyscraper */
+.ui.skyscraper.ad {
+  width: 120px;
+  height: 600px;
+}
+
+/* Wide Skyscraper */
+.ui[class*="wide skyscraper"].ad {
+  width: 160px;
+}
+
+/*--------------
+     Banners
+---------------*/
+
+
+/* Banner */
+.ui.banner.ad {
+  width: 468px;
+  height: 60px;
+}
+
+/* Vertical Banner */
+.ui[class*="vertical banner"].ad {
+  width: 120px;
+  height: 240px;
+}
+
+/* Top Banner */
+.ui[class*="top banner"].ad {
+  width: 930px;
+  height: 180px;
+}
+
+/* Half Banner */
+.ui[class*="half banner"].ad {
+  width: 234px;
+  height: 60px;
+}
+
+/*--------------
+    Boards
+---------------*/
+
+
+/* Leaderboard */
+.ui[class*="large leaderboard"].ad {
+  width: 970px;
+  height: 90px;
+}
+
+/* Billboard */
+.ui.billboard.ad {
+  width: 970px;
+  height: 250px;
+}
+
+/*--------------
+    Panorama
+---------------*/
+
+
+/* Panorama */
+.ui.panorama.ad {
+  width: 980px;
+  height: 120px;
+}
+
+/*--------------
+     Netboard
+---------------*/
+
+
+/* Netboard */
+.ui.netboard.ad {
+  width: 580px;
+  height: 400px;
+}
+
+/*--------------
+     Mobile
+---------------*/
+
+
+/* Large Mobile Banner */
+.ui[class*="large mobile banner"].ad {
+  width: 320px;
+  height: 100px;
+}
+
+/* Mobile Leaderboard */
+.ui[class*="mobile leaderboard"].ad {
+  width: 320px;
+  height: 50px;
+}
+
+
+/*******************************
+             Types
+*******************************/
+
+
+/* Mobile Sizes */
+.ui.mobile.ad {
+  display: none;
+}
+@media only screen and (max-width: 767px) {
+  .ui.mobile.ad {
+    display: block;
+  }
+}
+
+
+/*******************************
+           Variations
+*******************************/
+
+.ui.centered.ad {
+  margin-left: auto;
+  margin-right: auto;
+}
+.ui.test.ad {
+  position: relative;
+  background: #545454;
+}
+.ui.test.ad:after {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  width: 100%;
+  text-align: center;
+  -webkit-transform: translateX(-50%) translateY(-50%);
+      -ms-transform: translateX(-50%) translateY(-50%);
+          transform: translateX(-50%) translateY(-50%);
+  content: 'Ad';
+  color: #ffffff;
+  font-size: 1em;
+  font-weight: bold;
+}
+.ui.mobile.test.ad:after {
+  font-size: 0.85714286em;
+}
+.ui.test.ad[data-text]:after {
+  content: attr(data-text);
+}
+
+
+/*******************************
+         Theme Overrides
+*******************************/
+
+
+
+/*******************************
+    User Variable Overrides
+*******************************/
+

+ 10 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/ad.min.css

@@ -0,0 +1,10 @@
+/*!
+ * # Semantic UI 2.0.0 - Ad
+ * http://github.com/semantic-org/semantic-ui/
+ *
+ *
+ * Copyright 2013 Contributors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ */.ui.ad{display:block;overflow:hidden;margin:1em 0}.ui.ad:first-child,.ui.ad:last-child{margin:0}.ui.ad iframe{margin:0;padding:0;border:none;overflow:hidden}.ui.leaderboard.ad{width:728px;height:90px}.ui[class*="medium rectangle"].ad{width:300px;height:250px}.ui[class*="large rectangle"].ad{width:336px;height:280px}.ui[class*="half page"].ad{width:300px;height:600px}.ui.square.ad{width:250px;height:250px}.ui[class*="small square"].ad{width:200px;height:200px}.ui[class*="small rectangle"].ad{width:180px;height:150px}.ui[class*="vertical rectangle"].ad{width:240px;height:400px}.ui.button.ad{width:120px;height:90px}.ui[class*="square button"].ad{width:125px;height:125px}.ui[class*="small button"].ad{width:120px;height:60px}.ui.skyscraper.ad{width:120px;height:600px}.ui[class*="wide skyscraper"].ad{width:160px}.ui.banner.ad{width:468px;height:60px}.ui[class*="vertical banner"].ad{width:120px;height:240px}.ui[class*="top banner"].ad{width:930px;height:180px}.ui[class*="half banner"].ad{width:234px;height:60px}.ui[class*="large leaderboard"].ad{width:970px;height:90px}.ui.billboard.ad{width:970px;height:250px}.ui.panorama.ad{width:980px;height:120px}.ui.netboard.ad{width:580px;height:400px}.ui[class*="large mobile banner"].ad{width:320px;height:100px}.ui[class*="mobile leaderboard"].ad{width:320px;height:50px}.ui.mobile.ad{display:none}@media only screen and (max-width:767px){.ui.mobile.ad{display:block}}.ui.centered.ad{margin-left:auto;margin-right:auto}.ui.test.ad{position:relative;background:#545454}.ui.test.ad:after{position:absolute;top:50%;left:50%;width:100%;text-align:center;-webkit-transform:translateX(-50%) translateY(-50%);-ms-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%);content:'Ad';color:#fff;font-size:1em;font-weight:700}.ui.mobile.test.ad:after{font-size:.85714286em}.ui.test.ad[data-text]:after{content:attr(data-text)}

+ 1077 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/api.js

@@ -0,0 +1,1077 @@
+/*!
+ * # Semantic UI 2.0.0 - API
+ * http://github.com/semantic-org/semantic-ui/
+ *
+ *
+ * Copyright 2015 Contributors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ */
+
+;(function ( $, window, document, undefined ) {
+
+"use strict";
+
+$.api = $.fn.api = function(parameters) {
+
+  var
+    // use window context if none specified
+    $allModules     = $.isFunction(this)
+        ? $(window)
+        : $(this),
+    moduleSelector = $allModules.selector || '',
+    time           = new Date().getTime(),
+    performance    = [],
+
+    query          = arguments[0],
+    methodInvoked  = (typeof query == 'string'),
+    queryArguments = [].slice.call(arguments, 1),
+
+    returnedValue
+  ;
+
+  $allModules
+    .each(function() {
+      var
+        settings          = ( $.isPlainObject(parameters) )
+          ? $.extend(true, {}, $.fn.api.settings, parameters)
+          : $.extend({}, $.fn.api.settings),
+
+        // internal aliases
+        namespace       = settings.namespace,
+        metadata        = settings.metadata,
+        selector        = settings.selector,
+        error           = settings.error,
+        className       = settings.className,
+
+        // define namespaces for modules
+        eventNamespace  = '.' + namespace,
+        moduleNamespace = 'module-' + namespace,
+
+        // element that creates request
+        $module         = $(this),
+        $form           = $module.closest(selector.form),
+
+        // context used for state
+        $context        = (settings.stateContext)
+          ? $(settings.stateContext)
+          : $module,
+
+        // request details
+        ajaxSettings,
+        requestSettings,
+        url,
+        data,
+        requestStartTime,
+
+        // standard module
+        element         = this,
+        context         = $context[0],
+        instance        = $module.data(moduleNamespace),
+        module
+      ;
+
+      module = {
+
+        initialize: function() {
+          if(!methodInvoked) {
+            module.bind.events();
+          }
+          module.instantiate();
+        },
+
+        instantiate: function() {
+          module.verbose('Storing instance of module', module);
+          instance = module;
+          $module
+            .data(moduleNamespace, instance)
+          ;
+        },
+
+        destroy: function() {
+          module.verbose('Destroying previous module for', element);
+          $module
+            .removeData(moduleNamespace)
+            .off(eventNamespace)
+          ;
+        },
+
+        bind: {
+          events: function() {
+            var
+              triggerEvent = module.get.event()
+            ;
+            if( triggerEvent ) {
+              module.verbose('Attaching API events to element', triggerEvent);
+              $module
+                .on(triggerEvent + eventNamespace, module.event.trigger)
+              ;
+            }
+            else if(settings.on == 'now') {
+              module.debug('Querying API now', triggerEvent);
+              module.query();
+            }
+          }
+        },
+
+        read: {
+          cachedResponse: function(url) {
+            var
+              response
+            ;
+            if(window.Storage === undefined) {
+              module.error(error.noStorage);
+              return;
+            }
+            response = sessionStorage.getItem(url);
+            module.debug('Using cached response', url, response);
+            if(response !== undefined) {
+              try {
+               response = JSON.parse(response);
+              }
+              catch(e) {
+                // didnt store object
+              }
+              return response;
+            }
+            return false;
+          }
+        },
+        write: {
+          cachedResponse: function(url, response) {
+            if(response && response === '') {
+              module.debug('Response empty, not caching', response);
+              return;
+            }
+            if(window.Storage === undefined) {
+              module.error(error.noStorage);
+              return;
+            }
+            if( $.isPlainObject(response) ) {
+              response = JSON.stringify(response);
+            }
+            sessionStorage.setItem(url, response);
+            module.verbose('Storing cached response for url', url, response);
+          }
+        },
+
+        query: function() {
+
+          if(module.is.disabled()) {
+            module.debug('Element is disabled API request aborted');
+            return;
+          }
+
+          if(module.is.loading()) {
+            if(settings.interruptRequests) {
+              module.debug('Interrupting previous request');
+              module.abort();
+            }
+            else {
+              module.debug('Cancelling request, previous request is still pending');
+              return;
+            }
+          }
+
+          // pass element metadata to url (value, text)
+          if(settings.defaultData) {
+            $.extend(true, settings.urlData, module.get.defaultData());
+          }
+
+          // Add form content
+          if(settings.serializeForm) {
+            settings.data = module.add.formData(settings.data);
+          }
+
+          // call beforesend and get any settings changes
+          requestSettings = module.get.settings();
+
+          // check if before send cancelled request
+          if(requestSettings === false) {
+            module.cancelled = true;
+            module.error(error.beforeSend);
+            return;
+          }
+          else {
+            module.cancelled = false;
+          }
+
+          // get url
+          url = module.get.templatedURL();
+
+          if(!url && !module.is.mocked()) {
+            module.error(error.missingURL);
+            return;
+          }
+
+          // replace variables
+          url = module.add.urlData( url );
+
+          // missing url parameters
+          if( !url && !module.is.mocked()) {
+            return;
+          }
+
+
+          // look for jQuery ajax parameters in settings
+          ajaxSettings = $.extend(true, {}, settings, {
+            type       : settings.method || settings.type,
+            data       : data,
+            url        : settings.base + url,
+            beforeSend : settings.beforeXHR,
+            success    : function() {},
+            failure    : function() {},
+            complete   : function() {}
+          });
+
+          module.debug('Querying URL', ajaxSettings.url);
+          module.verbose('Using AJAX settings', ajaxSettings);
+
+          if(settings.cache === 'local' && module.read.cachedResponse(url)) {
+            module.debug('Response returned from local cache');
+            module.request = module.create.request();
+            module.request.resolveWith(context, [ module.read.cachedResponse(url) ]);
+            return;
+          }
+
+          if( !settings.throttle ) {
+            module.debug('Sending request', data, ajaxSettings.method);
+            module.send.request();
+          }
+          else {
+            if(!settings.throttleFirstRequest && !module.timer) {
+              module.debug('Sending request', data, ajaxSettings.method);
+              module.send.request();
+              module.timer = setTimeout(function(){}, settings.throttle);
+            }
+            else {
+              module.debug('Throttling request', settings.throttle);
+              clearTimeout(module.timer);
+              module.timer = setTimeout(function() {
+                if(module.timer) {
+                  delete module.timer;
+                }
+                module.debug('Sending throttled request', data, ajaxSettings.method);
+                module.send.request();
+              }, settings.throttle);
+            }
+          }
+
+        },
+
+        is: {
+          disabled: function() {
+            return ($module.filter(selector.disabled).length > 0);
+          },
+          form: function() {
+            return $module.is('form');
+          },
+          mocked: function() {
+            return (settings.mockResponse || settings.mockResponseAsync);
+          },
+          input: function() {
+            return $module.is('input');
+          },
+          loading: function() {
+            return (module.request && module.request.state() == 'pending');
+          },
+          abortedRequest: function(xhr) {
+            if(xhr && xhr.readyState !== undefined && xhr.readyState === 0) {
+              module.verbose('XHR request determined to be aborted');
+              return true;
+            }
+            else {
+              module.verbose('XHR request was not aborted');
+              return false;
+            }
+          },
+          validResponse: function(response) {
+            if( settings.dataType !== 'json' || !$.isFunction(settings.successTest) ) {
+              module.verbose('Response is not JSON, skipping validation', settings.successTest, response);
+              return true;
+            }
+            module.debug('Checking JSON returned success', settings.successTest, response);
+            if( settings.successTest(response) ) {
+              module.debug('Response passed success test', response);
+              return true;
+            }
+            else {
+              module.debug('Response failed success test', response);
+              return false;
+            }
+          }
+        },
+
+        was: {
+          cancelled: function() {
+            return (module.cancelled || false);
+          },
+          succesful: function() {
+            return (module.request && module.request.state() == 'resolved');
+          },
+          failure: function() {
+            return (module.request && module.request.state() == 'rejected');
+          },
+          complete: function() {
+            return (module.request && (module.request.state() == 'resolved' || module.request.state() == 'rejected') );
+          }
+        },
+
+        add: {
+          urlData: function(url, urlData) {
+            var
+              requiredVariables,
+              optionalVariables
+            ;
+            if(url) {
+              requiredVariables = url.match(settings.regExp.required);
+              optionalVariables = url.match(settings.regExp.optional);
+              urlData           = urlData || settings.urlData;
+              if(requiredVariables) {
+                module.debug('Looking for required URL variables', requiredVariables);
+                $.each(requiredVariables, function(index, templatedString) {
+                  var
+                    // allow legacy {$var} style
+                    variable = (templatedString.indexOf('$') !== -1)
+                      ? templatedString.substr(2, templatedString.length - 3)
+                      : templatedString.substr(1, templatedString.length - 2),
+                    value   = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
+                      ? urlData[variable]
+                      : ($module.data(variable) !== undefined)
+                        ? $module.data(variable)
+                        : ($context.data(variable) !== undefined)
+                          ? $context.data(variable)
+                          : urlData[variable]
+                  ;
+                  // remove value
+                  if(value === undefined) {
+                    module.error(error.requiredParameter, variable, url);
+                    url = false;
+                    return false;
+                  }
+                  else {
+                    module.verbose('Found required variable', variable, value);
+                    url = url.replace(templatedString, value);
+                  }
+                });
+              }
+              if(optionalVariables) {
+                module.debug('Looking for optional URL variables', requiredVariables);
+                $.each(optionalVariables, function(index, templatedString) {
+                  var
+                    // allow legacy {/$var} style
+                    variable = (templatedString.indexOf('$') !== -1)
+                      ? templatedString.substr(3, templatedString.length - 4)
+                      : templatedString.substr(2, templatedString.length - 3),
+                    value   = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
+                      ? urlData[variable]
+                      : ($module.data(variable) !== undefined)
+                        ? $module.data(variable)
+                        : ($context.data(variable) !== undefined)
+                          ? $context.data(variable)
+                          : urlData[variable]
+                  ;
+                  // optional replacement
+                  if(value !== undefined) {
+                    module.verbose('Optional variable Found', variable, value);
+                    url = url.replace(templatedString, value);
+                  }
+                  else {
+                    module.verbose('Optional variable not found', variable);
+                    // remove preceding slash if set
+                    if(url.indexOf('/' + templatedString) !== -1) {
+                      url = url.replace('/' + templatedString, '');
+                    }
+                    else {
+                      url = url.replace(templatedString, '');
+                    }
+                  }
+                });
+              }
+            }
+            return url;
+          },
+          formData: function(data) {
+            var
+              canSerialize = ($.fn.serializeObject !== undefined),
+              formData     = (canSerialize)
+                ? $form.serializeObject()
+                : $form.serialize(),
+              hasOtherData
+            ;
+            data         = data || settings.data;
+            hasOtherData = $.isPlainObject(data);
+
+            if(hasOtherData) {
+              if(canSerialize) {
+                module.debug('Extending existing data with form data', data, formData);
+                data = $.extend(true, {}, data, formData);
+              }
+              else {
+                module.error(error.missingSerialize);
+                module.debug('Cant extend data. Replacing data with form data', data, formData);
+                data = formData;
+              }
+            }
+            else {
+              module.debug('Adding form data', formData);
+              data = formData;
+            }
+            return data;
+          }
+        },
+
+        send: {
+          request: function() {
+            module.set.loading();
+            module.request = module.create.request();
+            if( module.is.mocked() ) {
+              module.mockedXHR = module.create.mockedXHR();
+            }
+            else {
+              module.xhr = module.create.xhr();
+            }
+            settings.onRequest.call(context, module.request, module.xhr);
+          }
+        },
+
+        event: {
+          trigger: function(event) {
+            module.query();
+            if(event.type == 'submit' || event.type == 'click') {
+              event.preventDefault();
+            }
+          },
+          xhr: {
+            always: function() {
+              // calculate if loading time was below minimum threshold
+            },
+            done: function(response, textStatus, xhr) {
+              var
+                context      = this,
+                elapsedTime  = (new Date().getTime() - requestStartTime),
+                timeLeft     = (settings.loadingDuration - elapsedTime),
+                translatedResponse = ( $.isFunction(settings.onResponse) )
+                  ? settings.onResponse.call(context, $.extend(true, {}, response))
+                  : false
+              ;
+              timeLeft = (timeLeft > 0)
+                ? timeLeft
+                : 0
+              ;
+              if(translatedResponse) {
+                module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response);
+                response = translatedResponse;
+              }
+              if(timeLeft > 0) {
+                module.debug('Response completed early delaying state change by', timeLeft);
+              }
+              setTimeout(function() {
+                if( module.is.validResponse(response) ) {
+                  module.request.resolveWith(context, [response]);
+                }
+                else {
+                  module.request.rejectWith(context, [xhr, 'invalid']);
+                }
+              }, timeLeft);
+            },
+            fail: function(xhr, status, httpMessage) {
+              var
+                context     = this,
+                elapsedTime = (new Date().getTime() - requestStartTime),
+                timeLeft    = (settings.loadingDuration - elapsedTime)
+              ;
+              timeLeft = (timeLeft > 0)
+                ? timeLeft
+                : 0
+              ;
+              if(timeLeft > 0) {
+                module.debug('Response completed early delaying state change by', timeLeft);
+              }
+              setTimeout(function() {
+                if( module.is.abortedRequest(xhr) ) {
+                  module.request.rejectWith(context, [xhr, 'aborted', httpMessage]);
+                }
+                else {
+                  module.request.rejectWith(context, [xhr, 'error', status, httpMessage]);
+                }
+              }, timeLeft);
+            }
+          },
+          request: {
+            complete: function(response) {
+              module.remove.loading();
+              settings.onComplete.call(context, response, $module);
+            },
+            done: function(response) {
+              module.debug('Successful API Response', response);
+              if(settings.cache === 'local' && url) {
+                module.write.cachedResponse(url, response);
+                module.debug('Saving server response locally', module.cache);
+              }
+              settings.onSuccess.call(context, response, $module);
+            },
+            fail: function(xhr, status, httpMessage) {
+              var
+                // pull response from xhr if available
+                response = $.isPlainObject(xhr)
+                  ? (xhr.responseText)
+                  : false,
+                errorMessage = ($.isPlainObject(response) && response.error !== undefined)
+                  ? response.error // use json error message
+                  : (settings.error[status] !== undefined) // use server error message
+                    ? settings.error[status]
+                    : httpMessage
+              ;
+              if(status == 'aborted') {
+                module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage);
+                settings.onAbort.call(context, status, $module);
+              }
+              else if(status == 'invalid') {
+                module.debug('JSON did not pass success test. A server-side error has most likely occurred', response);
+              }
+              else if(status == 'error')  {
+
+                if(xhr !== undefined) {
+                  module.debug('XHR produced a server error', status, httpMessage);
+                  // make sure we have an error to display to console
+                  if( xhr.status != 200 && httpMessage !== undefined && httpMessage !== '') {
+                    module.error(error.statusMessage + httpMessage, ajaxSettings.url);
+                  }
+                  settings.onError.call(context, errorMessage, $module);
+                }
+              }
+
+              if(settings.errorDuration && status !== 'aborted') {
+                module.debug('Adding error state');
+                module.set.error();
+                setTimeout(module.remove.error, settings.errorDuration);
+              }
+              module.debug('API Request failed', errorMessage, xhr);
+              settings.onFailure.call(context, response, $module);
+            }
+          }
+        },
+
+        create: {
+
+          request: function() {
+            // api request promise
+            return $.Deferred()
+              .always(module.event.request.complete)
+              .done(module.event.request.done)
+              .fail(module.event.request.fail)
+            ;
+          },
+
+          mockedXHR: function () {
+            var
+              // xhr does not simulate these properties of xhr but must return them
+              textStatus  = false,
+              status      = false,
+              httpMessage = false,
+              asyncCallback,
+              response,
+              mockedXHR
+            ;
+
+            mockedXHR = $.Deferred()
+              .always(module.event.xhr.complete)
+              .done(module.event.xhr.done)
+              .fail(module.event.xhr.fail)
+            ;
+
+            if(settings.mockResponse) {
+              if( $.isFunction(settings.mockResponse) ) {
+                module.debug('Using mocked callback returning response', settings.mockResponse);
+                response = settings.mockResponse.call(context, settings);
+              }
+              else {
+                module.debug('Using specified response', settings.mockResponse);
+                response = settings.mockResponse;
+              }
+              // simulating response
+              mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
+            }
+            else if( $.isFunction(settings.mockResponseAsync) ) {
+              asyncCallback = function(response) {
+                module.debug('Async callback returned response', response);
+
+                if(response) {
+                  mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
+                }
+                else {
+                  mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]);
+                }
+              };
+              module.debug('Using async mocked response', settings.mockResponseAsync);
+              settings.mockResponseAsync.call(context, settings, asyncCallback);
+            }
+            return mockedXHR;
+          },
+
+          xhr: function() {
+            var
+              xhr
+            ;
+            // ajax request promise
+            xhr = $.ajax(ajaxSettings)
+              .always(module.event.xhr.always)
+              .done(module.event.xhr.done)
+              .fail(module.event.xhr.fail)
+            ;
+            module.verbose('Created server request', xhr);
+            return xhr;
+          }
+        },
+
+        set: {
+          error: function() {
+            module.verbose('Adding error state to element', $context);
+            $context.addClass(className.error);
+          },
+          loading: function() {
+            module.verbose('Adding loading state to element', $context);
+            $context.addClass(className.loading);
+            requestStartTime = new Date().getTime();
+          }
+        },
+
+        remove: {
+          error: function() {
+            module.verbose('Removing error state from element', $context);
+            $context.removeClass(className.error);
+          },
+          loading: function() {
+            module.verbose('Removing loading state from element', $context);
+            $context.removeClass(className.loading);
+          }
+        },
+
+        get: {
+          request: function() {
+            return module.request || false;
+          },
+          xhr: function() {
+            return module.xhr || false;
+          },
+          settings: function() {
+            var
+              runSettings
+            ;
+            runSettings = settings.beforeSend.call(context, settings);
+            if(runSettings) {
+              if(runSettings.success !== undefined) {
+                module.debug('Legacy success callback detected', runSettings);
+                module.error(error.legacyParameters, runSettings.success);
+                runSettings.onSuccess = runSettings.success;
+              }
+              if(runSettings.failure !== undefined) {
+                module.debug('Legacy failure callback detected', runSettings);
+                module.error(error.legacyParameters, runSettings.failure);
+                runSettings.onFailure = runSettings.failure;
+              }
+              if(runSettings.complete !== undefined) {
+                module.debug('Legacy complete callback detected', runSettings);
+                module.error(error.legacyParameters, runSettings.complete);
+                runSettings.onComplete = runSettings.complete;
+              }
+            }
+            if(runSettings === undefined) {
+              module.error(error.noReturnedValue);
+            }
+            return (runSettings !== undefined)
+              ? runSettings
+              : settings
+            ;
+          },
+          defaultData: function() {
+            var
+              data = {}
+            ;
+            if( !$.isWindow(element) ) {
+              if( module.is.input() ) {
+                data.value = $module.val();
+              }
+              else if( !module.is.form() ) {
+
+              }
+              else {
+                data.text = $module.text();
+              }
+            }
+            return data;
+          },
+          event: function() {
+            if( $.isWindow(element) || settings.on == 'now' ) {
+              module.debug('API called without element, no events attached');
+              return false;
+            }
+            else if(settings.on == 'auto') {
+              if( $module.is('input') ) {
+                return (element.oninput !== undefined)
+                  ? 'input'
+                  : (element.onpropertychange !== undefined)
+                    ? 'propertychange'
+                    : 'keyup'
+                ;
+              }
+              else if( $module.is('form') ) {
+                return 'submit';
+              }
+              else {
+                return 'click';
+              }
+            }
+            else {
+              return settings.on;
+            }
+          },
+          templatedURL: function(action) {
+            action = action || $module.data(metadata.action) || settings.action || false;
+            url    = $module.data(metadata.url) || settings.url || false;
+            if(url) {
+              module.debug('Using specified url', url);
+              return url;
+            }
+            if(action) {
+              module.debug('Looking up url for action', action, settings.api);
+              if(settings.api[action] === undefined && !module.is.mocked()) {
+                module.error(error.missingAction, settings.action, settings.api);
+                return;
+              }
+              url = settings.api[action];
+            }
+            else if( module.is.form() ) {
+              url = $module.attr('action') || false;
+              module.debug('No url or action specified, defaulting to form action', url);
+            }
+            return url;
+          }
+        },
+
+        abort: function() {
+          var
+            xhr = module.get.xhr()
+          ;
+          if( xhr && xhr.state() !== 'resolved') {
+            module.debug('Cancelling API request');
+            xhr.abort();
+          }
+        },
+
+        // reset state
+        reset: function() {
+          module.remove.error();
+          module.remove.loading();
+        },
+
+        setting: function(name, value) {
+          module.debug('Changing setting', name, value);
+          if( $.isPlainObject(name) ) {
+            $.extend(true, settings, name);
+          }
+          else if(value !== undefined) {
+            settings[name] = value;
+          }
+          else {
+            return settings[name];
+          }
+        },
+        internal: function(name, value) {
+          if( $.isPlainObject(name) ) {
+            $.extend(true, module, name);
+          }
+          else if(value !== undefined) {
+            module[name] = value;
+          }
+          else {
+            return module[name];
+          }
+        },
+        debug: function() {
+          if(settings.debug) {
+            if(settings.performance) {
+              module.performance.log(arguments);
+            }
+            else {
+              module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
+              module.debug.apply(console, arguments);
+            }
+          }
+        },
+        verbose: function() {
+          if(settings.verbose && settings.debug) {
+            if(settings.performance) {
+              module.performance.log(arguments);
+            }
+            else {
+              module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
+              module.verbose.apply(console, arguments);
+            }
+          }
+        },
+        error: function() {
+          module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
+          module.error.apply(console, arguments);
+        },
+        performance: {
+          log: function(message) {
+            var
+              currentTime,
+              executionTime,
+              previousTime
+            ;
+            if(settings.performance) {
+              currentTime   = new Date().getTime();
+              previousTime  = time || currentTime;
+              executionTime = currentTime - previousTime;
+              time          = currentTime;
+              performance.push({
+                'Name'           : message[0],
+                'Arguments'      : [].slice.call(message, 1) || '',
+                //'Element'        : element,
+                'Execution Time' : executionTime
+              });
+            }
+            clearTimeout(module.performance.timer);
+            module.performance.timer = setTimeout(module.performance.display, 500);
+          },
+          display: function() {
+            var
+              title = settings.name + ':',
+              totalTime = 0
+            ;
+            time = false;
+            clearTimeout(module.performance.timer);
+            $.each(performance, function(index, data) {
+              totalTime += data['Execution Time'];
+            });
+            title += ' ' + totalTime + 'ms';
+            if(moduleSelector) {
+              title += ' \'' + moduleSelector + '\'';
+            }
+            if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
+              console.groupCollapsed(title);
+              if(console.table) {
+                console.table(performance);
+              }
+              else {
+                $.each(performance, function(index, data) {
+                  console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
+                });
+              }
+              console.groupEnd();
+            }
+            performance = [];
+          }
+        },
+        invoke: function(query, passedArguments, context) {
+          var
+            object = instance,
+            maxDepth,
+            found,
+            response
+          ;
+          passedArguments = passedArguments || queryArguments;
+          context         = element         || context;
+          if(typeof query == 'string' && object !== undefined) {
+            query    = query.split(/[\. ]/);
+            maxDepth = query.length - 1;
+            $.each(query, function(depth, value) {
+              var camelCaseValue = (depth != maxDepth)
+                ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
+                : query
+              ;
+              if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
+                object = object[camelCaseValue];
+              }
+              else if( object[camelCaseValue] !== undefined ) {
+                found = object[camelCaseValue];
+                return false;
+              }
+              else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
+                object = object[value];
+              }
+              else if( object[value] !== undefined ) {
+                found = object[value];
+                return false;
+              }
+              else {
+                module.error(error.method, query);
+                return false;
+              }
+            });
+          }
+          if ( $.isFunction( found ) ) {
+            response = found.apply(context, passedArguments);
+          }
+          else if(found !== undefined) {
+            response = found;
+          }
+          if($.isArray(returnedValue)) {
+            returnedValue.push(response);
+          }
+          else if(returnedValue !== undefined) {
+            returnedValue = [returnedValue, response];
+          }
+          else if(response !== undefined) {
+            returnedValue = response;
+          }
+          return found;
+        }
+      };
+
+      if(methodInvoked) {
+        if(instance === undefined) {
+          module.initialize();
+        }
+        module.invoke(query);
+      }
+      else {
+        if(instance !== undefined) {
+          instance.invoke('destroy');
+        }
+        module.initialize();
+      }
+    })
+  ;
+
+  return (returnedValue !== undefined)
+    ? returnedValue
+    : this
+  ;
+};
+
+$.api.settings = {
+
+  name              : 'API',
+  namespace         : 'api',
+
+  debug             : true,
+  verbose           : false,
+  performance       : true,
+
+  // object containing all templates endpoints
+  api               : {},
+
+  // whether to cache responses
+  cache             : true,
+
+  // whether new requests should abort previous requests
+  interruptRequests : true,
+
+  // event binding
+  on                : 'auto',
+
+  // context for applying state classes
+  stateContext      : false,
+
+  // duration for loading state
+  loadingDuration   : 0,
+
+  // duration for error state
+  errorDuration     : 2000,
+
+  // API action to use
+  action            : false,
+
+  // templated URL to use
+  url               : false,
+
+  // base URL to apply to all endpoints
+  base              : '',
+
+  // data that will
+  urlData           : {},
+
+  // whether to add default data to url data
+  defaultData          : true,
+
+  // whether to serialize closest form
+  serializeForm        : false,
+
+  // how long to wait before request should occur
+  throttle             : 0,
+
+  // whether to throttle first request or only repeated
+  throttleFirstRequest : true,
+
+  // standard ajax settings
+  method            : 'get',
+  data              : {},
+  dataType          : 'json',
+
+  // mock response
+  mockResponse      : false,
+  mockResponseAsync : false,
+
+  // callbacks before request
+  beforeSend  : function(settings) { return settings; },
+  beforeXHR   : function(xhr) {},
+  onRequest   : function(promise, xhr) {},
+
+  // after request
+  onResponse  : false, // function(response) { },
+
+  // response was successful, if JSON passed validation
+  onSuccess   : function(response, $module) {},
+
+  // request finished without aborting
+  onComplete  : function(response, $module) {},
+
+  // failed JSON success test
+  onFailure   : function(response, $module) {},
+
+  // server error
+  onError     : function(errorMessage, $module) {},
+
+  // request aborted
+  onAbort     : function(errorMessage, $module) {},
+
+  successTest : false,
+
+  // errors
+  error : {
+    beforeSend        : 'The before send function has aborted the request',
+    error             : 'There was an error with your request',
+    exitConditions    : 'API Request Aborted. Exit conditions met',
+    JSONParse         : 'JSON could not be parsed during error handling',
+    legacyParameters  : 'You are using legacy API success callback names',
+    method            : 'The method you called is not defined',
+    missingAction     : 'API action used but no url was defined',
+    missingSerialize  : 'jquery-serialize-object is required to add form data to an existing data object',
+    missingURL        : 'No URL specified for api event',
+    noReturnedValue   : 'The beforeSend callback must return a settings object, beforeSend ignored.',
+    noStorage         : 'Caching respopnses locally requires session storage',
+    parseError        : 'There was an error parsing your request',
+    requiredParameter : 'Missing a required URL parameter: ',
+    statusMessage     : 'Server gave an error: ',
+    timeout           : 'Your request timed out'
+  },
+
+  regExp  : {
+    required : /\{\$*[A-z0-9]+\}/g,
+    optional : /\{\/\$*[A-z0-9]+\}/g,
+  },
+
+  className: {
+    loading : 'loading',
+    error   : 'error'
+  },
+
+  selector: {
+    disabled : '.disabled',
+    form      : 'form'
+  },
+
+  metadata: {
+    action  : 'action',
+    url     : 'url'
+  }
+};
+
+
+
+})( jQuery, window , document );

Разница между файлами не показана из-за своего большого размера
+ 10 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/api.min.js


+ 125 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/breadcrumb.css

@@ -0,0 +1,125 @@
+/*!
+ * # Semantic UI 2.0.0 - Breadcrumb
+ * http://github.com/semantic-org/semantic-ui/
+ *
+ *
+ * Copyright 2015 Contributors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ */
+
+
+/*******************************
+           Breadcrumb
+*******************************/
+
+.ui.breadcrumb {
+  line-height: 1;
+  margin: 1em 0em;
+  display: inline-block;
+  vertical-align: middle;
+}
+.ui.breadcrumb:first-child {
+  margin-top: 0em;
+}
+.ui.breadcrumb:last-child {
+  margin-bottom: 0em;
+}
+
+
+/*******************************
+          Content
+*******************************/
+
+
+/* Divider */
+.ui.breadcrumb .divider {
+  display: inline-block;
+  opacity: 0.7;
+  margin: 0em 0.21428571rem 0em;
+  font-size: 0.92857143em;
+  color: rgba(0, 0, 0, 0.4);
+  vertical-align: baseline;
+}
+
+/* Link */
+.ui.breadcrumb a {
+  color: #4183c4;
+}
+.ui.breadcrumb a:hover {
+  color: #1e70bf;
+}
+
+/* Icon Divider */
+.ui.breadcrumb .icon.divider {
+  font-size: 0.85714286em;
+  vertical-align: baseline;
+}
+
+/* Section */
+.ui.breadcrumb a.section {
+  cursor: pointer;
+}
+.ui.breadcrumb .section {
+  display: inline-block;
+  margin: 0em;
+  padding: 0em;
+}
+
+/* Loose Coupling */
+.ui.breadcrumb.segment {
+  display: inline-block;
+  padding: 0.71428571em 1em;
+}
+
+
+/*******************************
+            States
+*******************************/
+
+.ui.breadcrumb .active.section {
+  font-weight: bold;
+}
+
+
+/*******************************
+           Variations
+*******************************/
+
+.ui.mini.breadcrumb {
+  font-size: 0.71428571rem;
+}
+.ui.tiny.breadcrumb {
+  font-size: 0.85714286rem;
+}
+.ui.small.breadcrumb {
+  font-size: 0.92857143rem;
+}
+.ui.breadcrumb {
+  font-size: 1rem;
+}
+.ui.large.breadcrumb {
+  font-size: 1.14285714rem;
+}
+.ui.big.breadcrumb {
+  font-size: 1.28571429rem;
+}
+.ui.huge.breadcrumb {
+  font-size: 1.42857143rem;
+}
+.ui.massive.breadcrumb {
+  font-size: 1.71428571rem;
+}
+
+
+/*******************************
+         Theme Overrides
+*******************************/
+
+
+
+/*******************************
+         Site Overrides
+*******************************/
+

+ 10 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/breadcrumb.min.css

@@ -0,0 +1,10 @@
+/*!
+ * # Semantic UI 2.0.0 - Breadcrumb
+ * http://github.com/semantic-org/semantic-ui/
+ *
+ *
+ * Copyright 2015 Contributors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ */.ui.breadcrumb{line-height:1;margin:1em 0;display:inline-block;vertical-align:middle}.ui.breadcrumb:first-child{margin-top:0}.ui.breadcrumb:last-child{margin-bottom:0}.ui.breadcrumb .divider{display:inline-block;opacity:.7;margin:0 .21428571rem;font-size:.92857143em;color:rgba(0,0,0,.4);vertical-align:baseline}.ui.breadcrumb a{color:#4183c4}.ui.breadcrumb a:hover{color:#1e70bf}.ui.breadcrumb .icon.divider{font-size:.85714286em;vertical-align:baseline}.ui.breadcrumb a.section{cursor:pointer}.ui.breadcrumb .section{display:inline-block;margin:0;padding:0}.ui.breadcrumb.segment{display:inline-block;padding:.71428571em 1em}.ui.breadcrumb .active.section{font-weight:700}.ui.mini.breadcrumb{font-size:.71428571rem}.ui.tiny.breadcrumb{font-size:.85714286rem}.ui.small.breadcrumb{font-size:.92857143rem}.ui.breadcrumb{font-size:1rem}.ui.large.breadcrumb{font-size:1.14285714rem}.ui.big.breadcrumb{font-size:1.28571429rem}.ui.huge.breadcrumb{font-size:1.42857143rem}.ui.massive.breadcrumb{font-size:1.71428571rem}

+ 3237 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/button.css

@@ -0,0 +1,3237 @@
+/*!
+ * # Semantic UI 2.0.0 - Button
+ * http://github.com/semantic-org/semantic-ui/
+ *
+ *
+ * Copyright 2015 Contributors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ */
+
+
+/*******************************
+            Button
+*******************************/
+
+.ui.button {
+  cursor: pointer;
+  display: inline-block;
+  min-height: 1em;
+  outline: none;
+  border: none;
+  vertical-align: baseline;
+  background: #e0e1e2 none;
+  color: rgba(0, 0, 0, 0.6);
+  font-family: 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif;
+  margin: 0em 0.25em 0em 0em;
+  padding: 0.78571429em 1.5em 0.78571429em;
+  text-transform: none;
+  text-shadow: none;
+  font-weight: bold;
+  line-height: 1em;
+  font-style: normal;
+  text-align: center;
+  text-decoration: none;
+  border-radius: 0.28571429rem;
+  box-shadow: 0px 0px 0px 1px transparent inset, 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-transition: opacity 0.1s ease, background-color 0.1s ease, color 0.1s ease, box-shadow 0.1s ease, background 0.1s ease;
+          transition: opacity 0.1s ease, background-color 0.1s ease, color 0.1s ease, box-shadow 0.1s ease, background 0.1s ease;
+  will-change: '';
+  -webkit-tap-highlight-color: transparent;
+}
+
+
+/*******************************
+            States
+*******************************/
+
+
+/*--------------
+      Hover
+---------------*/
+
+.ui.button:hover {
+  background-color: #cacbcd;
+  background-image: none;
+  box-shadow: 0px 0px 0px 1px transparent inset, 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+  color: rgba(0, 0, 0, 0.8);
+}
+.ui.button:hover .icon {
+  opacity: 0.85;
+}
+
+/*--------------
+      Focus
+---------------*/
+
+.ui.button:focus {
+  background-color: #cacbcd;
+  color: rgba(0, 0, 0, 0.8);
+  background-image: '' !important;
+  box-shadow: '' !important;
+}
+.ui.button:focus .icon {
+  opacity: 0.85;
+}
+
+/*--------------
+      Down
+---------------*/
+
+.ui.button:active,
+.ui.active.button:active {
+  background-color: #babbbc;
+  background-image: '';
+  color: rgba(0, 0, 0, 0.9);
+  box-shadow: 0px 0px 0px 1px transparent inset, none;
+}
+
+/*--------------
+     Active
+---------------*/
+
+.ui.active.button {
+  background-color: #c0c1c2;
+  background-image: none;
+  box-shadow: 0px 0px 0px 1px transparent inset;
+  color: rgba(0, 0, 0, 0.95);
+}
+.ui.active.button:hover {
+  background-color: #c0c1c2;
+  background-image: none;
+  color: rgba(0, 0, 0, 0.95);
+}
+.ui.active.button:active {
+  background-color: #c0c1c2;
+  background-image: none;
+}
+
+/*--------------
+    Loading
+---------------*/
+
+
+/* Specificity hack */
+.ui.loading.loading.loading.loading.loading.loading.button {
+  position: relative;
+  cursor: default;
+  text-shadow: none !important;
+  color: transparent !important;
+  opacity: 1;
+  pointer-events: auto;
+  -webkit-transition: all 0s linear, opacity 0.1s ease;
+          transition: all 0s linear, opacity 0.1s ease;
+}
+.ui.loading.button:before {
+  position: absolute;
+  content: '';
+  top: 50%;
+  left: 50%;
+  margin: -0.64285714em 0em 0em -0.64285714em;
+  width: 1.28571429em;
+  height: 1.28571429em;
+  border-radius: 500rem;
+  border: 0.2em solid rgba(0, 0, 0, 0.15);
+}
+.ui.loading.button:after {
+  position: absolute;
+  content: '';
+  top: 50%;
+  left: 50%;
+  margin: -0.64285714em 0em 0em -0.64285714em;
+  width: 1.28571429em;
+  height: 1.28571429em;
+  -webkit-animation: button-spin 0.6s linear;
+          animation: button-spin 0.6s linear;
+  -webkit-animation-iteration-count: infinite;
+          animation-iteration-count: infinite;
+  border-radius: 500rem;
+  border-color: #ffffff transparent transparent;
+  border-style: solid;
+  border-width: 0.2em;
+  box-shadow: 0px 0px 0px 1px transparent;
+}
+.ui.labeled.icon.loading.button .icon {
+  background-color: transparent;
+  box-shadow: none;
+}
+@-webkit-keyframes button-spin {
+  from {
+    -webkit-transform: rotate(0deg);
+            transform: rotate(0deg);
+  }
+  to {
+    -webkit-transform: rotate(360deg);
+            transform: rotate(360deg);
+  }
+}
+@keyframes button-spin {
+  from {
+    -webkit-transform: rotate(0deg);
+            transform: rotate(0deg);
+  }
+  to {
+    -webkit-transform: rotate(360deg);
+            transform: rotate(360deg);
+  }
+}
+.ui.basic.loading.button:not(.inverted):before {
+  border-color: rgba(0, 0, 0, 0.1);
+}
+.ui.basic.loading.button:not(.inverted):after {
+  border-top-color: #767676;
+}
+
+/*-------------------
+      Disabled
+--------------------*/
+
+.ui.buttons .disabled.button,
+.ui.disabled.button,
+.ui.button:disabled,
+.ui.disabled.button:hover,
+.ui.disabled.active.button {
+  cursor: default;
+  opacity: 0.45 !important;
+  background-image: none !important;
+  box-shadow: none !important;
+  pointer-events: none;
+}
+
+/* Basic Group With Disabled */
+.ui.basic.buttons .ui.disabled.button {
+  border-color: rgba(34, 36, 38, 0.5);
+}
+
+
+/*******************************
+             Types
+*******************************/
+
+
+/*-------------------
+       Animated
+--------------------*/
+
+.ui.animated.button {
+  position: relative;
+  overflow: hidden;
+  padding-right: 0em !important;
+  vertical-align: middle;
+  z-index: 1;
+}
+.ui.animated.button .content {
+  will-change: transform, opacity;
+}
+.ui.animated.button .visible.content {
+  position: relative;
+  margin-right: 1.5em;
+}
+.ui.animated.button .hidden.content {
+  position: absolute;
+  width: 100%;
+}
+
+/* Horizontal */
+.ui.animated.button .visible.content,
+.ui.animated.button .hidden.content {
+  -webkit-transition: right 0.3s ease 0s;
+          transition: right 0.3s ease 0s;
+}
+.ui.animated.button .visible.content {
+  left: auto;
+  right: 0%;
+}
+.ui.animated.button .hidden.content {
+  top: 50%;
+  left: auto;
+  right: -100%;
+  margin-top: -0.5em;
+}
+.ui.animated.button:focus .visible.content,
+.ui.animated.button:hover .visible.content {
+  left: auto;
+  right: 200%;
+}
+.ui.animated.button:focus .hidden.content,
+.ui.animated.button:hover .hidden.content {
+  left: auto;
+  right: 0%;
+}
+
+/* Vertical */
+.ui.vertical.animated.button .visible.content,
+.ui.vertical.animated.button .hidden.content {
+  -webkit-transition: top 0.3s ease, -webkit-transform 0.3s ease;
+          transition: top 0.3s ease, transform 0.3s ease;
+}
+.ui.vertical.animated.button .visible.content {
+  -webkit-transform: translateY(0%);
+      -ms-transform: translateY(0%);
+          transform: translateY(0%);
+  right: auto;
+}
+.ui.vertical.animated.button .hidden.content {
+  top: -50%;
+  left: 0%;
+  right: auto;
+}
+.ui.vertical.animated.button:focus .visible.content,
+.ui.vertical.animated.button:hover .visible.content {
+  -webkit-transform: translateY(200%);
+      -ms-transform: translateY(200%);
+          transform: translateY(200%);
+  right: auto;
+}
+.ui.vertical.animated.button:focus .hidden.content,
+.ui.vertical.animated.button:hover .hidden.content {
+  top: 50%;
+  right: auto;
+}
+
+/* Fade */
+.ui.fade.animated.button .visible.content,
+.ui.fade.animated.button .hidden.content {
+  -webkit-transition: opacity 0.3s ease, -webkit-transform 0.3s ease;
+          transition: opacity 0.3s ease, transform 0.3s ease;
+}
+.ui.fade.animated.button .visible.content {
+  left: auto;
+  right: auto;
+  opacity: 1;
+  -webkit-transform: scale(1);
+      -ms-transform: scale(1);
+          transform: scale(1);
+}
+.ui.fade.animated.button .hidden.content {
+  opacity: 0;
+  left: 0%;
+  right: auto;
+  -webkit-transform: scale(1.5);
+      -ms-transform: scale(1.5);
+          transform: scale(1.5);
+}
+.ui.fade.animated.button:focus .visible.content,
+.ui.fade.animated.button:hover .visible.content {
+  left: auto;
+  right: auto;
+  opacity: 0;
+  -webkit-transform: scale(0.75);
+      -ms-transform: scale(0.75);
+          transform: scale(0.75);
+}
+.ui.fade.animated.button:focus .hidden.content,
+.ui.fade.animated.button:hover .hidden.content {
+  left: 0%;
+  right: auto;
+  opacity: 1;
+  -webkit-transform: scale(1);
+      -ms-transform: scale(1);
+          transform: scale(1);
+}
+
+/*-------------------
+       Inverted
+--------------------*/
+
+.ui.inverted.button {
+  box-shadow: 0px 0px 0px 2px #ffffff inset !important;
+  background: transparent none;
+  color: #ffffff;
+  text-shadow: none !important;
+}
+
+/* Group */
+.ui.inverted.buttons .button {
+  margin: 0px 0px 0px -2px;
+}
+.ui.inverted.buttons .button:first-child {
+  margin-left: 0em;
+}
+.ui.inverted.vertical.buttons .button {
+  margin: 0px 0px -2px 0px;
+}
+.ui.inverted.vertical.buttons .button:first-child {
+  margin-top: 0em;
+}
+
+/* States */
+.ui.inverted.button:hover {
+  background: #ffffff;
+  box-shadow: 0px 0px 0px 2px #ffffff inset !important;
+  color: rgba(0, 0, 0, 0.8);
+}
+.ui.inverted.button:focus {
+  background: #ffffff;
+  box-shadow: 0px 0px 0px 2px #ffffff inset !important;
+  color: rgba(0, 0, 0, 0.8);
+}
+
+/*-------------------
+       Social
+--------------------*/
+
+
+/* Facebook */
+.ui.facebook.button {
+  background-color: #3b5998;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.facebook.button:hover {
+  background-color: #304d8a;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.facebook.button:active {
+  background-color: #2d4373;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Twitter */
+.ui.twitter.button {
+  background-color: #0084b4;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.twitter.button:hover {
+  background-color: #00719b;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.twitter.button:active {
+  background-color: #005f81;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Google Plus */
+.ui.google.plus.button {
+  background-color: #dc4a38;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.google.plus.button:hover {
+  background-color: #de321d;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.google.plus.button:active {
+  background-color: #bf3322;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Linked In */
+.ui.linkedin.button {
+  background-color: #1f88be;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.linkedin.button:hover {
+  background-color: #147baf;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.linkedin.button:active {
+  background-color: #186992;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* YouTube */
+.ui.youtube.button {
+  background-color: #cc181e;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.youtube.button:hover {
+  background-color: #bd0d13;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.youtube.button:active {
+  background-color: #9e1317;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Instagram */
+.ui.instagram.button {
+  background-color: #49769c;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.instagram.button:hover {
+  background-color: #3d698e;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.instagram.button:active {
+  background-color: #395c79;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Pinterest */
+.ui.pinterest.button {
+  background-color: #00aced;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.pinterest.button:hover {
+  background-color: #0099d4;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.pinterest.button:active {
+  background-color: #0087ba;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* VK */
+.ui.vk.button {
+  background-color: #4D7198;
+  color: #ffffff;
+  background-image: none;
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.vk.button:hover {
+  background-color: #41648a;
+  color: #ffffff;
+}
+.ui.vk.button:active {
+  background-color: #3c5876;
+  color: #ffffff;
+}
+
+/*--------------
+     Icon
+---------------*/
+
+.ui.button > .icon {
+  height: 0.92857143em;
+  opacity: 0.8;
+  margin: 0em 0.42857143em 0em -0.21428571em;
+  -webkit-transition: opacity 0.1s ease;
+          transition: opacity 0.1s ease;
+  vertical-align: '';
+  color: '';
+}
+.ui.button > .right.icon {
+  margin: 0em -0.21428571em 0em 0.42857143em;
+}
+
+
+/*******************************
+           Variations
+*******************************/
+
+
+/*-------------------
+       Floated
+--------------------*/
+
+.ui[class*="left floated"].buttons,
+.ui[class*="left floated"].button {
+  float: left;
+  margin-left: 0em;
+  margin-right: 0.25em;
+}
+.ui[class*="right floated"].buttons,
+.ui[class*="right floated"].button {
+  float: right;
+  margin-right: 0em;
+  margin-left: 0.25em;
+}
+
+/*-------------------
+       Compact
+--------------------*/
+
+.ui.compact.buttons .button,
+.ui.compact.button {
+  padding: 0.58928571em 1.125em 0.58928571em;
+}
+.ui.compact.icon.buttons .button,
+.ui.compact.icon.button {
+  padding: 0.58928571em 0.58928571em 0.58928571em;
+}
+.ui.compact.labeled.icon.buttons .button,
+.ui.compact.labeled.icon.button {
+  padding: 0.58928571em 3.69642857em 0.58928571em;
+}
+
+/*-------------------
+        Sizes
+--------------------*/
+
+.ui.mini.buttons .button,
+.ui.mini.buttons .or,
+.ui.mini.button {
+  font-size: 0.71428571rem;
+}
+.ui.tiny.buttons .button,
+.ui.tiny.buttons .or,
+.ui.tiny.button {
+  font-size: 0.85714286rem;
+}
+.ui.small.buttons .button,
+.ui.small.buttons .or,
+.ui.small.button {
+  font-size: 0.92857143rem;
+}
+.ui.buttons .button,
+.ui.buttons .or,
+.ui.button {
+  font-size: 1rem;
+}
+.ui.large.buttons .button,
+.ui.large.buttons .or,
+.ui.large.button {
+  font-size: 1.14285714rem;
+}
+.ui.big.buttons .button,
+.ui.big.buttons .or,
+.ui.big.button {
+  font-size: 1.28571429rem;
+}
+.ui.huge.buttons .button,
+.ui.huge.buttons .or,
+.ui.huge.button {
+  font-size: 1.42857143rem;
+}
+.ui.massive.buttons .button,
+.ui.massive.buttons .or,
+.ui.massive.button {
+  font-size: 1.71428571rem;
+}
+
+/*--------------
+    Icon Only
+---------------*/
+
+.ui.icon.buttons .button,
+.ui.icon.button {
+  padding: 0.78571429em 0.78571429em 0.78571429em;
+}
+.ui.icon.buttons .button > .icon,
+.ui.icon.button > .icon {
+  opacity: 0.9;
+  margin: 0em;
+  vertical-align: top;
+}
+
+/*-------------------
+        Basic
+--------------------*/
+
+.ui.basic.buttons .button,
+.ui.basic.button {
+  background: transparent none !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+  font-weight: normal;
+  border-radius: 0.28571429rem;
+  text-transform: none;
+  text-shadow: none !important;
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.basic.buttons {
+  box-shadow: none;
+  border: 1px solid rgba(34, 36, 38, 0.15);
+  border-radius: 0.28571429rem;
+}
+.ui.basic.buttons .button {
+  border-radius: 0em;
+}
+.ui.basic.buttons .button:hover,
+.ui.basic.button:hover {
+  background: #ffffff !important;
+  color: rgba(0, 0, 0, 0.8) !important;
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.35) inset, 0px 0px 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.basic.buttons .button:focus,
+.ui.basic.button:focus {
+  background: #ffffff !important;
+  color: rgba(0, 0, 0, 0.8) !important;
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.35) inset, 0px 0px 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.basic.buttons .button:active,
+.ui.basic.button:active {
+  background: #f8f8f8 !important;
+  color: rgba(0, 0, 0, 0.9) !important;
+  box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.15) inset, 0px 1px 4px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.basic.buttons .active.button,
+.ui.basic.active.button {
+  background: rgba(0, 0, 0, 0.05) !important;
+  box-shadow: '' !important;
+  color: rgba(0, 0, 0, 0.95);
+  box-shadow: rgba(34, 36, 38, 0.35);
+}
+.ui.basic.buttons .active.button:hover,
+.ui.basic.active.button:hover {
+  background-color: rgba(0, 0, 0, 0.05);
+}
+
+/* Vertical */
+.ui.basic.buttons .button:hover {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.35) inset, 0px 0px 0px 0px rgba(34, 36, 38, 0.15) inset inset;
+}
+.ui.basic.buttons .button:active {
+  box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.15) inset, 0px 1px 4px 0px rgba(34, 36, 38, 0.15) inset inset;
+}
+.ui.basic.buttons .active.button {
+  box-shadow: rgba(34, 36, 38, 0.35) inset;
+}
+
+/* Standard Basic Inverted */
+.ui.basic.inverted.buttons .button,
+.ui.basic.inverted.button {
+  background-color: transparent !important;
+  color: #f9fafb !important;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+}
+.ui.basic.inverted.buttons .button:hover,
+.ui.basic.inverted.button:hover {
+  color: #ffffff !important;
+  box-shadow: 0px 0px 0px 2px #ffffff inset !important;
+}
+.ui.basic.inverted.buttons .button:focus,
+.ui.basic.inverted.button:focus {
+  color: #ffffff !important;
+  box-shadow: 0px 0px 0px 2px #ffffff inset !important;
+}
+.ui.basic.inverted.buttons .button:active,
+.ui.basic.inverted.button:active {
+  background-color: rgba(255, 255, 255, 0.08) !important;
+  color: #ffffff !important;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.9) inset !important;
+}
+.ui.basic.inverted.buttons .active.button,
+.ui.basic.inverted.active.button {
+  background-color: rgba(255, 255, 255, 0.08);
+  color: #ffffff;
+  text-shadow: none;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.7) inset;
+}
+.ui.basic.inverted.buttons .active.button:hover,
+.ui.basic.inverted.active.button:hover {
+  background-color: rgba(255, 255, 255, 0.15);
+  box-shadow: 0px 0px 0px 2px #ffffff inset !important;
+}
+
+/* Basic Group */
+.ui.basic.buttons .button {
+  border-left: 1px solid rgba(34, 36, 38, 0.15);
+  box-shadow: none;
+}
+.ui.basic.vertical.buttons .button {
+  border-left: none;
+}
+.ui.basic.vertical.buttons .button {
+  border-left-width: 0px;
+  border-top: 1px solid rgba(34, 36, 38, 0.15);
+}
+.ui.basic.vertical.buttons .button:first-child {
+  border-top-width: 0px;
+}
+
+/*--------------
+  Labeled Icon
+---------------*/
+
+.ui.labeled.icon.buttons .button,
+.ui.labeled.icon.button {
+  position: relative;
+  padding-left: 4.07142857em !important;
+  padding-right: 1.5em !important;
+}
+
+/* Left Labeled */
+.ui.labeled.icon.buttons > .button > .icon,
+.ui.labeled.icon.button > .icon {
+  position: absolute;
+  height: 100%;
+  line-height: 1;
+  width: 2.57142857em;
+  background-color: rgba(0, 0, 0, 0.05);
+  text-align: center;
+  color: '';
+  border-radius: 0.28571429rem 0px 0px 0.28571429rem;
+  box-shadow: -1px 0px 0px 0px transparent inset;
+}
+
+/* Left Labeled */
+.ui.labeled.icon.buttons > .button > .icon,
+.ui.labeled.icon.button > .icon {
+  top: 0em;
+  left: 0em;
+}
+
+/* Right Labeled */
+.ui[class*="right labeled"].icon.button {
+  padding-right: 4.07142857em !important;
+  padding-left: 1.5em !important;
+}
+.ui[class*="right labeled"].icon.button > .icon {
+  left: auto;
+  right: 0em;
+  border-radius: 0em 0.28571429rem 0.28571429rem 0em;
+  box-shadow: 1px 0px 0px 0px transparent inset;
+}
+.ui.labeled.icon.buttons > .button > .icon:before,
+.ui.labeled.icon.button > .icon:before,
+.ui.labeled.icon.buttons > .button > .icon:after,
+.ui.labeled.icon.button > .icon:after {
+  display: block;
+  position: absolute;
+  width: 100%;
+  top: 50%;
+  text-align: center;
+  margin-top: -0.5em;
+}
+.ui.labeled.icon.buttons .button > .icon {
+  border-radius: 0em;
+}
+.ui.labeled.icon.buttons .button:first-child > .icon {
+  border-top-left-radius: 0.28571429rem;
+  border-bottom-left-radius: 0.28571429rem;
+}
+.ui.labeled.icon.buttons .button:last-child > .icon {
+  border-top-right-radius: 0.28571429rem;
+  border-bottom-right-radius: 0.28571429rem;
+}
+.ui.vertical.labeled.icon.buttons .button:first-child > .icon {
+  border-radius: 0em;
+  border-top-left-radius: 0.28571429rem;
+}
+.ui.vertical.labeled.icon.buttons .button:last-child > .icon {
+  border-radius: 0em;
+  border-bottom-left-radius: 0.28571429rem;
+}
+
+/* Fluid Labeled */
+.ui.fluid[class*="left labeled"].icon.button,
+.ui.fluid[class*="right labeled"].icon.button {
+  padding-left: 1.5em !important;
+  padding-right: 1.5em !important;
+}
+
+/*--------------
+     Toggle
+---------------*/
+
+
+/* Toggle (Modifies active state to give affordances) */
+.ui.toggle.buttons .active.button,
+.ui.buttons .button.toggle.active,
+.ui.button.toggle.active {
+  background-color: #21ba45 !important;
+  box-shadow: none !important;
+  text-shadow: none;
+  color: #ffffff !important;
+}
+.ui.button.toggle.active:hover {
+  background-color: #16ab39 !important;
+  text-shadow: none;
+  color: #ffffff !important;
+}
+
+/*--------------
+    Circular
+---------------*/
+
+.ui.circular.button {
+  border-radius: 10em;
+}
+.ui.circular.button > .icon {
+  width: 1em;
+  vertical-align: baseline;
+}
+
+/*-------------------
+      Or Buttons
+--------------------*/
+
+.ui.buttons .or {
+  position: relative;
+  width: 0.3em;
+  height: 2.57142857em;
+  z-index: 3;
+}
+.ui.buttons .or:before {
+  position: absolute;
+  text-align: center;
+  border-radius: 500rem;
+  content: 'or';
+  top: 50%;
+  left: 50%;
+  background-color: #ffffff;
+  text-shadow: none;
+  margin-top: -0.89285714em;
+  margin-left: -0.89285714em;
+  width: 1.78571429em;
+  height: 1.78571429em;
+  line-height: 1.78571429em;
+  color: rgba(0, 0, 0, 0.4);
+  font-style: normal;
+  font-weight: bold;
+  box-shadow: 0px 0px 0px 1px transparent inset;
+}
+.ui.buttons .or[data-text]:before {
+  content: attr(data-text);
+}
+
+/* Fluid Or */
+.ui.fluid.buttons .or {
+  width: 0em !important;
+}
+.ui.fluid.buttons .or:after {
+  display: none;
+}
+
+/*-------------------
+       Attached
+--------------------*/
+
+
+/* Singular */
+.ui.attached.button {
+  position: relative;
+  display: block;
+  margin: 0em;
+  border-radius: 0em;
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) !important;
+}
+
+/* Top / Bottom */
+.ui.attached.top.button {
+  border-radius: 0.28571429rem 0.28571429rem 0em 0em;
+}
+.ui.attached.bottom.button {
+  border-radius: 0em 0em 0.28571429rem 0.28571429rem;
+}
+
+/* Left / Right */
+.ui.left.attached.button {
+  display: inline-block;
+  border-left: none;
+  text-align: right;
+  padding-right: 0.75em;
+  border-radius: 0.28571429rem 0em 0em 0.28571429rem;
+}
+.ui.right.attached.button {
+  display: inline-block;
+  text-align: left;
+  padding-left: 0.75em;
+  border-radius: 0em 0.28571429rem 0.28571429rem 0em;
+}
+
+/* Plural */
+.ui.attached.buttons {
+  position: relative;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  border-radius: 0em;
+  width: auto !important;
+  z-index: 2;
+  margin-left: -1px;
+  margin-right: -1px;
+}
+.ui.attached.buttons .button {
+  margin: 0em;
+}
+.ui.attached.buttons .button:first-child {
+  border-radius: 0em;
+}
+.ui.attached.buttons .button:last-child {
+  border-radius: 0em;
+}
+
+/* Top / Bottom */
+.ui[class*="top attached"].buttons {
+  margin-bottom: -1px;
+  border-radius: 0.28571429rem 0.28571429rem 0em 0em;
+}
+.ui[class*="top attached"].buttons .button:first-child {
+  border-radius: 0.28571429rem 0em 0em 0em;
+}
+.ui[class*="top attached"].buttons .button:last-child {
+  border-radius: 0em 0.28571429rem 0em 0em;
+}
+.ui[class*="bottom attached"].buttons {
+  margin-top: -1px;
+  border-radius: 0em 0em 0.28571429rem 0.28571429rem;
+}
+.ui[class*="bottom attached"].buttons .button:first-child {
+  border-radius: 0em 0em 0em 0.28571429rem;
+}
+.ui[class*="bottom attached"].buttons .button:last-child {
+  border-radius: 0em 0em 0.28571429rem 0em;
+}
+
+/* Left / Right */
+.ui[class*="left attached"].buttons {
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  margin-right: 0em;
+  margin-left: -1px;
+  border-radius: 0em 0.28571429rem 0.28571429rem 0em;
+}
+.ui[class*="left attached"].buttons .button:first-child {
+  margin-left: -1px;
+  border-radius: 0em 0.28571429rem 0em 0em;
+}
+.ui[class*="left attached"].buttons .button:last-child {
+  margin-left: -1px;
+  border-radius: 0em 0em 0.28571429rem 0em;
+}
+.ui[class*="right attached"].buttons {
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  margin-left: 0em;
+  margin-right: -1px;
+  border-radius: 0.28571429rem 0em 0em 0.28571429rem;
+}
+.ui[class*="right attached"].buttons .button:first-child {
+  margin-left: -1px;
+  border-radius: 0.28571429rem 0em 0em 0em;
+}
+.ui[class*="right attached"].buttons .button:last-child {
+  margin-left: -1px;
+  border-radius: 0em 0em 0em 0.28571429rem;
+}
+
+/*-------------------
+        Fluid
+--------------------*/
+
+.ui.fluid.buttons,
+.ui.button.fluid {
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+      -ms-flex-pack: center;
+          justify-content: center;
+  -webkit-box-orient: horizontal;
+  -webkit-box-direction: normal;
+  -webkit-flex-direction: row;
+      -ms-flex-direction: row;
+          flex-direction: row;
+  width: 100%;
+}
+.ui.two.buttons {
+  width: 100%;
+}
+.ui.two.buttons > .button {
+  width: 50%;
+}
+.ui.three.buttons {
+  width: 100%;
+}
+.ui.three.buttons > .button {
+  width: 33.333%;
+}
+.ui.four.buttons {
+  width: 100%;
+}
+.ui.four.buttons > .button {
+  width: 25%;
+}
+.ui.five.buttons {
+  width: 100%;
+}
+.ui.five.buttons > .button {
+  width: 20%;
+}
+.ui.six.buttons {
+  width: 100%;
+}
+.ui.six.buttons > .button {
+  width: 16.666%;
+}
+.ui.seven.buttons {
+  width: 100%;
+}
+.ui.seven.buttons > .button {
+  width: 14.285%;
+}
+.ui.eight.buttons {
+  width: 100%;
+}
+.ui.eight.buttons > .button {
+  width: 12.500%;
+}
+.ui.nine.buttons {
+  width: 100%;
+}
+.ui.nine.buttons > .button {
+  width: 11.11%;
+}
+.ui.ten.buttons {
+  width: 100%;
+}
+.ui.ten.buttons > .button {
+  width: 10%;
+}
+.ui.eleven.buttons {
+  width: 100%;
+}
+.ui.eleven.buttons > .button {
+  width: 9.09%;
+}
+.ui.twelve.buttons {
+  width: 100%;
+}
+.ui.twelve.buttons > .button {
+  width: 8.3333%;
+}
+
+/* Fluid Vertical Buttons */
+.ui.fluid.vertical.buttons,
+.ui.fluid.vertical.buttons > .button {
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  width: auto;
+}
+.ui.two.vertical.buttons > .button {
+  height: 50%;
+}
+.ui.three.vertical.buttons > .button {
+  height: 33.333%;
+}
+.ui.four.vertical.buttons > .button {
+  height: 25%;
+}
+.ui.five.vertical.buttons > .button {
+  height: 20%;
+}
+.ui.six.vertical.buttons > .button {
+  height: 16.666%;
+}
+.ui.seven.vertical.buttons > .button {
+  height: 14.285%;
+}
+.ui.eight.vertical.buttons > .button {
+  height: 12.500%;
+}
+.ui.nine.vertical.buttons > .button {
+  height: 11.11%;
+}
+.ui.ten.vertical.buttons > .button {
+  height: 10%;
+}
+.ui.eleven.vertical.buttons > .button {
+  height: 9.09%;
+}
+.ui.twelve.vertical.buttons > .button {
+  height: 8.3333%;
+}
+
+/*-------------------
+       Colors
+--------------------*/
+
+
+/*--- Black ---*/
+
+.ui.black.buttons .button,
+.ui.black.button {
+  background-color: #1b1c1d;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.black.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.black.buttons .button:hover,
+.ui.black.button:hover {
+  background-color: #27292a;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.black.buttons .button:focus,
+.ui.black.button:focus {
+  background-color: #2f3032;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.black.buttons .button:active,
+.ui.black.button:active {
+  background-color: #343637;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.black.buttons .active.button,
+.ui.black.buttons .active.button:active,
+.ui.black.active.button,
+.ui.black.button .active.button:active {
+  background-color: #0f0f10;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.black.buttons .button,
+.ui.basic.black.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.black.buttons .button:hover,
+.ui.basic.black.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #27292a inset !important;
+  color: #27292a !important;
+}
+.ui.basic.black.buttons .button:focus,
+.ui.basic.black.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #2f3032 inset !important;
+}
+.ui.basic.black.buttons .active.button,
+.ui.basic.black.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #0f0f10 inset !important;
+  color: #343637 !important;
+}
+.ui.basic.black.buttons .button:active,
+.ui.basic.black.button:active {
+  box-shadow: 0px 0px 0px 2px #343637 inset !important;
+  color: #343637 !important;
+}
+.ui.buttons > .basic.black.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.black.buttons .button,
+.ui.inverted.black.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #d4d4d5 inset !important;
+  color: #ffffff;
+}
+.ui.inverted.black.buttons .button:hover,
+.ui.inverted.black.button:hover,
+.ui.inverted.black.buttons .button:focus,
+.ui.inverted.black.button:focus,
+.ui.inverted.black.buttons .button.active,
+.ui.inverted.black.button.active,
+.ui.inverted.black.buttons .button:active,
+.ui.inverted.black.button:active {
+  box-shadow: none !important;
+  color: #ffffff;
+}
+.ui.inverted.black.buttons .button:hover,
+.ui.inverted.black.button:hover {
+  background-color: #000000;
+}
+.ui.inverted.black.buttons .button:focus,
+.ui.inverted.black.button:focus {
+  background-color: #000000;
+}
+.ui.inverted.black.buttons .active.button,
+.ui.inverted.black.active.button {
+  background-color: #000000;
+}
+.ui.inverted.black.buttons .button:active,
+.ui.inverted.black.button:active {
+  background-color: #000000;
+}
+
+/* Inverted Basic */
+.ui.inverted.black.basic.buttons .button,
+.ui.inverted.black.buttons .basic.button,
+.ui.inverted.black.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.black.basic.buttons .button:hover,
+.ui.inverted.black.buttons .basic.button:hover,
+.ui.inverted.black.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #000000 inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.black.basic.buttons .button:focus,
+.ui.inverted.black.basic.buttons .button:focus,
+.ui.inverted.black.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #000000 inset !important;
+  color: #545454 !important;
+}
+.ui.inverted.black.basic.buttons .active.button,
+.ui.inverted.black.buttons .basic.active.button,
+.ui.inverted.black.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #000000 inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.black.basic.buttons .button:active,
+.ui.inverted.black.buttons .basic.button:active,
+.ui.inverted.black.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #000000 inset !important;
+  color: #ffffff !important;
+}
+
+/*--- Grey ---*/
+
+.ui.grey.buttons .button,
+.ui.grey.button {
+  background-color: #767676;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.grey.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.grey.buttons .button:hover,
+.ui.grey.button:hover {
+  background-color: #838383;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.grey.buttons .button:focus,
+.ui.grey.button:focus {
+  background-color: #8a8a8a;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.grey.buttons .button:active,
+.ui.grey.button:active {
+  background-color: #909090;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.grey.buttons .active.button,
+.ui.grey.buttons .active.button:active,
+.ui.grey.active.button,
+.ui.grey.button .active.button:active {
+  background-color: #696969;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.grey.buttons .button,
+.ui.basic.grey.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.grey.buttons .button:hover,
+.ui.basic.grey.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #838383 inset !important;
+  color: #838383 !important;
+}
+.ui.basic.grey.buttons .button:focus,
+.ui.basic.grey.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #8a8a8a inset !important;
+}
+.ui.basic.grey.buttons .active.button,
+.ui.basic.grey.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #696969 inset !important;
+  color: #909090 !important;
+}
+.ui.basic.grey.buttons .button:active,
+.ui.basic.grey.button:active {
+  box-shadow: 0px 0px 0px 2px #909090 inset !important;
+  color: #909090 !important;
+}
+.ui.buttons > .basic.grey.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.grey.buttons .button,
+.ui.inverted.grey.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #d4d4d5 inset !important;
+  color: #ffffff;
+}
+.ui.inverted.grey.buttons .button:hover,
+.ui.inverted.grey.button:hover,
+.ui.inverted.grey.buttons .button:focus,
+.ui.inverted.grey.button:focus,
+.ui.inverted.grey.buttons .button.active,
+.ui.inverted.grey.button.active,
+.ui.inverted.grey.buttons .button:active,
+.ui.inverted.grey.button:active {
+  box-shadow: none !important;
+  color: rgba(0, 0, 0, 0.6);
+}
+.ui.inverted.grey.buttons .button:hover,
+.ui.inverted.grey.button:hover {
+  background-color: #cfd0d2;
+}
+.ui.inverted.grey.buttons .button:focus,
+.ui.inverted.grey.button:focus {
+  background-color: #c7c9cb;
+}
+.ui.inverted.grey.buttons .active.button,
+.ui.inverted.grey.active.button {
+  background-color: #cfd0d2;
+}
+.ui.inverted.grey.buttons .button:active,
+.ui.inverted.grey.button:active {
+  background-color: #c2c4c5;
+}
+
+/* Inverted Basic */
+.ui.inverted.grey.basic.buttons .button,
+.ui.inverted.grey.buttons .basic.button,
+.ui.inverted.grey.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.grey.basic.buttons .button:hover,
+.ui.inverted.grey.buttons .basic.button:hover,
+.ui.inverted.grey.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #cfd0d2 inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.grey.basic.buttons .button:focus,
+.ui.inverted.grey.basic.buttons .button:focus,
+.ui.inverted.grey.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #c7c9cb inset !important;
+  color: #dcddde !important;
+}
+.ui.inverted.grey.basic.buttons .active.button,
+.ui.inverted.grey.buttons .basic.active.button,
+.ui.inverted.grey.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #cfd0d2 inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.grey.basic.buttons .button:active,
+.ui.inverted.grey.buttons .basic.button:active,
+.ui.inverted.grey.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #c2c4c5 inset !important;
+  color: #ffffff !important;
+}
+
+/*--- Brown ---*/
+
+.ui.brown.buttons .button,
+.ui.brown.button {
+  background-color: #a5673f;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.brown.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.brown.buttons .button:hover,
+.ui.brown.button:hover {
+  background-color: #975b33;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.brown.buttons .button:focus,
+.ui.brown.button:focus {
+  background-color: #90532b;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.brown.buttons .button:active,
+.ui.brown.button:active {
+  background-color: #805031;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.brown.buttons .active.button,
+.ui.brown.buttons .active.button:active,
+.ui.brown.active.button,
+.ui.brown.button .active.button:active {
+  background-color: #995a31;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.brown.buttons .button,
+.ui.basic.brown.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.brown.buttons .button:hover,
+.ui.basic.brown.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #975b33 inset !important;
+  color: #975b33 !important;
+}
+.ui.basic.brown.buttons .button:focus,
+.ui.basic.brown.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #90532b inset !important;
+}
+.ui.basic.brown.buttons .active.button,
+.ui.basic.brown.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #995a31 inset !important;
+  color: #805031 !important;
+}
+.ui.basic.brown.buttons .button:active,
+.ui.basic.brown.button:active {
+  box-shadow: 0px 0px 0px 2px #805031 inset !important;
+  color: #805031 !important;
+}
+.ui.buttons > .basic.brown.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.brown.buttons .button,
+.ui.inverted.brown.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #d67c1c inset !important;
+  color: #d67c1c;
+}
+.ui.inverted.brown.buttons .button:hover,
+.ui.inverted.brown.button:hover,
+.ui.inverted.brown.buttons .button:focus,
+.ui.inverted.brown.button:focus,
+.ui.inverted.brown.buttons .button.active,
+.ui.inverted.brown.button.active,
+.ui.inverted.brown.buttons .button:active,
+.ui.inverted.brown.button:active {
+  box-shadow: none !important;
+  color: #ffffff;
+}
+.ui.inverted.brown.buttons .button:hover,
+.ui.inverted.brown.button:hover {
+  background-color: #c86f11;
+}
+.ui.inverted.brown.buttons .button:focus,
+.ui.inverted.brown.button:focus {
+  background-color: #c16808;
+}
+.ui.inverted.brown.buttons .active.button,
+.ui.inverted.brown.active.button {
+  background-color: #cc6f0d;
+}
+.ui.inverted.brown.buttons .button:active,
+.ui.inverted.brown.button:active {
+  background-color: #a96216;
+}
+
+/* Inverted Basic */
+.ui.inverted.brown.basic.buttons .button,
+.ui.inverted.brown.buttons .basic.button,
+.ui.inverted.brown.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.brown.basic.buttons .button:hover,
+.ui.inverted.brown.buttons .basic.button:hover,
+.ui.inverted.brown.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #c86f11 inset !important;
+  color: #d67c1c !important;
+}
+.ui.inverted.brown.basic.buttons .button:focus,
+.ui.inverted.brown.basic.buttons .button:focus,
+.ui.inverted.brown.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #c16808 inset !important;
+  color: #d67c1c !important;
+}
+.ui.inverted.brown.basic.buttons .active.button,
+.ui.inverted.brown.buttons .basic.active.button,
+.ui.inverted.brown.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #cc6f0d inset !important;
+  color: #d67c1c !important;
+}
+.ui.inverted.brown.basic.buttons .button:active,
+.ui.inverted.brown.buttons .basic.button:active,
+.ui.inverted.brown.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #a96216 inset !important;
+  color: #d67c1c !important;
+}
+
+/*--- Blue ---*/
+
+.ui.blue.buttons .button,
+.ui.blue.button {
+  background-color: #2185d0;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.blue.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.blue.buttons .button:hover,
+.ui.blue.button:hover {
+  background-color: #1678c2;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.blue.buttons .button:focus,
+.ui.blue.button:focus {
+  background-color: #0d71bb;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.blue.buttons .button:active,
+.ui.blue.button:active {
+  background-color: #1a69a4;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.blue.buttons .active.button,
+.ui.blue.buttons .active.button:active,
+.ui.blue.active.button,
+.ui.blue.button .active.button:active {
+  background-color: #1279c6;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.blue.buttons .button,
+.ui.basic.blue.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.blue.buttons .button:hover,
+.ui.basic.blue.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #1678c2 inset !important;
+  color: #1678c2 !important;
+}
+.ui.basic.blue.buttons .button:focus,
+.ui.basic.blue.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #0d71bb inset !important;
+}
+.ui.basic.blue.buttons .active.button,
+.ui.basic.blue.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #1279c6 inset !important;
+  color: #1a69a4 !important;
+}
+.ui.basic.blue.buttons .button:active,
+.ui.basic.blue.button:active {
+  box-shadow: 0px 0px 0px 2px #1a69a4 inset !important;
+  color: #1a69a4 !important;
+}
+.ui.buttons > .basic.blue.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.blue.buttons .button,
+.ui.inverted.blue.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #54c8ff inset !important;
+  color: #54c8ff;
+}
+.ui.inverted.blue.buttons .button:hover,
+.ui.inverted.blue.button:hover,
+.ui.inverted.blue.buttons .button:focus,
+.ui.inverted.blue.button:focus,
+.ui.inverted.blue.buttons .button.active,
+.ui.inverted.blue.button.active,
+.ui.inverted.blue.buttons .button:active,
+.ui.inverted.blue.button:active {
+  box-shadow: none !important;
+  color: #ffffff;
+}
+.ui.inverted.blue.buttons .button:hover,
+.ui.inverted.blue.button:hover {
+  background-color: #3ac0ff;
+}
+.ui.inverted.blue.buttons .button:focus,
+.ui.inverted.blue.button:focus {
+  background-color: #2bbbff;
+}
+.ui.inverted.blue.buttons .active.button,
+.ui.inverted.blue.active.button {
+  background-color: #3ac0ff;
+}
+.ui.inverted.blue.buttons .button:active,
+.ui.inverted.blue.button:active {
+  background-color: #21b8ff;
+}
+
+/* Inverted Basic */
+.ui.inverted.blue.basic.buttons .button,
+.ui.inverted.blue.buttons .basic.button,
+.ui.inverted.blue.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.blue.basic.buttons .button:hover,
+.ui.inverted.blue.buttons .basic.button:hover,
+.ui.inverted.blue.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #3ac0ff inset !important;
+  color: #54c8ff !important;
+}
+.ui.inverted.blue.basic.buttons .button:focus,
+.ui.inverted.blue.basic.buttons .button:focus,
+.ui.inverted.blue.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #2bbbff inset !important;
+  color: #54c8ff !important;
+}
+.ui.inverted.blue.basic.buttons .active.button,
+.ui.inverted.blue.buttons .basic.active.button,
+.ui.inverted.blue.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #3ac0ff inset !important;
+  color: #54c8ff !important;
+}
+.ui.inverted.blue.basic.buttons .button:active,
+.ui.inverted.blue.buttons .basic.button:active,
+.ui.inverted.blue.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #21b8ff inset !important;
+  color: #54c8ff !important;
+}
+
+/*--- Green ---*/
+
+.ui.green.buttons .button,
+.ui.green.button {
+  background-color: #21ba45;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.green.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.green.buttons .button:hover,
+.ui.green.button:hover {
+  background-color: #16ab39;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.green.buttons .button:focus,
+.ui.green.button:focus {
+  background-color: #0ea432;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.green.buttons .button:active,
+.ui.green.button:active {
+  background-color: #198f35;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.green.buttons .active.button,
+.ui.green.buttons .active.button:active,
+.ui.green.active.button,
+.ui.green.button .active.button:active {
+  background-color: #13ae38;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.green.buttons .button,
+.ui.basic.green.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.green.buttons .button:hover,
+.ui.basic.green.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #16ab39 inset !important;
+  color: #16ab39 !important;
+}
+.ui.basic.green.buttons .button:focus,
+.ui.basic.green.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #0ea432 inset !important;
+}
+.ui.basic.green.buttons .active.button,
+.ui.basic.green.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #13ae38 inset !important;
+  color: #198f35 !important;
+}
+.ui.basic.green.buttons .button:active,
+.ui.basic.green.button:active {
+  box-shadow: 0px 0px 0px 2px #198f35 inset !important;
+  color: #198f35 !important;
+}
+.ui.buttons > .basic.green.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.green.buttons .button,
+.ui.inverted.green.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #2ecc40 inset !important;
+  color: #2ecc40;
+}
+.ui.inverted.green.buttons .button:hover,
+.ui.inverted.green.button:hover,
+.ui.inverted.green.buttons .button:focus,
+.ui.inverted.green.button:focus,
+.ui.inverted.green.buttons .button.active,
+.ui.inverted.green.button.active,
+.ui.inverted.green.buttons .button:active,
+.ui.inverted.green.button:active {
+  box-shadlightOw: none !important;
+  color: #ffffff;
+}
+.ui.inverted.green.buttons .button:hover,
+.ui.inverted.green.button:hover {
+  background-color: #22be34;
+}
+.ui.inverted.green.buttons .button:focus,
+.ui.inverted.green.button:focus {
+  background-color: #19b82b;
+}
+.ui.inverted.green.buttons .active.button,
+.ui.inverted.green.active.button {
+  background-color: #1fc231;
+}
+.ui.inverted.green.buttons .button:active,
+.ui.inverted.green.button:active {
+  background-color: #25a233;
+}
+
+/* Inverted Basic */
+.ui.inverted.green.basic.buttons .button,
+.ui.inverted.green.buttons .basic.button,
+.ui.inverted.green.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.green.basic.buttons .button:hover,
+.ui.inverted.green.buttons .basic.button:hover,
+.ui.inverted.green.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #22be34 inset !important;
+  color: #2ecc40 !important;
+}
+.ui.inverted.green.basic.buttons .button:focus,
+.ui.inverted.green.basic.buttons .button:focus,
+.ui.inverted.green.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #19b82b inset !important;
+  color: #2ecc40 !important;
+}
+.ui.inverted.green.basic.buttons .active.button,
+.ui.inverted.green.buttons .basic.active.button,
+.ui.inverted.green.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #1fc231 inset !important;
+  color: #2ecc40 !important;
+}
+.ui.inverted.green.basic.buttons .button:active,
+.ui.inverted.green.buttons .basic.button:active,
+.ui.inverted.green.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #25a233 inset !important;
+  color: #2ecc40 !important;
+}
+
+/*--- Orange ---*/
+
+.ui.orange.buttons .button,
+.ui.orange.button {
+  background-color: #f2711c;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.orange.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.orange.buttons .button:hover,
+.ui.orange.button:hover {
+  background-color: #f26202;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.orange.buttons .button:focus,
+.ui.orange.button:focus {
+  background-color: #e55b00;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.orange.buttons .button:active,
+.ui.orange.button:active {
+  background-color: #cf590c;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.orange.buttons .active.button,
+.ui.orange.buttons .active.button:active,
+.ui.orange.active.button,
+.ui.orange.button .active.button:active {
+  background-color: #f56100;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.orange.buttons .button,
+.ui.basic.orange.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.orange.buttons .button:hover,
+.ui.basic.orange.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #f26202 inset !important;
+  color: #f26202 !important;
+}
+.ui.basic.orange.buttons .button:focus,
+.ui.basic.orange.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #e55b00 inset !important;
+}
+.ui.basic.orange.buttons .active.button,
+.ui.basic.orange.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #f56100 inset !important;
+  color: #cf590c !important;
+}
+.ui.basic.orange.buttons .button:active,
+.ui.basic.orange.button:active {
+  box-shadow: 0px 0px 0px 2px #cf590c inset !important;
+  color: #cf590c !important;
+}
+.ui.buttons > .basic.orange.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.orange.buttons .button,
+.ui.inverted.orange.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #ff851b inset !important;
+  color: #ff851b;
+}
+.ui.inverted.orange.buttons .button:hover,
+.ui.inverted.orange.button:hover,
+.ui.inverted.orange.buttons .button:focus,
+.ui.inverted.orange.button:focus,
+.ui.inverted.orange.buttons .button.active,
+.ui.inverted.orange.button.active,
+.ui.inverted.orange.buttons .button:active,
+.ui.inverted.orange.button:active {
+  box-shadow: none !important;
+  color: #ffffff;
+}
+.ui.inverted.orange.buttons .button:hover,
+.ui.inverted.orange.button:hover {
+  background-color: #ff7701;
+}
+.ui.inverted.orange.buttons .button:focus,
+.ui.inverted.orange.button:focus {
+  background-color: #f17000;
+}
+.ui.inverted.orange.buttons .active.button,
+.ui.inverted.orange.active.button {
+  background-color: #ff7701;
+}
+.ui.inverted.orange.buttons .button:active,
+.ui.inverted.orange.button:active {
+  background-color: #e76b00;
+}
+
+/* Inverted Basic */
+.ui.inverted.orange.basic.buttons .button,
+.ui.inverted.orange.buttons .basic.button,
+.ui.inverted.orange.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.orange.basic.buttons .button:hover,
+.ui.inverted.orange.buttons .basic.button:hover,
+.ui.inverted.orange.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #ff7701 inset !important;
+  color: #ff851b !important;
+}
+.ui.inverted.orange.basic.buttons .button:focus,
+.ui.inverted.orange.basic.buttons .button:focus,
+.ui.inverted.orange.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #f17000 inset !important;
+  color: #ff851b !important;
+}
+.ui.inverted.orange.basic.buttons .active.button,
+.ui.inverted.orange.buttons .basic.active.button,
+.ui.inverted.orange.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #ff7701 inset !important;
+  color: #ff851b !important;
+}
+.ui.inverted.orange.basic.buttons .button:active,
+.ui.inverted.orange.buttons .basic.button:active,
+.ui.inverted.orange.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #e76b00 inset !important;
+  color: #ff851b !important;
+}
+
+/*--- Pink ---*/
+
+.ui.pink.buttons .button,
+.ui.pink.button {
+  background-color: #e03997;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.pink.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.pink.buttons .button:hover,
+.ui.pink.button:hover {
+  background-color: #e61a8d;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.pink.buttons .button:focus,
+.ui.pink.button:focus {
+  background-color: #e10f85;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.pink.buttons .button:active,
+.ui.pink.button:active {
+  background-color: #c71f7e;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.pink.buttons .active.button,
+.ui.pink.buttons .active.button:active,
+.ui.pink.active.button,
+.ui.pink.button .active.button:active {
+  background-color: #ea158d;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.pink.buttons .button,
+.ui.basic.pink.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.pink.buttons .button:hover,
+.ui.basic.pink.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #e61a8d inset !important;
+  color: #e61a8d !important;
+}
+.ui.basic.pink.buttons .button:focus,
+.ui.basic.pink.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #e10f85 inset !important;
+}
+.ui.basic.pink.buttons .active.button,
+.ui.basic.pink.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #ea158d inset !important;
+  color: #c71f7e !important;
+}
+.ui.basic.pink.buttons .button:active,
+.ui.basic.pink.button:active {
+  box-shadow: 0px 0px 0px 2px #c71f7e inset !important;
+  color: #c71f7e !important;
+}
+.ui.buttons > .basic.pink.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.pink.buttons .button,
+.ui.inverted.pink.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #ff8edf inset !important;
+  color: #ff8edf;
+}
+.ui.inverted.pink.buttons .button:hover,
+.ui.inverted.pink.button:hover,
+.ui.inverted.pink.buttons .button:focus,
+.ui.inverted.pink.button:focus,
+.ui.inverted.pink.buttons .button.active,
+.ui.inverted.pink.button.active,
+.ui.inverted.pink.buttons .button:active,
+.ui.inverted.pink.button:active {
+  box-shadow: none !important;
+  color: #ffffff;
+}
+.ui.inverted.pink.buttons .button:hover,
+.ui.inverted.pink.button:hover {
+  background-color: #ff74d8;
+}
+.ui.inverted.pink.buttons .button:focus,
+.ui.inverted.pink.button:focus {
+  background-color: #ff65d3;
+}
+.ui.inverted.pink.buttons .active.button,
+.ui.inverted.pink.active.button {
+  background-color: #ff74d8;
+}
+.ui.inverted.pink.buttons .button:active,
+.ui.inverted.pink.button:active {
+  background-color: #ff5bd1;
+}
+
+/* Inverted Basic */
+.ui.inverted.pink.basic.buttons .button,
+.ui.inverted.pink.buttons .basic.button,
+.ui.inverted.pink.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.pink.basic.buttons .button:hover,
+.ui.inverted.pink.buttons .basic.button:hover,
+.ui.inverted.pink.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #ff74d8 inset !important;
+  color: #ff8edf !important;
+}
+.ui.inverted.pink.basic.buttons .button:focus,
+.ui.inverted.pink.basic.buttons .button:focus,
+.ui.inverted.pink.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #ff65d3 inset !important;
+  color: #ff8edf !important;
+}
+.ui.inverted.pink.basic.buttons .active.button,
+.ui.inverted.pink.buttons .basic.active.button,
+.ui.inverted.pink.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #ff74d8 inset !important;
+  color: #ff8edf !important;
+}
+.ui.inverted.pink.basic.buttons .button:active,
+.ui.inverted.pink.buttons .basic.button:active,
+.ui.inverted.pink.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #ff5bd1 inset !important;
+  color: #ff8edf !important;
+}
+
+/*--- Violet ---*/
+
+.ui.violet.buttons .button,
+.ui.violet.button {
+  background-color: #6435c9;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.violet.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.violet.buttons .button:hover,
+.ui.violet.button:hover {
+  background-color: #5829bb;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.violet.buttons .button:focus,
+.ui.violet.button:focus {
+  background-color: #4f20b5;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.violet.buttons .button:active,
+.ui.violet.button:active {
+  background-color: #502aa1;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.violet.buttons .active.button,
+.ui.violet.buttons .active.button:active,
+.ui.violet.active.button,
+.ui.violet.button .active.button:active {
+  background-color: #5626bf;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.violet.buttons .button,
+.ui.basic.violet.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.violet.buttons .button:hover,
+.ui.basic.violet.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #5829bb inset !important;
+  color: #5829bb !important;
+}
+.ui.basic.violet.buttons .button:focus,
+.ui.basic.violet.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #4f20b5 inset !important;
+}
+.ui.basic.violet.buttons .active.button,
+.ui.basic.violet.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #5626bf inset !important;
+  color: #502aa1 !important;
+}
+.ui.basic.violet.buttons .button:active,
+.ui.basic.violet.button:active {
+  box-shadow: 0px 0px 0px 2px #502aa1 inset !important;
+  color: #502aa1 !important;
+}
+.ui.buttons > .basic.violet.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.violet.buttons .button,
+.ui.inverted.violet.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #a291fb inset !important;
+  color: #a291fb;
+}
+.ui.inverted.violet.buttons .button:hover,
+.ui.inverted.violet.button:hover,
+.ui.inverted.violet.buttons .button:focus,
+.ui.inverted.violet.button:focus,
+.ui.inverted.violet.buttons .button.active,
+.ui.inverted.violet.button.active,
+.ui.inverted.violet.buttons .button:active,
+.ui.inverted.violet.button:active {
+  box-shadow: none !important;
+  color: #ffffff;
+}
+.ui.inverted.violet.buttons .button:hover,
+.ui.inverted.violet.button:hover {
+  background-color: #8a73ff;
+}
+.ui.inverted.violet.buttons .button:focus,
+.ui.inverted.violet.button:focus {
+  background-color: #7d64ff;
+}
+.ui.inverted.violet.buttons .active.button,
+.ui.inverted.violet.active.button {
+  background-color: #8a73ff;
+}
+.ui.inverted.violet.buttons .button:active,
+.ui.inverted.violet.button:active {
+  background-color: #7860f9;
+}
+
+/* Inverted Basic */
+.ui.inverted.violet.basic.buttons .button,
+.ui.inverted.violet.buttons .basic.button,
+.ui.inverted.violet.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.violet.basic.buttons .button:hover,
+.ui.inverted.violet.buttons .basic.button:hover,
+.ui.inverted.violet.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #8a73ff inset !important;
+  color: #a291fb !important;
+}
+.ui.inverted.violet.basic.buttons .button:focus,
+.ui.inverted.violet.basic.buttons .button:focus,
+.ui.inverted.violet.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #7d64ff inset !important;
+  color: #a291fb !important;
+}
+.ui.inverted.violet.basic.buttons .active.button,
+.ui.inverted.violet.buttons .basic.active.button,
+.ui.inverted.violet.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #8a73ff inset !important;
+  color: #a291fb !important;
+}
+.ui.inverted.violet.basic.buttons .button:active,
+.ui.inverted.violet.buttons .basic.button:active,
+.ui.inverted.violet.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #7860f9 inset !important;
+  color: #a291fb !important;
+}
+
+/*--- Purple ---*/
+
+.ui.purple.buttons .button,
+.ui.purple.button {
+  background-color: #a333c8;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.purple.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.purple.buttons .button:hover,
+.ui.purple.button:hover {
+  background-color: #9627ba;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.purple.buttons .button:focus,
+.ui.purple.button:focus {
+  background-color: #8f1eb4;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.purple.buttons .button:active,
+.ui.purple.button:active {
+  background-color: #82299f;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.purple.buttons .active.button,
+.ui.purple.buttons .active.button:active,
+.ui.purple.active.button,
+.ui.purple.button .active.button:active {
+  background-color: #9724be;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.purple.buttons .button,
+.ui.basic.purple.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.purple.buttons .button:hover,
+.ui.basic.purple.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #9627ba inset !important;
+  color: #9627ba !important;
+}
+.ui.basic.purple.buttons .button:focus,
+.ui.basic.purple.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #8f1eb4 inset !important;
+}
+.ui.basic.purple.buttons .active.button,
+.ui.basic.purple.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #9724be inset !important;
+  color: #82299f !important;
+}
+.ui.basic.purple.buttons .button:active,
+.ui.basic.purple.button:active {
+  box-shadow: 0px 0px 0px 2px #82299f inset !important;
+  color: #82299f !important;
+}
+.ui.buttons > .basic.purple.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.purple.buttons .button,
+.ui.inverted.purple.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #dc73ff inset !important;
+  color: #dc73ff;
+}
+.ui.inverted.purple.buttons .button:hover,
+.ui.inverted.purple.button:hover,
+.ui.inverted.purple.buttons .button:focus,
+.ui.inverted.purple.button:focus,
+.ui.inverted.purple.buttons .button.active,
+.ui.inverted.purple.button.active,
+.ui.inverted.purple.buttons .button:active,
+.ui.inverted.purple.button:active {
+  box-shadow: none !important;
+  color: #ffffff;
+}
+.ui.inverted.purple.buttons .button:hover,
+.ui.inverted.purple.button:hover {
+  background-color: #d65aff;
+}
+.ui.inverted.purple.buttons .button:focus,
+.ui.inverted.purple.button:focus {
+  background-color: #d24aff;
+}
+.ui.inverted.purple.buttons .active.button,
+.ui.inverted.purple.active.button {
+  background-color: #d65aff;
+}
+.ui.inverted.purple.buttons .button:active,
+.ui.inverted.purple.button:active {
+  background-color: #cf40ff;
+}
+
+/* Inverted Basic */
+.ui.inverted.purple.basic.buttons .button,
+.ui.inverted.purple.buttons .basic.button,
+.ui.inverted.purple.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.purple.basic.buttons .button:hover,
+.ui.inverted.purple.buttons .basic.button:hover,
+.ui.inverted.purple.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #d65aff inset !important;
+  color: #dc73ff !important;
+}
+.ui.inverted.purple.basic.buttons .button:focus,
+.ui.inverted.purple.basic.buttons .button:focus,
+.ui.inverted.purple.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #d24aff inset !important;
+  color: #dc73ff !important;
+}
+.ui.inverted.purple.basic.buttons .active.button,
+.ui.inverted.purple.buttons .basic.active.button,
+.ui.inverted.purple.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #d65aff inset !important;
+  color: #dc73ff !important;
+}
+.ui.inverted.purple.basic.buttons .button:active,
+.ui.inverted.purple.buttons .basic.button:active,
+.ui.inverted.purple.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #cf40ff inset !important;
+  color: #dc73ff !important;
+}
+
+/*--- Red ---*/
+
+.ui.red.buttons .button,
+.ui.red.button {
+  background-color: #db2828;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.red.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.red.buttons .button:hover,
+.ui.red.button:hover {
+  background-color: #d01919;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.red.buttons .button:focus,
+.ui.red.button:focus {
+  background-color: #ca1010;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.red.buttons .button:active,
+.ui.red.button:active {
+  background-color: #b21e1e;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.red.buttons .active.button,
+.ui.red.buttons .active.button:active,
+.ui.red.active.button,
+.ui.red.button .active.button:active {
+  background-color: #d41515;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.red.buttons .button,
+.ui.basic.red.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.red.buttons .button:hover,
+.ui.basic.red.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #d01919 inset !important;
+  color: #d01919 !important;
+}
+.ui.basic.red.buttons .button:focus,
+.ui.basic.red.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #ca1010 inset !important;
+}
+.ui.basic.red.buttons .active.button,
+.ui.basic.red.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #d41515 inset !important;
+  color: #b21e1e !important;
+}
+.ui.basic.red.buttons .button:active,
+.ui.basic.red.button:active {
+  box-shadow: 0px 0px 0px 2px #b21e1e inset !important;
+  color: #b21e1e !important;
+}
+.ui.buttons > .basic.red.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.red.buttons .button,
+.ui.inverted.red.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #ff695e inset !important;
+  color: #ff695e;
+}
+.ui.inverted.red.buttons .button:hover,
+.ui.inverted.red.button:hover,
+.ui.inverted.red.buttons .button:focus,
+.ui.inverted.red.button:focus,
+.ui.inverted.red.buttons .button.active,
+.ui.inverted.red.button.active,
+.ui.inverted.red.buttons .button:active,
+.ui.inverted.red.button:active {
+  box-shadow: none !important;
+  color: #ffffff;
+}
+.ui.inverted.red.buttons .button:hover,
+.ui.inverted.red.button:hover {
+  background-color: #ff5144;
+}
+.ui.inverted.red.buttons .button:focus,
+.ui.inverted.red.button:focus {
+  background-color: #ff4335;
+}
+.ui.inverted.red.buttons .active.button,
+.ui.inverted.red.active.button {
+  background-color: #ff5144;
+}
+.ui.inverted.red.buttons .button:active,
+.ui.inverted.red.button:active {
+  background-color: #ff392b;
+}
+
+/* Inverted Basic */
+.ui.inverted.red.basic.buttons .button,
+.ui.inverted.red.buttons .basic.button,
+.ui.inverted.red.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.red.basic.buttons .button:hover,
+.ui.inverted.red.buttons .basic.button:hover,
+.ui.inverted.red.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #ff5144 inset !important;
+  color: #ff695e !important;
+}
+.ui.inverted.red.basic.buttons .button:focus,
+.ui.inverted.red.basic.buttons .button:focus,
+.ui.inverted.red.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #ff4335 inset !important;
+  color: #ff695e !important;
+}
+.ui.inverted.red.basic.buttons .active.button,
+.ui.inverted.red.buttons .basic.active.button,
+.ui.inverted.red.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #ff5144 inset !important;
+  color: #ff695e !important;
+}
+.ui.inverted.red.basic.buttons .button:active,
+.ui.inverted.red.buttons .basic.button:active,
+.ui.inverted.red.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #ff392b inset !important;
+  color: #ff695e !important;
+}
+
+/*--- Teal ---*/
+
+.ui.teal.buttons .button,
+.ui.teal.button {
+  background-color: #00b5ad;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.teal.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.teal.buttons .button:hover,
+.ui.teal.button:hover {
+  background-color: #009c95;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.teal.buttons .button:focus,
+.ui.teal.button:focus {
+  background-color: #008c86;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.teal.buttons .button:active,
+.ui.teal.button:active {
+  background-color: #00827c;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.teal.buttons .active.button,
+.ui.teal.buttons .active.button:active,
+.ui.teal.active.button,
+.ui.teal.button .active.button:active {
+  background-color: #009c95;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.teal.buttons .button,
+.ui.basic.teal.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.teal.buttons .button:hover,
+.ui.basic.teal.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #009c95 inset !important;
+  color: #009c95 !important;
+}
+.ui.basic.teal.buttons .button:focus,
+.ui.basic.teal.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #008c86 inset !important;
+}
+.ui.basic.teal.buttons .active.button,
+.ui.basic.teal.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #009c95 inset !important;
+  color: #00827c !important;
+}
+.ui.basic.teal.buttons .button:active,
+.ui.basic.teal.button:active {
+  box-shadow: 0px 0px 0px 2px #00827c inset !important;
+  color: #00827c !important;
+}
+.ui.buttons > .basic.teal.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.teal.buttons .button,
+.ui.inverted.teal.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #6dffff inset !important;
+  color: #6dffff;
+}
+.ui.inverted.teal.buttons .button:hover,
+.ui.inverted.teal.button:hover,
+.ui.inverted.teal.buttons .button:focus,
+.ui.inverted.teal.button:focus,
+.ui.inverted.teal.buttons .button.active,
+.ui.inverted.teal.button.active,
+.ui.inverted.teal.buttons .button:active,
+.ui.inverted.teal.button:active {
+  box-shadow: none !important;
+  color: rgba(0, 0, 0, 0.6);
+}
+.ui.inverted.teal.buttons .button:hover,
+.ui.inverted.teal.button:hover {
+  background-color: #54ffff;
+}
+.ui.inverted.teal.buttons .button:focus,
+.ui.inverted.teal.button:focus {
+  background-color: #44ffff;
+}
+.ui.inverted.teal.buttons .active.button,
+.ui.inverted.teal.active.button {
+  background-color: #54ffff;
+}
+.ui.inverted.teal.buttons .button:active,
+.ui.inverted.teal.button:active {
+  background-color: #3affff;
+}
+
+/* Inverted Basic */
+.ui.inverted.teal.basic.buttons .button,
+.ui.inverted.teal.buttons .basic.button,
+.ui.inverted.teal.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.teal.basic.buttons .button:hover,
+.ui.inverted.teal.buttons .basic.button:hover,
+.ui.inverted.teal.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #54ffff inset !important;
+  color: #6dffff !important;
+}
+.ui.inverted.teal.basic.buttons .button:focus,
+.ui.inverted.teal.basic.buttons .button:focus,
+.ui.inverted.teal.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #44ffff inset !important;
+  color: #6dffff !important;
+}
+.ui.inverted.teal.basic.buttons .active.button,
+.ui.inverted.teal.buttons .basic.active.button,
+.ui.inverted.teal.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #54ffff inset !important;
+  color: #6dffff !important;
+}
+.ui.inverted.teal.basic.buttons .button:active,
+.ui.inverted.teal.buttons .basic.button:active,
+.ui.inverted.teal.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #3affff inset !important;
+  color: #6dffff !important;
+}
+
+/*--- Olive ---*/
+
+.ui.olive.buttons .button,
+.ui.olive.button {
+  background-color: #b5cc18;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.olive.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.olive.buttons .button:hover,
+.ui.olive.button:hover {
+  background-color: #a7bd0d;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.olive.buttons .button:focus,
+.ui.olive.button:focus {
+  background-color: #a0b605;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.olive.buttons .button:active,
+.ui.olive.button:active {
+  background-color: #8d9e13;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.olive.buttons .active.button,
+.ui.olive.buttons .active.button:active,
+.ui.olive.active.button,
+.ui.olive.button .active.button:active {
+  background-color: #aac109;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.olive.buttons .button,
+.ui.basic.olive.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.olive.buttons .button:hover,
+.ui.basic.olive.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #a7bd0d inset !important;
+  color: #a7bd0d !important;
+}
+.ui.basic.olive.buttons .button:focus,
+.ui.basic.olive.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #a0b605 inset !important;
+}
+.ui.basic.olive.buttons .active.button,
+.ui.basic.olive.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #aac109 inset !important;
+  color: #8d9e13 !important;
+}
+.ui.basic.olive.buttons .button:active,
+.ui.basic.olive.button:active {
+  box-shadow: 0px 0px 0px 2px #8d9e13 inset !important;
+  color: #8d9e13 !important;
+}
+.ui.buttons > .basic.olive.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.olive.buttons .button,
+.ui.inverted.olive.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #d9e778 inset !important;
+  color: #d9e778;
+}
+.ui.inverted.olive.buttons .button:hover,
+.ui.inverted.olive.button:hover,
+.ui.inverted.olive.buttons .button:focus,
+.ui.inverted.olive.button:focus,
+.ui.inverted.olive.buttons .button.active,
+.ui.inverted.olive.button.active,
+.ui.inverted.olive.buttons .button:active,
+.ui.inverted.olive.button:active {
+  box-shadow: none !important;
+  color: rgba(0, 0, 0, 0.6);
+}
+.ui.inverted.olive.buttons .button:hover,
+.ui.inverted.olive.button:hover {
+  background-color: #d8ea5c;
+}
+.ui.inverted.olive.buttons .button:focus,
+.ui.inverted.olive.button:focus {
+  background-color: #daef47;
+}
+.ui.inverted.olive.buttons .active.button,
+.ui.inverted.olive.active.button {
+  background-color: #daed59;
+}
+.ui.inverted.olive.buttons .button:active,
+.ui.inverted.olive.button:active {
+  background-color: #cddf4d;
+}
+
+/* Inverted Basic */
+.ui.inverted.olive.basic.buttons .button,
+.ui.inverted.olive.buttons .basic.button,
+.ui.inverted.olive.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.olive.basic.buttons .button:hover,
+.ui.inverted.olive.buttons .basic.button:hover,
+.ui.inverted.olive.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #d8ea5c inset !important;
+  color: #d9e778 !important;
+}
+.ui.inverted.olive.basic.buttons .button:focus,
+.ui.inverted.olive.basic.buttons .button:focus,
+.ui.inverted.olive.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #daef47 inset !important;
+  color: #d9e778 !important;
+}
+.ui.inverted.olive.basic.buttons .active.button,
+.ui.inverted.olive.buttons .basic.active.button,
+.ui.inverted.olive.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #daed59 inset !important;
+  color: #d9e778 !important;
+}
+.ui.inverted.olive.basic.buttons .button:active,
+.ui.inverted.olive.buttons .basic.button:active,
+.ui.inverted.olive.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #cddf4d inset !important;
+  color: #d9e778 !important;
+}
+
+/*--- Yellow ---*/
+
+.ui.yellow.buttons .button,
+.ui.yellow.button {
+  background-color: #fbbd08;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.yellow.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.yellow.buttons .button:hover,
+.ui.yellow.button:hover {
+  background-color: #eaae00;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.yellow.buttons .button:focus,
+.ui.yellow.button:focus {
+  background-color: #daa300;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.yellow.buttons .button:active,
+.ui.yellow.button:active {
+  background-color: #cd9903;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.yellow.buttons .active.button,
+.ui.yellow.buttons .active.button:active,
+.ui.yellow.active.button,
+.ui.yellow.button .active.button:active {
+  background-color: #eaae00;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/* Basic */
+.ui.basic.yellow.buttons .button,
+.ui.basic.yellow.button {
+  box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset !important;
+  color: rgba(0, 0, 0, 0.6) !important;
+}
+.ui.basic.yellow.buttons .button:hover,
+.ui.basic.yellow.button:hover {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #eaae00 inset !important;
+  color: #eaae00 !important;
+}
+.ui.basic.yellow.buttons .button:focus,
+.ui.basic.yellow.button:focus {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #daa300 inset !important;
+}
+.ui.basic.yellow.buttons .active.button,
+.ui.basic.yellow.active.button {
+  background: transparent !important;
+  box-shadow: 0px 0px 0px 2px #eaae00 inset !important;
+  color: #cd9903 !important;
+}
+.ui.basic.yellow.buttons .button:active,
+.ui.basic.yellow.button:active {
+  box-shadow: 0px 0px 0px 2px #cd9903 inset !important;
+  color: #cd9903 !important;
+}
+.ui.buttons > .basic.yellow.button:not(:first-child) {
+  margin-left: -2px;
+}
+
+/* Inverted */
+.ui.inverted.yellow.buttons .button,
+.ui.inverted.yellow.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px #ffe21f inset !important;
+  color: #ffe21f;
+}
+.ui.inverted.yellow.buttons .button:hover,
+.ui.inverted.yellow.button:hover,
+.ui.inverted.yellow.buttons .button:focus,
+.ui.inverted.yellow.button:focus,
+.ui.inverted.yellow.buttons .button.active,
+.ui.inverted.yellow.button.active,
+.ui.inverted.yellow.buttons .button:active,
+.ui.inverted.yellow.button:active {
+  box-shadow: none !important;
+  color: rgba(0, 0, 0, 0.6);
+}
+.ui.inverted.yellow.buttons .button:hover,
+.ui.inverted.yellow.button:hover {
+  background-color: #ffdf05;
+}
+.ui.inverted.yellow.buttons .button:focus,
+.ui.inverted.yellow.button:focus {
+  background-color: #f5d500;
+}
+.ui.inverted.yellow.buttons .active.button,
+.ui.inverted.yellow.active.button {
+  background-color: #ffdf05;
+}
+.ui.inverted.yellow.buttons .button:active,
+.ui.inverted.yellow.button:active {
+  background-color: #ebcd00;
+}
+
+/* Inverted Basic */
+.ui.inverted.yellow.basic.buttons .button,
+.ui.inverted.yellow.buttons .basic.button,
+.ui.inverted.yellow.basic.button {
+  background-color: transparent;
+  box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.5) inset !important;
+  color: #ffffff !important;
+}
+.ui.inverted.yellow.basic.buttons .button:hover,
+.ui.inverted.yellow.buttons .basic.button:hover,
+.ui.inverted.yellow.basic.button:hover {
+  box-shadow: 0px 0px 0px 2px #ffdf05 inset !important;
+  color: #ffe21f !important;
+}
+.ui.inverted.yellow.basic.buttons .button:focus,
+.ui.inverted.yellow.basic.buttons .button:focus,
+.ui.inverted.yellow.basic.button:focus {
+  box-shadow: 0px 0px 0px 2px #f5d500 inset !important;
+  color: #ffe21f !important;
+}
+.ui.inverted.yellow.basic.buttons .active.button,
+.ui.inverted.yellow.buttons .basic.active.button,
+.ui.inverted.yellow.basic.active.button {
+  box-shadow: 0px 0px 0px 2px #ffdf05 inset !important;
+  color: #ffe21f !important;
+}
+.ui.inverted.yellow.basic.buttons .button:active,
+.ui.inverted.yellow.buttons .basic.button:active,
+.ui.inverted.yellow.basic.button:active {
+  box-shadow: 0px 0px 0px 2px #ebcd00 inset !important;
+  color: #ffe21f !important;
+}
+
+/*-------------------
+       Primary
+--------------------*/
+
+.ui.primary.buttons .button,
+.ui.primary.button {
+  background-color: #2185d0;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.primary.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.primary.buttons .button:hover,
+.ui.primary.button:hover {
+  background-color: #1678c2;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.primary.buttons .button:focus,
+.ui.primary.button:focus {
+  background-color: #0d71bb;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.primary.buttons .button:active,
+.ui.primary.button:active {
+  background-color: #1a69a4;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.primary.buttons .active.button,
+.ui.primary.active.button {
+  background-color: #1279c6;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/*-------------------
+      Secondary
+--------------------*/
+
+.ui.secondary.buttons .button,
+.ui.secondary.button {
+  background-color: #1b1c1d;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.secondary.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.secondary.buttons .button:hover,
+.ui.secondary.button:hover {
+  background-color: #27292a;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.secondary.buttons .button:focus,
+.ui.secondary.button:focus {
+  background-color: #2e3032;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.secondary.buttons .button:active,
+.ui.secondary.button:active {
+  background-color: #343637;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.secondary.buttons .active.button,
+.ui.secondary.active.button {
+  background-color: #27292a;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/*---------------
+    Positive
+----------------*/
+
+.ui.positive.buttons .button,
+.ui.positive.button {
+  background-color: #21ba45 !important;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.positive.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.positive.buttons .button:hover,
+.ui.positive.button:hover {
+  background-color: #16ab39 !important;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.positive.buttons .button:focus,
+.ui.positive.button:focus {
+  background-color: #0ea432 !important;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.positive.buttons .button:active,
+.ui.positive.button:active {
+  background-color: #198f35 !important;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.positive.buttons .active.button,
+.ui.positive.active.button,
+.ui.positive.buttons .active.button:active {
+  background-color: #13ae38;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+/*---------------
+     Negative
+----------------*/
+
+.ui.negative.buttons .button,
+.ui.negative.button {
+  background-color: #db2828 !important;
+  color: #ffffff;
+  text-shadow: none;
+  background-image: none;
+}
+.ui.negative.button {
+  box-shadow: 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.negative.buttons .button:hover,
+.ui.negative.button:hover {
+  background-color: #d01919 !important;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.negative.buttons .button:focus,
+.ui.negative.button:focus {
+  background-color: #ca1010 !important;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.negative.buttons .button:active,
+.ui.negative.button:active {
+  background-color: #b21e1e !important;
+  color: #ffffff;
+  text-shadow: none;
+}
+.ui.negative.buttons .active.button,
+.ui.negative.active.button,
+.ui.negative.buttons .active.button:active {
+  background-color: #d41515;
+  color: #ffffff;
+  text-shadow: none;
+}
+
+
+/*******************************
+            Groups
+*******************************/
+
+.ui.buttons {
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  -webkit-box-orient: horizontal;
+  -webkit-box-direction: normal;
+  -webkit-flex-direction: row;
+      -ms-flex-direction: row;
+          flex-direction: row;
+  font-size: 0em;
+  vertical-align: baseline;
+  margin: 0em 0.25em 0em 0em;
+}
+.ui.buttons:not(.basic):not(.inverted) {
+  box-shadow: none;
+}
+
+/* Clearfix */
+.ui.buttons:after {
+  content: ".";
+  display: block;
+  height: 0;
+  clear: both;
+  visibility: hidden;
+}
+
+/* Standard Group */
+.ui.buttons .button {
+  -webkit-box-flex: 1;
+  -webkit-flex: 1 0 auto;
+      -ms-flex: 1 0 auto;
+          flex: 1 0 auto;
+  margin: 0em;
+  border-radius: 0em;
+  margin: 0px 0px 0px 0px;
+}
+.ui.buttons > .ui.button:not(.basic):not(.inverted),
+.ui.buttons:not(.basic):not(.inverted) > .button {
+  box-shadow: 0px 0px 0px 1px transparent inset, 0px 0em 0px 0px rgba(34, 36, 38, 0.15) inset;
+}
+.ui.buttons .button:first-child {
+  border-left: none;
+  margin-left: 0em;
+  border-top-left-radius: 0.28571429rem;
+  border-bottom-left-radius: 0.28571429rem;
+}
+.ui.buttons .button:last-child {
+  border-top-right-radius: 0.28571429rem;
+  border-bottom-right-radius: 0.28571429rem;
+}
+
+/* Vertical  Style */
+.ui.vertical.buttons {
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  -webkit-box-orient: vertical;
+  -webkit-box-direction: normal;
+  -webkit-flex-direction: column;
+      -ms-flex-direction: column;
+          flex-direction: column;
+}
+.ui.vertical.buttons .button {
+  display: block;
+  float: none;
+  width: 100%;
+  margin: 0px 0px 0px 0px;
+  box-shadow: none;
+}
+.ui.vertical.buttons .button:first-child,
+.ui.vertical.buttons .mini.button:first-child,
+.ui.vertical.buttons .tiny.button:first-child,
+.ui.vertical.buttons .small.button:first-child,
+.ui.vertical.buttons .massive.button:first-child,
+.ui.vertical.buttons .huge.button:first-child {
+  border-radius: 0.28571429rem 0.28571429rem 0px 0px;
+}
+.ui.vertical.buttons .button:last-child,
+.ui.vertical.buttons .mini.button:last-child,
+.ui.vertical.buttons .tiny.button:last-child,
+.ui.vertical.buttons .small.button:last-child,
+.ui.vertical.buttons .massive.button:last-child,
+.ui.vertical.buttons .huge.button:last-child,
+.ui.vertical.buttons .gigantic.button:last-child {
+  margin-bottom: 0px;
+  border-radius: 0px 0px 0.28571429rem 0.28571429rem;
+}
+
+
+/*******************************
+         Theme Overrides
+*******************************/
+
+
+
+/*******************************
+         Site Overrides
+*******************************/
+

Разница между файлами не показана из-за своего большого размера
+ 9 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/button.min.css


+ 949 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/card.css

@@ -0,0 +1,949 @@
+/*!
+ * # Semantic UI 2.0.0 - Item
+ * http://github.com/semantic-org/semantic-ui/
+ *
+ *
+ * Copyright 2015 Contributors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ */
+
+
+/*******************************
+            Standard
+*******************************/
+
+
+/*--------------
+      Card
+---------------*/
+
+.ui.cards > .card,
+.ui.card {
+  max-width: 100%;
+  position: relative;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-box-orient: vertical;
+  -webkit-box-direction: normal;
+  -webkit-flex-direction: column;
+      -ms-flex-direction: column;
+          flex-direction: column;
+  width: 290px;
+  min-height: 0px;
+  background: #ffffff;
+  padding: 0em;
+  border: none;
+  border-radius: 0.28571429rem;
+  box-shadow: 0px 1px 3px 0px #d4d4d5, 0px 0px 0px 1px #d4d4d5;
+  -webkit-transition: box-shadow 0.1s ease, -webkit-transform 0.1s ease;
+          transition: box-shadow 0.1s ease, transform 0.1s ease;
+  z-index: '';
+}
+.ui.card {
+  margin: 1em 0em;
+}
+.ui.cards > .card a,
+.ui.card a {
+  cursor: pointer;
+}
+.ui.card:first-child {
+  margin-top: 0em;
+}
+.ui.card:last-child {
+  margin-bottom: 0em;
+}
+
+/*--------------
+      Cards
+---------------*/
+
+.ui.cards {
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  margin: -0.875em -0.5em;
+  -webkit-flex-wrap: wrap;
+      -ms-flex-wrap: wrap;
+          flex-wrap: wrap;
+}
+.ui.cards > .card {
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  margin: 0.875em 0.5em;
+  float: none;
+}
+
+/* Clearing */
+.ui.cards:after,
+.ui.card:after {
+  display: block;
+  content: ' ';
+  height: 0px;
+  clear: both;
+  overflow: hidden;
+  visibility: hidden;
+}
+
+/* Consecutive Card Groups Preserve Row Spacing */
+.ui.cards ~ .ui.cards {
+  margin-top: 0.875em;
+}
+
+/*--------------
+  Rounded Edges
+---------------*/
+
+.ui.cards > .card > :first-child,
+.ui.card > :first-child {
+  border-radius: 0.28571429rem 0.28571429rem 0em 0em !important;
+  border-top: none !important;
+}
+.ui.cards > .card > :last-child,
+.ui.card > :last-child {
+  border-radius: 0em 0em 0.28571429rem 0.28571429rem !important;
+}
+.ui.cards > .card > :only-child,
+.ui.card > :only-child {
+  border-radius: 0.28571429rem !important;
+}
+
+/*--------------
+     Images
+---------------*/
+
+.ui.cards > .card > .image,
+.ui.card > .image {
+  position: relative;
+  display: block;
+  -webkit-box-flex: 0;
+  -webkit-flex: 0 0 auto;
+      -ms-flex: 0 0 auto;
+          flex: 0 0 auto;
+  padding: 0em;
+  background: rgba(0, 0, 0, 0.05);
+}
+.ui.cards > .card > .image > img,
+.ui.card > .image > img {
+  display: block;
+  width: 100%;
+  height: auto;
+  border-radius: inherit;
+}
+.ui.cards > .card > .image:not(.ui) > img,
+.ui.card > .image:not(.ui) > img {
+  border: none;
+}
+
+/*--------------
+     Content
+---------------*/
+
+.ui.cards > .card > .content,
+.ui.card > .content {
+  -webkit-box-flex: 1;
+  -webkit-flex-grow: 1;
+      -ms-flex-positive: 1;
+          flex-grow: 1;
+  border: none;
+  border-top: 1px solid rgba(34, 36, 38, 0.1);
+  background: none;
+  margin: 0em;
+  padding: 1em 1em;
+  box-shadow: none;
+  font-size: 1em;
+  border-radius: 0em;
+}
+.ui.cards > .card > .content:after,
+.ui.card > .content:after {
+  display: block;
+  content: ' ';
+  height: 0px;
+  clear: both;
+  overflow: hidden;
+  visibility: hidden;
+}
+.ui.cards > .card > .content > .header,
+.ui.card > .content > .header {
+  display: block;
+  margin: '';
+  font-family: 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif;
+  color: rgba(0, 0, 0, 0.85);
+}
+
+/* Default Header Size */
+.ui.cards > .card > .content > .header:not(.ui),
+.ui.card > .content > .header:not(.ui) {
+  font-weight: bold;
+  font-size: 1.28571429em;
+  margin-top: -0.21425em;
+  line-height: 1.2857em;
+}
+.ui.cards > .card > .content > .meta + .description,
+.ui.cards > .card > .content > .header + .description,
+.ui.card > .content > .meta + .description,
+.ui.card > .content > .header + .description {
+  margin-top: 0.5em;
+}
+
+/*----------------
+ Floated Content
+-----------------*/
+
+.ui.cards > .card [class*="left floated"],
+.ui.card [class*="left floated"] {
+  float: left;
+}
+.ui.cards > .card [class*="right floated"],
+.ui.card [class*="right floated"] {
+  float: right;
+}
+
+/*--------------
+     Aligned
+---------------*/
+
+.ui.cards > .card [class*="left aligned"],
+.ui.card [class*="left aligned"] {
+  text-align: left;
+}
+.ui.cards > .card [class*="center aligned"],
+.ui.card [class*="center aligned"] {
+  text-align: center;
+}
+.ui.cards > .card [class*="right aligned"],
+.ui.card [class*="right aligned"] {
+  text-align: right;
+}
+
+/*--------------
+  Content Image
+---------------*/
+
+.ui.cards > .card .content img,
+.ui.card .content img {
+  display: inline-block;
+  vertical-align: middle;
+  width: '';
+}
+.ui.cards > .card img.avatar,
+.ui.cards > .card .avatar img,
+.ui.card img.avatar,
+.ui.card .avatar img {
+  width: 2em;
+  height: 2em;
+  border-radius: 500rem;
+}
+
+/*--------------
+   Description
+---------------*/
+
+.ui.cards > .card > .content > .description,
+.ui.card > .content > .description {
+  clear: both;
+  color: rgba(0, 0, 0, 0.68);
+}
+
+/*--------------
+    Paragraph
+---------------*/
+
+.ui.cards > .card > .content p,
+.ui.card > .content p {
+  margin: 0em 0em 0.5em;
+}
+.ui.cards > .card > .content p:last-child,
+.ui.card > .content p:last-child {
+  margin-bottom: 0em;
+}
+
+/*--------------
+      Meta
+---------------*/
+
+.ui.cards > .card .meta,
+.ui.card .meta {
+  font-size: 1em;
+  color: rgba(0, 0, 0, 0.4);
+}
+.ui.cards > .card .meta *,
+.ui.card .meta * {
+  margin-right: 0.3em;
+}
+.ui.cards > .card .meta :last-child,
+.ui.card .meta :last-child {
+  margin-right: 0em;
+}
+.ui.cards > .card .meta [class*="right floated"],
+.ui.card .meta [class*="right floated"] {
+  margin-right: 0em;
+  margin-left: 0.3em;
+}
+
+/*--------------
+      Links
+---------------*/
+
+
+/* Generic */
+.ui.cards > .card > .content a:not(.ui),
+.ui.card > .content a:not(.ui) {
+  color: '';
+  -webkit-transition: color 0.1s ease;
+          transition: color 0.1s ease;
+}
+.ui.cards > .card > .content a:not(.ui):hover,
+.ui.card > .content a:not(.ui):hover {
+  color: '';
+}
+
+/* Header */
+.ui.cards > .card > .content > a.header,
+.ui.card > .content > a.header {
+  color: rgba(0, 0, 0, 0.85);
+}
+.ui.cards > .card > .content > a.header:hover,
+.ui.card > .content > a.header:hover {
+  color: #1e70bf;
+}
+
+/* Meta */
+.ui.cards > .card .meta > a:not(.ui),
+.ui.card .meta > a:not(.ui) {
+  color: rgba(0, 0, 0, 0.4);
+}
+.ui.cards > .card .meta > a:not(.ui):hover,
+.ui.card .meta > a:not(.ui):hover {
+  color: rgba(0, 0, 0, 0.87);
+}
+
+/*--------------
+     Buttons
+---------------*/
+
+.ui.cards > .card > .buttons,
+.ui.card > .buttons,
+.ui.cards > .card > .button,
+.ui.card > .button {
+  margin: 0px -1px;
+  width: calc(100% +  2px );
+}
+
+/*--------------
+      Dimmer
+---------------*/
+
+.ui.cards > .card .dimmer,
+.ui.card .dimmer {
+  background-color: '';
+  z-index: 10;
+}
+
+/*--------------
+     Labels
+---------------*/
+
+
+/*-----Star----- */
+
+
+/* Icon */
+.ui.cards > .card > .content .star.icon,
+.ui.card > .content .star.icon {
+  cursor: pointer;
+  opacity: 0.75;
+  -webkit-transition: color 0.1s ease;
+          transition: color 0.1s ease;
+}
+.ui.cards > .card > .content .star.icon:hover,
+.ui.card > .content .star.icon:hover {
+  opacity: 1;
+  color: #ffb70a;
+}
+.ui.cards > .card > .content .active.star.icon,
+.ui.card > .content .active.star.icon {
+  color: #ffe623;
+}
+
+/*-----Like----- */
+
+
+/* Icon */
+.ui.cards > .card > .content .like.icon,
+.ui.card > .content .like.icon {
+  cursor: pointer;
+  opacity: 0.75;
+  -webkit-transition: color 0.1s ease;
+          transition: color 0.1s ease;
+}
+.ui.cards > .card > .content .like.icon:hover,
+.ui.card > .content .like.icon:hover {
+  opacity: 1;
+  color: #ff2733;
+}
+.ui.cards > .card > .content .active.like.icon,
+.ui.card > .content .active.like.icon {
+  color: #ff2733;
+}
+
+/*----------------
+  Extra Content
+-----------------*/
+
+.ui.cards > .card > .extra,
+.ui.card > .extra {
+  max-width: 100%;
+  min-height: 0em !important;
+  -webkit-box-flex: 0;
+  -webkit-flex-grow: 0;
+      -ms-flex-positive: 0;
+          flex-grow: 0;
+  border-top: 1px solid rgba(0, 0, 0, 0.05) !important;
+  position: static;
+  background: none;
+  width: auto;
+  margin: 0em 0em;
+  padding: 0.75em 1em;
+  top: 0em;
+  left: 0em;
+  color: rgba(0, 0, 0, 0.4);
+  box-shadow: none;
+  -webkit-transition: color 0.1s ease;
+          transition: color 0.1s ease;
+}
+.ui.cards > .card > .extra a:not(.ui),
+.ui.card > .extra a:not(.ui) {
+  color: rgba(0, 0, 0, 0.4);
+}
+.ui.cards > .card > .extra a:not(.ui):hover,
+.ui.card > .extra a:not(.ui):hover {
+  color: #1e70bf;
+}
+
+
+/*******************************
+           Variations
+*******************************/
+
+
+/*-------------------
+       Centered
+--------------------*/
+
+.ui.centered.card {
+  margin-left: auto;
+  margin-right: auto;
+}
+
+/*-------------------
+        Fluid
+--------------------*/
+
+.ui.fluid.card {
+  width: 100%;
+  max-width: 9999px;
+}
+
+/*-------------------
+        Link
+--------------------*/
+
+.ui.cards a.card,
+.ui.link.cards .card,
+a.ui.card,
+.ui.link.card {
+  -webkit-transform: none;
+      -ms-transform: none;
+          transform: none;
+}
+.ui.cards a.card:hover,
+.ui.link.cards .card:hover,
+a.ui.card:hover,
+.ui.link.card:hover {
+  cursor: pointer;
+  z-index: 5;
+  background: #ffffff;
+  border: none;
+  box-shadow: 0px 1px 3px 0px #bcbdbd, 0px 0px 0px 1px #d4d4d5;
+  -webkit-transform: translateY(-3px);
+      -ms-transform: translateY(-3px);
+          transform: translateY(-3px);
+}
+
+/*-------------------
+       Colors
+--------------------*/
+
+
+/* Red */
+.ui.red.cards > .card,
+.ui.cards > .red.card,
+.ui.red.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #db2828, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.red.cards > .card:hover,
+.ui.cards > .red.card:hover,
+.ui.red.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #d01919, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Orange */
+.ui.orange.cards > .card,
+.ui.cards > .orange.card,
+.ui.orange.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #f2711c, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.orange.cards > .card:hover,
+.ui.cards > .orange.card:hover,
+.ui.orange.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #f26202, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Yellow */
+.ui.yellow.cards > .card,
+.ui.cards > .yellow.card,
+.ui.yellow.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #fbbd08, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.yellow.cards > .card:hover,
+.ui.cards > .yellow.card:hover,
+.ui.yellow.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #eaae00, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Olive */
+.ui.olive.cards > .card,
+.ui.cards > .olive.card,
+.ui.olive.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #b5cc18, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.olive.cards > .card:hover,
+.ui.cards > .olive.card:hover,
+.ui.olive.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #a7bd0d, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Green */
+.ui.green.cards > .card,
+.ui.cards > .green.card,
+.ui.green.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #21ba45, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.green.cards > .card:hover,
+.ui.cards > .green.card:hover,
+.ui.green.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #16ab39, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Teal */
+.ui.teal.cards > .card,
+.ui.cards > .teal.card,
+.ui.teal.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #00b5ad, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.teal.cards > .card:hover,
+.ui.cards > .teal.card:hover,
+.ui.teal.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #009c95, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Blue */
+.ui.blue.cards > .card,
+.ui.cards > .blue.card,
+.ui.blue.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #2185d0, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.blue.cards > .card:hover,
+.ui.cards > .blue.card:hover,
+.ui.blue.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #1678c2, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Violet */
+.ui.violet.cards > .card,
+.ui.cards > .violet.card,
+.ui.violet.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #6435c9, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.violet.cards > .card:hover,
+.ui.cards > .violet.card:hover,
+.ui.violet.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #5829bb, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Purple */
+.ui.purple.cards > .card,
+.ui.cards > .purple.card,
+.ui.purple.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #a333c8, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.purple.cards > .card:hover,
+.ui.cards > .purple.card:hover,
+.ui.purple.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #9627ba, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Pink */
+.ui.pink.cards > .card,
+.ui.cards > .pink.card,
+.ui.pink.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #e03997, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.pink.cards > .card:hover,
+.ui.cards > .pink.card:hover,
+.ui.pink.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #e61a8d, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Brown */
+.ui.brown.cards > .card,
+.ui.cards > .brown.card,
+.ui.brown.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #a5673f, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.brown.cards > .card:hover,
+.ui.cards > .brown.card:hover,
+.ui.brown.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #975b33, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Grey */
+.ui.grey.cards > .card,
+.ui.cards > .grey.card,
+.ui.grey.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #767676, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.grey.cards > .card:hover,
+.ui.cards > .grey.card:hover,
+.ui.grey.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #838383, 0px 1px 3px 0px #bcbdbd;
+}
+
+/* Black */
+.ui.black.cards > .card,
+.ui.cards > .black.card,
+.ui.black.card {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #1b1c1d, 0px 1px 3px 0px #d4d4d5;
+}
+.ui.black.cards > .card:hover,
+.ui.cards > .black.card:hover,
+.ui.black.card:hover {
+  box-shadow: 0px 0px 0px 1px #d4d4d5, 0px 2px 0px 0px #27292a, 0px 1px 3px 0px #bcbdbd;
+}
+
+/*--------------
+   Card Count
+---------------*/
+
+.ui.one.cards {
+  margin-left: 0em;
+  margin-right: 0em;
+}
+.ui.one.cards > .card {
+  width: 100%;
+}
+.ui.two.cards {
+  margin-left: -1em;
+  margin-right: -1em;
+}
+.ui.two.cards > .card {
+  width: calc( 50%  -  2em );
+  margin-left: 1em;
+  margin-right: 1em;
+}
+.ui.three.cards {
+  margin-left: -1em;
+  margin-right: -1em;
+}
+.ui.three.cards > .card {
+  width: calc( 33.33333333%  -  2em );
+  margin-left: 1em;
+  margin-right: 1em;
+}
+.ui.four.cards {
+  margin-left: -0.75em;
+  margin-right: -0.75em;
+}
+.ui.four.cards > .card {
+  width: calc( 25%  -  1.5em );
+  margin-left: 0.75em;
+  margin-right: 0.75em;
+}
+.ui.five.cards {
+  margin-left: -0.75em;
+  margin-right: -0.75em;
+}
+.ui.five.cards > .card {
+  width: calc( 20%  -  1.5em );
+  margin-left: 0.75em;
+  margin-right: 0.75em;
+}
+.ui.six.cards {
+  margin-left: -0.75em;
+  margin-right: -0.75em;
+}
+.ui.six.cards > .card {
+  width: calc( 16.66666667%  -  1.5em );
+  margin-left: 0.75em;
+  margin-right: 0.75em;
+}
+.ui.seven.cards {
+  margin-left: -0.5em;
+  margin-right: -0.5em;
+}
+.ui.seven.cards > .card {
+  width: calc( 14.28571429%  -  1em );
+  margin-left: 0.5em;
+  margin-right: 0.5em;
+}
+.ui.eight.cards {
+  margin-left: -0.5em;
+  margin-right: -0.5em;
+}
+.ui.eight.cards > .card {
+  width: calc( 12.5%  -  1em );
+  margin-left: 0.5em;
+  margin-right: 0.5em;
+  font-size: 11px;
+}
+.ui.nine.cards {
+  margin-left: -0.5em;
+  margin-right: -0.5em;
+}
+.ui.nine.cards > .card {
+  width: calc( 11.11111111%  -  1em );
+  margin-left: 0.5em;
+  margin-right: 0.5em;
+  font-size: 10px;
+}
+.ui.ten.cards {
+  margin-left: -0.5em;
+  margin-right: -0.5em;
+}
+.ui.ten.cards > .card {
+  width: calc( 10%  -  1em );
+  margin-left: 0.5em;
+  margin-right: 0.5em;
+}
+
+/*-------------------
+      Doubling
+--------------------*/
+
+
+/* Mobily Only */
+@media only screen and (max-width: 767px) {
+  .ui.two.doubling.cards {
+    margin-left: 0em;
+    margin-right: 0em;
+  }
+  .ui.two.doubling.cards .card {
+    width: 100%;
+    margin-left: 0em;
+    margin-right: 0em;
+  }
+  .ui.three.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.three.doubling.cards .card {
+    width: calc( 50%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.four.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.four.doubling.cards .card {
+    width: calc( 50%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.five.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.five.doubling.cards .card {
+    width: calc( 50%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.six.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.six.doubling.cards .card {
+    width: calc( 50%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.seven.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.seven.doubling.cards .card {
+    width: calc( 33.33333333%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.eight.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.eight.doubling.cards .card {
+    width: calc( 33.33333333%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.nine.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.nine.doubling.cards .card {
+    width: calc( 33.33333333%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.ten.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.ten.doubling.cards .card {
+    width: calc( 33.33333333%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+}
+
+/* Tablet Only */
+@media only screen and (min-width: 768px) and (max-width: 991px) {
+  .ui.two.doubling.cards {
+    margin-left: 0em;
+    margin-right: 0em;
+  }
+  .ui.two.doubling.cards .card {
+    width: 100%;
+    margin-left: 0em;
+    margin-right: 0em;
+  }
+  .ui.three.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.three.doubling.cards .card {
+    width: calc( 50%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.four.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.four.doubling.cards .card {
+    width: calc( 50%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.five.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.five.doubling.cards .card {
+    width: calc( 33.33333333%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.six.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.six.doubling.cards .card {
+    width: calc( 33.33333333%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.eight.doubling.cards {
+    margin-left: -1em;
+    margin-right: -1em;
+  }
+  .ui.eight.doubling.cards .card {
+    width: calc( 33.33333333%  -  2em );
+    margin-left: 1em;
+    margin-right: 1em;
+  }
+  .ui.eight.doubling.cards {
+    margin-left: -0.75em;
+    margin-right: -0.75em;
+  }
+  .ui.eight.doubling.cards .card {
+    width: calc( 25%  -  1.5em );
+    margin-left: 0.75em;
+    margin-right: 0.75em;
+  }
+  .ui.nine.doubling.cards {
+    margin-left: -0.75em;
+    margin-right: -0.75em;
+  }
+  .ui.nine.doubling.cards .card {
+    width: calc( 25%  -  1.5em );
+    margin-left: 0.75em;
+    margin-right: 0.75em;
+  }
+  .ui.ten.doubling.cards {
+    margin-left: -0.75em;
+    margin-right: -0.75em;
+  }
+  .ui.ten.doubling.cards .card {
+    width: calc( 20%  -  1.5em );
+    margin-left: 0.75em;
+    margin-right: 0.75em;
+  }
+}
+
+/*-------------------
+      Stackable
+--------------------*/
+
+@media only screen and (max-width: 767px) {
+  .ui.stackable.cards {
+    display: block !important;
+  }
+  .ui.stackable.cards .card:first-child {
+    margin-top: 0em !important;
+  }
+  .ui.stackable.cards > .card {
+    display: block !important;
+    height: auto !important;
+    margin: 1em 1em;
+    padding: 0 !important;
+    width: calc( 100%  -  2em ) !important;
+  }
+}
+
+/*--------------
+      Size
+---------------*/
+
+.ui.cards > .card {
+  font-size: 1em;
+}
+
+
+/*******************************
+         Theme Overrides
+*******************************/
+
+
+
+/*******************************
+    User Variable Overrides
+*******************************/
+

Разница между файлами не показана из-за своего большого размера
+ 9 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/card.min.css


+ 588 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/checkbox.css

@@ -0,0 +1,588 @@
+/*!
+ * # Semantic UI 2.0.0 - Checkbox
+ * http://github.com/semantic-org/semantic-ui/
+ *
+ *
+ * Copyright 2015 Contributors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ */
+
+
+/*******************************
+           Checkbox
+*******************************/
+
+
+/*--------------
+    Content
+---------------*/
+
+.ui.checkbox {
+  position: relative;
+  display: inline-block;
+  -webkit-backface-visibility: hidden;
+          backface-visibility: hidden;
+  outline: none;
+  vertical-align: baseline;
+  min-height: 17px;
+  font-size: 1rem;
+  line-height: 17px;
+  min-width: 17px;
+}
+.ui.checkbox input[type="checkbox"],
+.ui.checkbox input[type="radio"] {
+  cursor: pointer;
+  position: absolute;
+  top: 0px;
+  left: 0px;
+  opacity: 0 !important;
+  outline: none;
+  z-index: 3;
+  width: 17px;
+  height: 17px;
+}
+
+/*--------------
+      Box
+---------------*/
+
+.ui.checkbox .box,
+.ui.checkbox label {
+  cursor: auto;
+  position: relative;
+  display: block;
+  padding-left: 1.85714em;
+  outline: none;
+}
+.ui.checkbox .box,
+.ui.checkbox label {
+  font-size: 14px;
+}
+.ui.checkbox .box:before,
+.ui.checkbox label:before {
+  position: absolute;
+  top: 0px;
+  left: 0px;
+  width: 17px;
+  height: 17px;
+  content: '';
+  background: #ffffff;
+  border-radius: 0.21428571rem;
+  -webkit-transition: border 0.1s ease, opacity 0.1s ease, -webkit-transform 0.1s ease, box-shadow 0.1s ease;
+          transition: border 0.1s ease, opacity 0.1s ease, transform 0.1s ease, box-shadow 0.1s ease;
+  border: 1px solid #d4d4d5;
+}
+
+/*--------------
+    Checkmark
+---------------*/
+
+.ui.checkbox .box:after,
+.ui.checkbox label:after {
+  position: absolute;
+  font-size: 14px;
+  top: 0px;
+  left: 0px;
+  width: 17px;
+  height: 17px;
+  text-align: center;
+  opacity: 0;
+  color: rgba(0, 0, 0, 0.87);
+  -webkit-transition: border 0.1s ease, opacity 0.1s ease, -webkit-transform 0.1s ease, box-shadow 0.1s ease;
+          transition: border 0.1s ease, opacity 0.1s ease, transform 0.1s ease, box-shadow 0.1s ease;
+}
+
+/*--------------
+      Label
+---------------*/
+
+
+/* Inside */
+.ui.checkbox label,
+.ui.checkbox + label {
+  color: rgba(0, 0, 0, 0.87);
+  -webkit-transition: color 0.1s ease;
+          transition: color 0.1s ease;
+}
+
+/* Outside */
+.ui.checkbox + label {
+  vertical-align: middle;
+}
+
+
+/*******************************
+           States
+*******************************/
+
+
+/*--------------
+      Hover
+---------------*/
+
+.ui.checkbox .box:hover::before,
+.ui.checkbox label:hover::before {
+  background: #ffffff;
+  border-color: rgba(34, 36, 38, 0.35);
+}
+.ui.checkbox label:hover,
+.ui.checkbox + label:hover {
+  color: rgba(0, 0, 0, 0.8);
+}
+
+/*--------------
+      Down
+---------------*/
+
+.ui.checkbox .box:active::before,
+.ui.checkbox label:active::before {
+  background: #f9fafb;
+  border-color: rgba(34, 36, 38, 0.35);
+}
+.ui.checkbox .box:active::after,
+.ui.checkbox label:active::after {
+  color: rgba(0, 0, 0, 0.95);
+}
+.ui.checkbox input[type="checkbox"]:active ~ label,
+.ui.checkbox input[type="radio"]:active ~ label {
+  color: rgba(0, 0, 0, 0.95);
+}
+
+/*--------------
+     Focus
+---------------*/
+
+.ui.checkbox input[type="checkbox"]:focus ~ .box:before,
+.ui.checkbox input[type="checkbox"]:focus ~ label:before,
+.ui.checkbox input[type="radio"]:focus ~ .box:before,
+.ui.checkbox input[type="radio"]:focus ~ label:before {
+  background: #f9fafb;
+  border-color: rgba(34, 36, 38, 0.35);
+}
+.ui.checkbox input[type="checkbox"]:focus ~ .box:after,
+.ui.checkbox input[type="checkbox"]:focus ~ label:after,
+.ui.checkbox input[type="radio"]:focus ~ .box:after,
+.ui.checkbox input[type="radio"]:focus ~ label:after {
+  color: rgba(0, 0, 0, 0.95);
+}
+.ui.checkbox input[type="checkbox"]:focus ~ label,
+.ui.checkbox input[type="radio"]:focus ~ label {
+  color: rgba(0, 0, 0, 0.95);
+}
+
+/*--------------
+     Active
+---------------*/
+
+.ui.checkbox input:checked ~ .box:before,
+.ui.checkbox input:checked ~ label:before {
+  background: #ffffff;
+  border-color: rgba(34, 36, 38, 0.35);
+}
+.ui.checkbox input:checked ~ .box:after,
+.ui.checkbox input:checked ~ label:after {
+  opacity: 1;
+  color: rgba(0, 0, 0, 0.95);
+}
+
+/*--------------
+  Indeterminate
+---------------*/
+
+.ui.checkbox input:indeterminate ~ .box:before,
+.ui.checkbox input:indeterminate ~ label:before {
+  background: #ffffff;
+  border-color: rgba(34, 36, 38, 0.35);
+}
+.ui.checkbox input:indeterminate ~ .box:after,
+.ui.checkbox input:indeterminate ~ label:after {
+  opacity: 1;
+  color: rgba(0, 0, 0, 0.95);
+}
+
+/*--------------
+  Active Focus
+---------------*/
+
+.ui.checkbox input[type="radio"]:indeterminate:focus ~ .box:before,
+.ui.checkbox input[type="radio"]:indeterminate:focus ~ label:before,
+.ui.checkbox input[type="radio"]:checked:focus ~ .box:before,
+.ui.checkbox input[type="radio"]:checked:focus ~ label:before {
+  background: #f9fafb;
+  border-color: rgba(34, 36, 38, 0.35);
+}
+
+/*--------------
+    Read-Only
+---------------*/
+
+.ui.read-only.checkbox,
+.ui.read-only.checkbox label {
+  cursor: default;
+}
+
+/*--------------
+     Disabled
+---------------*/
+
+.ui.disabled.checkbox .box:after,
+.ui.disabled.checkbox label,
+.ui.checkbox input[disabled] ~ .box:after,
+.ui.checkbox input[disabled] ~ label {
+  cursor: default;
+  opacity: 0.5;
+  color: #000000;
+}
+
+/*--------------
+     Hidden
+---------------*/
+
+
+/* Initialized checkbox moves input below element
+ to prevent manually triggering */
+.ui.checkbox input[type="checkbox"].hidden,
+.ui.checkbox input[type="radio"].hidden {
+  z-index: -1;
+}
+
+/* Selectable Label */
+.ui.checkbox input[type="checkbox"].hidden + label,
+.ui.checkbox input[type="radio"].hidden + label {
+  cursor: pointer;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+}
+
+
+/*******************************
+             Types
+*******************************/
+
+
+/*--------------
+     Radio
+---------------*/
+
+.ui.radio.checkbox {
+  min-height: 15px;
+}
+.ui.radio.checkbox .box,
+.ui.radio.checkbox label {
+  padding-left: 1.85714em;
+}
+
+/* Box */
+.ui.radio.checkbox .box:before,
+.ui.radio.checkbox label:before {
+  content: '';
+  -webkit-transform: none;
+      -ms-transform: none;
+          transform: none;
+  width: 15px;
+  height: 15px;
+  border-radius: 500rem;
+  top: 1px;
+  left: 0px;
+}
+
+/* Bullet */
+.ui.radio.checkbox .box:after,
+.ui.radio.checkbox label:after {
+  border: none;
+  content: '' !important;
+  width: 15px;
+  height: 15px;
+  line-height: 15px;
+}
+
+/* Radio Checkbox */
+.ui.radio.checkbox .box:after,
+.ui.radio.checkbox label:after {
+  top: 1px;
+  left: 0px;
+  width: 15px;
+  height: 15px;
+  border-radius: 500rem;
+  -webkit-transform: scale(0.46666667);
+      -ms-transform: scale(0.46666667);
+          transform: scale(0.46666667);
+  background-color: rgba(0, 0, 0, 0.87);
+}
+
+/* Active */
+.ui.radio.checkbox input[type="radio"]:checked ~ .box:before,
+.ui.radio.checkbox input[type="radio"]:checked ~ label:before {
+  background-color: #ffffff;
+}
+.ui.radio.checkbox input[type="radio"]:checked ~ .box:after,
+.ui.radio.checkbox input[type="radio"]:checked ~ label:after {
+  background-color: rgba(0, 0, 0, 0.95);
+}
+
+/*--------------
+     Slider
+---------------*/
+
+.ui.slider.checkbox {
+  min-height: 1.25rem;
+}
+
+/* Input */
+.ui.slider.checkbox input[type="checkbox"],
+.ui.slider.checkbox input[type="radio"] {
+  width: 3.5rem;
+  height: 1.25rem;
+}
+
+/* Label */
+.ui.slider.checkbox .box,
+.ui.slider.checkbox label {
+  padding-left: 4.5rem;
+  line-height: 1rem;
+  color: rgba(0, 0, 0, 0.4);
+}
+
+/* Line */
+.ui.slider.checkbox .box:before,
+.ui.slider.checkbox label:before {
+  display: block;
+  position: absolute;
+  content: '';
+  border: none !important;
+  left: 0em;
+  z-index: 1;
+  top: 0.4rem;
+  background-color: rgba(0, 0, 0, 0.05);
+  width: 3.5rem;
+  height: 0.21428571rem;
+  -webkit-transform: none;
+      -ms-transform: none;
+          transform: none;
+  border-radius: 500rem;
+  -webkit-transition: background 0.3s ease;
+          transition: background 0.3s ease;
+}
+
+/* Handle */
+.ui.slider.checkbox .box:after,
+.ui.slider.checkbox label:after {
+  background: #ffffff -webkit-linear-gradient(transparent, rgba(0, 0, 0, 0.05));
+  background: #ffffff linear-gradient(transparent, rgba(0, 0, 0, 0.05));
+  position: absolute;
+  content: '' !important;
+  opacity: 1;
+  z-index: 2;
+  border: none;
+  box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15), 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset;
+  width: 1.5rem;
+  height: 1.5rem;
+  top: -0.25rem;
+  left: 0em;
+  -webkit-transform: none;
+      -ms-transform: none;
+          transform: none;
+  border-radius: 500rem;
+  -webkit-transition: left 0.3s ease;
+          transition: left 0.3s ease;
+}
+
+/* Focus */
+.ui.slider.checkbox input[type="checkbox"]:focus ~ .box:before,
+.ui.slider.checkbox input[type="checkbox"]:focus ~ label:before,
+.ui.slider.checkbox input[type="radio"]:focus ~ .box:before,
+.ui.slider.checkbox input[type="radio"]:focus ~ label:before {
+  background-color: rgba(0, 0, 0, 0.15);
+  border: none;
+}
+
+/* Hover */
+.ui.slider.checkbox .box:hover,
+.ui.slider.checkbox label:hover {
+  color: rgba(0, 0, 0, 0.8);
+}
+.ui.slider.checkbox .box:hover::before,
+.ui.slider.checkbox label:hover::before {
+  background: rgba(0, 0, 0, 0.15);
+}
+
+/* Active */
+.ui.slider.checkbox :checked ~ .box,
+.ui.slider.checkbox :checked ~ label {
+  color: rgba(0, 0, 0, 0.95);
+}
+.ui.slider.checkbox :checked ~ .box:before,
+.ui.slider.checkbox :checked ~ label:before {
+  background-color: #545454;
+}
+.ui.slider.checkbox :checked ~ .box:after,
+.ui.slider.checkbox :checked ~ label:after {
+  left: 2rem;
+}
+
+/*--------------
+     Toggle
+---------------*/
+
+.ui.toggle.checkbox {
+  min-height: 1.5rem;
+}
+
+/* Input */
+.ui.toggle.checkbox input[type="checkbox"],
+.ui.toggle.checkbox input[type="radio"] {
+  width: 3.5rem;
+  height: 1.5rem;
+}
+
+/* Label */
+.ui.toggle.checkbox .box,
+.ui.toggle.checkbox label {
+  min-height: 1.5rem;
+  padding-left: 4.5rem;
+  color: rgba(0, 0, 0, 0.87);
+}
+.ui.toggle.checkbox label {
+  padding-top: 0.15em;
+}
+
+/* Switch */
+.ui.toggle.checkbox .box:before,
+.ui.toggle.checkbox label:before {
+  display: block;
+  position: absolute;
+  content: '';
+  z-index: 1;
+  -webkit-transform: none;
+      -ms-transform: none;
+          transform: none;
+  border: none;
+  top: 0rem;
+  background: rgba(0, 0, 0, 0.05);
+  width: 3.5rem;
+  height: 1.5rem;
+  border-radius: 500rem;
+}
+
+/* Handle */
+.ui.toggle.checkbox .box:after,
+.ui.toggle.checkbox label:after {
+  background: #ffffff -webkit-linear-gradient(transparent, rgba(0, 0, 0, 0.05));
+  background: #ffffff linear-gradient(transparent, rgba(0, 0, 0, 0.05));
+  position: absolute;
+  content: '' !important;
+  opacity: 1;
+  z-index: 2;
+  border: none;
+  box-shadow: 0px 1px 2px 0 rgba(34, 36, 38, 0.15), 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset;
+  width: 1.5rem;
+  height: 1.5rem;
+  top: 0rem;
+  left: 0em;
+  border-radius: 500rem;
+  -webkit-transition: background 0.3s ease, left 0.3s ease;
+          transition: background 0.3s ease, left 0.3s ease;
+}
+.ui.toggle.checkbox input[type="checkbox"] ~ .box:after,
+.ui.toggle.checkbox input[type="checkbox"] ~ label:after,
+.ui.toggle.checkbox input[type="radio"] ~ .box:after,
+.ui.toggle.checkbox input[type="radio"] ~ label:after {
+  left: -0.05rem;
+}
+
+/* Focus */
+.ui.toggle.checkbox input[type="checkbox"]:focus ~ .box:before,
+.ui.toggle.checkbox input[type="checkbox"]:focus ~ label:before,
+.ui.toggle.checkbox input[type="radio"]:focus ~ .box:before,
+.ui.toggle.checkbox input[type="radio"]:focus ~ label:before {
+  background-color: rgba(0, 0, 0, 0.15);
+  border: none;
+}
+
+/* Hover */
+.ui.toggle.checkbox .box:hover::before,
+.ui.toggle.checkbox label:hover::before {
+  background-color: rgba(0, 0, 0, 0.15);
+  border: none;
+}
+
+/* Active */
+.ui.toggle.checkbox input:checked ~ .box,
+.ui.toggle.checkbox input:checked ~ label {
+  color: rgba(0, 0, 0, 0.95);
+}
+.ui.toggle.checkbox input:checked ~ .box:before,
+.ui.toggle.checkbox input:checked ~ label:before {
+  background-color: #2185d0;
+}
+.ui.toggle.checkbox input:checked ~ .box:after,
+.ui.toggle.checkbox input:checked ~ label:after {
+  left: 2.15rem;
+}
+
+
+/*******************************
+            Variations
+*******************************/
+
+
+/*--------------
+     Fitted
+---------------*/
+
+.ui.fitted.checkbox .box,
+.ui.fitted.checkbox label {
+  padding-left: 0em !important;
+}
+.ui.fitted.toggle.checkbox,
+.ui.fitted.toggle.checkbox {
+  width: 3.5rem;
+}
+.ui.fitted.slider.checkbox,
+.ui.fitted.slider.checkbox {
+  width: 3.5rem;
+}
+
+
+/*******************************
+         Theme Overrides
+*******************************/
+
+@font-face {
+  font-family: 'Checkbox';
+  src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SBD8AAAC8AAAAYGNtYXAYVtCJAAABHAAAAFRnYXNwAAAAEAAAAXAAAAAIZ2x5Zn4huwUAAAF4AAABYGhlYWQGPe1ZAAAC2AAAADZoaGVhB30DyAAAAxAAAAAkaG10eBBKAEUAAAM0AAAAHGxvY2EAmgESAAADUAAAABBtYXhwAAkALwAAA2AAAAAgbmFtZSC8IugAAAOAAAABknBvc3QAAwAAAAAFFAAAACAAAwMTAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADoAgPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAADAAAAAwAAABwAAQADAAAAHAADAAEAAAAcAAQAOAAAAAoACAACAAIAAQAg6AL//f//AAAAAAAg6AD//f//AAH/4xgEAAMAAQAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAABAEUAUQO7AvgAGgAAARQHAQYjIicBJjU0PwE2MzIfAQE2MzIfARYVA7sQ/hQQFhcQ/uMQEE4QFxcQqAF2EBcXEE4QAnMWEP4UEBABHRAXFhBOEBCoAXcQEE4QFwAAAAABAAABbgMlAkkAFAAAARUUBwYjISInJj0BNDc2MyEyFxYVAyUQEBf9SRcQEBAQFwK3FxAQAhJtFxAQEBAXbRcQEBAQFwAAAAABAAAASQMlA24ALAAAARUUBwYrARUUBwYrASInJj0BIyInJj0BNDc2OwE1NDc2OwEyFxYdATMyFxYVAyUQEBfuEBAXbhYQEO4XEBAQEBfuEBAWbhcQEO4XEBACEm0XEBDuFxAQEBAX7hAQF20XEBDuFxAQEBAX7hAQFwAAAQAAAAIAAHRSzT9fDzz1AAsEAAAAAADRsdR3AAAAANGx1HcAAAAAA7sDbgAAAAgAAgAAAAAAAAABAAADwP/AAAAEAAAAAAADuwABAAAAAAAAAAAAAAAAAAAABwQAAAAAAAAAAAAAAAIAAAAEAABFAyUAAAMlAAAAAAAAAAoAFAAeAE4AcgCwAAEAAAAHAC0AAQAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAOAK4AAQAAAAAAAQAIAAAAAQAAAAAAAgAHAGkAAQAAAAAAAwAIADkAAQAAAAAABAAIAH4AAQAAAAAABQALABgAAQAAAAAABgAIAFEAAQAAAAAACgAaAJYAAwABBAkAAQAQAAgAAwABBAkAAgAOAHAAAwABBAkAAwAQAEEAAwABBAkABAAQAIYAAwABBAkABQAWACMAAwABBAkABgAQAFkAAwABBAkACgA0ALBDaGVja2JveABDAGgAZQBjAGsAYgBvAHhWZXJzaW9uIDIuMABWAGUAcgBzAGkAbwBuACAAMgAuADBDaGVja2JveABDAGgAZQBjAGsAYgBvAHhDaGVja2JveABDAGgAZQBjAGsAYgBvAHhSZWd1bGFyAFIAZQBnAHUAbABhAHJDaGVja2JveABDAGgAZQBjAGsAYgBvAHhGb250IGdlbmVyYXRlZCBieSBJY29Nb29uLgBGAG8AbgB0ACAAZwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABJAGMAbwBNAG8AbwBuAC4AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) format('truetype');
+}
+
+/* Checkmark */
+.ui.checkbox label:after,
+.ui.checkbox .box:after {
+  font-family: 'Checkbox';
+}
+
+/* Checked */
+.ui.checkbox input:checked ~ .box:after,
+.ui.checkbox input:checked ~ label:after {
+  content: '\e800';
+}
+
+/* Indeterminate */
+.ui.checkbox input:indeterminate ~ .box:after,
+.ui.checkbox input:indeterminate ~ label:after {
+  font-size: 12px;
+  content: '\e801';
+}
+/*  UTF Reference
+.check:before { content: '\e800'; }
+.dash:before  { content: '\e801'; }
+.plus:before { content: '\e802'; }
+*/
+
+
+/*******************************
+         Site Overrides
+*******************************/
+

+ 706 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/checkbox.js

@@ -0,0 +1,706 @@
+/*!
+ * # Semantic UI 2.0.0 - Checkbox
+ * http://github.com/semantic-org/semantic-ui/
+ *
+ *
+ * Copyright 2015 Contributors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ */
+
+;(function ( $, window, document, undefined ) {
+
+"use strict";
+
+$.fn.checkbox = function(parameters) {
+  var
+    $allModules    = $(this),
+    moduleSelector = $allModules.selector || '',
+
+    time           = new Date().getTime(),
+    performance    = [],
+
+    query          = arguments[0],
+    methodInvoked  = (typeof query == 'string'),
+    queryArguments = [].slice.call(arguments, 1),
+    returnedValue
+  ;
+
+  $allModules
+    .each(function() {
+      var
+        settings        = $.extend(true, {}, $.fn.checkbox.settings, parameters),
+
+        className       = settings.className,
+        namespace       = settings.namespace,
+        selector        = settings.selector,
+        error           = settings.error,
+
+        eventNamespace  = '.' + namespace,
+        moduleNamespace = 'module-' + namespace,
+
+        $module         = $(this),
+        $label          = $(this).children(selector.label),
+        $input          = $(this).children(selector.input),
+
+        instance        = $module.data(moduleNamespace),
+
+        observer,
+        element         = this,
+        module
+      ;
+
+      module      = {
+
+        initialize: function() {
+          module.verbose('Initializing checkbox', settings);
+
+          module.create.label();
+          module.bind.events();
+
+          module.set.tabbable();
+          module.hide.input();
+
+          module.observeChanges();
+          module.instantiate();
+          module.setup();
+        },
+
+        instantiate: function() {
+          module.verbose('Storing instance of module', module);
+          instance = module;
+          $module
+            .data(moduleNamespace, module)
+          ;
+        },
+
+        destroy: function() {
+          module.verbose('Destroying module');
+          module.unbind.events();
+          module.show.input();
+          $module.removeData(moduleNamespace);
+        },
+
+        fix: {
+          reference: function() {
+            if( $module.is(selector.input) ) {
+              module.debug('Behavior called on <input> adjusting invoked element');
+              $module = $module.closest(selector.checkbox);
+              module.refresh();
+            }
+          }
+        },
+
+        setup: function() {
+          if( module.is.indeterminate() ) {
+            module.debug('Initial value is indeterminate');
+            module.set.indeterminate();
+            if(settings.fireOnInit) {
+              settings.onIndeterminate.call($input[0]);
+              settings.onChange.call($input[0]);
+            }
+          }
+          else if( module.is.checked() ) {
+            module.debug('Initial value is checked');
+            module.set.checked();
+            if(settings.fireOnInit) {
+              settings.onChecked.call($input[0]);
+              settings.onChange.call($input[0]);
+            }
+          }
+          else {
+            module.debug('Initial value is unchecked');
+            module.set.unchecked();
+            if(settings.fireOnInit) {
+              settings.onUnchecked.call($input[0]);
+              settings.onChange.call($input[0]);
+            }
+          }
+        },
+
+        refresh: function() {
+          $label = $module.children(selector.label);
+          $input = $module.children(selector.input);
+        },
+
+        hide: {
+          input: function() {
+            module.verbose('Modfying <input> z-index to be unselectable');
+            $input.addClass(className.hidden);
+          }
+        },
+        show: {
+          input: function() {
+            module.verbose('Modfying <input> z-index to be selectable');
+            $input.removeClass(className.hidden);
+          }
+        },
+
+        observeChanges: function() {
+          if('MutationObserver' in window) {
+            observer = new MutationObserver(function(mutations) {
+              module.debug('DOM tree modified, updating selector cache');
+              module.refresh();
+            });
+            observer.observe(element, {
+              childList : true,
+              subtree   : true
+            });
+            module.debug('Setting up mutation observer', observer);
+          }
+        },
+
+        attachEvents: function(selector, event) {
+          var
+            $element = $(selector)
+          ;
+          event = $.isFunction(module[event])
+            ? module[event]
+            : module.toggle
+          ;
+          if($element.length > 0) {
+            module.debug('Attaching checkbox events to element', selector, event);
+            $element
+              .on('click' + eventNamespace, event)
+            ;
+          }
+          else {
+            module.error(error.notFound);
+          }
+        },
+
+        event: {
+          click: function(event) {
+            if( $(event.target).is(selector.input) ) {
+              module.verbose('Using default check action on initialized checkbox');
+              return;
+            }
+            module.toggle();
+          },
+          keydown: function(event) {
+            var
+              key     = event.which,
+              keyCode = {
+                enter  : 13,
+                space  : 32,
+                escape : 27
+              }
+            ;
+            if(key == keyCode.escape) {
+              module.verbose('Escape key pressed blurring field');
+              $input.blur();
+              event.preventDefault();
+            }
+            if(!event.ctrlKey && (key == keyCode.enter || key == keyCode.space)) {
+              module.verbose('Enter key pressed, toggling checkbox');
+              module.toggle();
+              event.preventDefault();
+            }
+          }
+        },
+
+        check: function() {
+          if( !module.is.indeterminate() && module.is.checked() ) {
+            module.debug('Checkbox is already checked');
+            return;
+          }
+          module.debug('Checking checkbox', $input);
+          module.set.checked();
+          settings.onChecked.call($input[0]);
+          settings.onChange.call($input[0]);
+        },
+
+        uncheck: function() {
+          if( !module.is.indeterminate() && module.is.unchecked() ) {
+            module.debug('Checkbox is already unchecked');
+            return;
+          }
+          module.debug('Unchecking checkbox');
+          module.set.unchecked();
+          settings.onUnchecked.call($input[0]);
+          settings.onChange.call($input[0]);
+        },
+
+        indeterminate: function() {
+          if( module.is.indeterminate() ) {
+            module.debug('Checkbox is already indeterminate');
+            return;
+          }
+          module.debug('Making checkbox indeterminate');
+          module.set.indeterminate();
+          settings.onIndeterminate.call($input[0]);
+          settings.onChange.call($input[0]);
+        },
+
+        determinate: function() {
+          if( module.is.determinate() ) {
+            module.debug('Checkbox is already determinate');
+            return;
+          }
+          module.debug('Making checkbox determinate');
+          module.set.determinate();
+          settings.onDeterminate.call($input[0]);
+          settings.onChange.call($input[0]);
+        },
+
+        enable: function() {
+          if( module.is.enabled() ) {
+            module.debug('Checkbox is already enabled');
+            return;
+          }
+          module.debug('Enabling checkbox');
+          module.set.enabled();
+          settings.onEnable.call($input[0]);
+        },
+
+        disable: function() {
+          if( module.is.disabled() ) {
+            module.debug('Checkbox is already disabled');
+            return;
+          }
+          module.debug('Disabling checkbox');
+          module.set.disabled();
+          settings.onDisable.call($input[0]);
+        },
+
+        get: {
+          radios: function() {
+            var
+              name = module.get.name()
+            ;
+            return $('input[name="' + name + '"]').closest(selector.checkbox);
+          },
+          name: function() {
+            return $input.attr('name');
+          }
+        },
+
+        is: {
+          radio: function() {
+            return ($input.hasClass(className.radio) || $input.attr('type') == 'radio');
+          },
+          indeterminate: function() {
+            return $input.prop('indeterminate') !== undefined && $input.prop('indeterminate');
+          },
+          checked: function() {
+            return $input.prop('checked') !== undefined && $input.prop('checked');
+          },
+          disabled: function() {
+            return $input.prop('disabled') !== undefined && $input.prop('disabled');
+          },
+          enabled: function() {
+            return !module.is.disabled();
+          },
+          determinate: function() {
+            return !module.is.indeterminate();
+          },
+          unchecked: function() {
+            return !module.is.checked();
+          }
+        },
+
+        can: {
+          change: function() {
+            return !( $module.hasClass(className.disabled) || $module.hasClass(className.readOnly) || $input.prop('disabled') || $input.prop('readonly') );
+          },
+          uncheck: function() {
+            return (typeof settings.uncheckable === 'boolean')
+              ? settings.uncheckable
+              : !module.is.radio()
+            ;
+          }
+        },
+
+        set: {
+          checked: function() {
+            if(!module.is.indeterminate() && module.is.checked()) {
+              module.debug('Input is already checked');
+              return;
+            }
+            module.verbose('Setting state to checked', $input[0]);
+            if( module.is.radio() ) {
+              module.uncheckOthers();
+            }
+            $input
+              .prop('indeterminate', false)
+              .prop('checked', true)
+            ;
+            $module
+              .removeClass(className.indeterminate)
+              .addClass(className.checked)
+            ;
+            module.trigger.change();
+          },
+          unchecked: function() {
+            if(!module.is.indeterminate() &&  module.is.unchecked() ) {
+              module.debug('Input is already unchecked');
+              return;
+            }
+            module.debug('Setting state to unchecked');
+            $input
+              .prop('indeterminate', false)
+              .prop('checked', false)
+            ;
+            $module
+              .removeClass(className.indeterminate)
+              .removeClass(className.checked)
+            ;
+            module.trigger.change();
+          },
+          indeterminate: function() {
+            if( module.is.indeterminate() ) {
+              module.debug('Input is already indeterminate');
+              return;
+            }
+            module.debug('Setting state to indeterminate');
+            $input
+              .prop('indeterminate', true)
+            ;
+            $module
+              .addClass(className.indeterminate)
+            ;
+            module.trigger.change();
+          },
+          determinate: function() {
+            if( module.is.determinate() ) {
+              module.debug('Input is already determinate');
+              return;
+            }
+            module.debug('Setting state to determinate');
+            $input
+              .prop('indeterminate', false)
+            ;
+            $module
+              .removeClass(className.indeterminate)
+            ;
+          },
+          disabled: function() {
+            if( module.is.disabled() ) {
+              module.debug('Input is already disabled');
+              return;
+            }
+            module.debug('Setting state to disabled');
+            $input
+              .prop('disabled', 'disabled')
+            ;
+            $module
+              .addClass(className.disabled)
+            ;
+            module.trigger.change();
+          },
+          enabled: function() {
+            if( module.is.enabled() ) {
+              module.debug('Input is already enabled');
+              return;
+            }
+            module.debug('Setting state to enabled');
+            $input
+              .prop('disabled', false)
+            ;
+            $module.removeClass(className.disabled);
+            module.trigger.change();
+          },
+          tabbable: function() {
+            module.verbose('Adding tabindex to checkbox');
+            if( $input.attr('tabindex') === undefined) {
+              $input.attr('tabindex', 0);
+            }
+          }
+        },
+
+        trigger: {
+          change: function() {
+            module.verbose('Triggering change event from programmatic change');
+            $input
+              .trigger('change')
+            ;
+          }
+        },
+
+
+        create: {
+          label: function() {
+            if($input.prevAll(selector.label).length > 0) {
+              $input.prev(selector.label).detach().insertAfter($input);
+              module.debug('Moving existing label', $label);
+            }
+            else if( !module.has.label() ) {
+              $label = $('<label>').insertAfter($input);
+              module.debug('Creating label', $label);
+            }
+          }
+        },
+
+        has: {
+          label: function() {
+            return ($label.length > 0);
+          }
+        },
+
+        bind: {
+          events: function() {
+            module.verbose('Attaching checkbox events');
+            $module
+              .on('click'   + eventNamespace, module.event.click)
+              .on('keydown' + eventNamespace, selector.input, module.event.keydown)
+            ;
+          }
+        },
+
+        unbind: {
+          events: function() {
+            module.debug('Removing events');
+            $module
+              .off(eventNamespace)
+            ;
+          }
+        },
+
+        uncheckOthers: function() {
+          var
+            $radios = module.get.radios()
+          ;
+          module.debug('Unchecking other radios', $radios);
+          $radios.removeClass(className.checked);
+        },
+
+        toggle: function() {
+          if( !module.can.change() ) {
+            if(!module.is.radio()) {
+              module.debug('Checkbox is read-only or disabled, ignoring toggle');
+            }
+            return;
+          }
+          if( module.is.indeterminate() || module.is.unchecked() ) {
+            module.debug('Currently unchecked');
+            module.check();
+          }
+          else if( module.is.checked() && module.can.uncheck() ) {
+            module.debug('Currently checked');
+            module.uncheck();
+          }
+        },
+        setting: function(name, value) {
+          module.debug('Changing setting', name, value);
+          if( $.isPlainObject(name) ) {
+            $.extend(true, settings, name);
+          }
+          else if(value !== undefined) {
+            settings[name] = value;
+          }
+          else {
+            return settings[name];
+          }
+        },
+        internal: function(name, value) {
+          if( $.isPlainObject(name) ) {
+            $.extend(true, module, name);
+          }
+          else if(value !== undefined) {
+            module[name] = value;
+          }
+          else {
+            return module[name];
+          }
+        },
+        debug: function() {
+          if(settings.debug) {
+            if(settings.performance) {
+              module.performance.log(arguments);
+            }
+            else {
+              module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
+              module.debug.apply(console, arguments);
+            }
+          }
+        },
+        verbose: function() {
+          if(settings.verbose && settings.debug) {
+            if(settings.performance) {
+              module.performance.log(arguments);
+            }
+            else {
+              module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
+              module.verbose.apply(console, arguments);
+            }
+          }
+        },
+        error: function() {
+          module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
+          module.error.apply(console, arguments);
+        },
+        performance: {
+          log: function(message) {
+            var
+              currentTime,
+              executionTime,
+              previousTime
+            ;
+            if(settings.performance) {
+              currentTime   = new Date().getTime();
+              previousTime  = time || currentTime;
+              executionTime = currentTime - previousTime;
+              time          = currentTime;
+              performance.push({
+                'Name'           : message[0],
+                'Arguments'      : [].slice.call(message, 1) || '',
+                'Element'        : element,
+                'Execution Time' : executionTime
+              });
+            }
+            clearTimeout(module.performance.timer);
+            module.performance.timer = setTimeout(module.performance.display, 500);
+          },
+          display: function() {
+            var
+              title = settings.name + ':',
+              totalTime = 0
+            ;
+            time = false;
+            clearTimeout(module.performance.timer);
+            $.each(performance, function(index, data) {
+              totalTime += data['Execution Time'];
+            });
+            title += ' ' + totalTime + 'ms';
+            if(moduleSelector) {
+              title += ' \'' + moduleSelector + '\'';
+            }
+            if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
+              console.groupCollapsed(title);
+              if(console.table) {
+                console.table(performance);
+              }
+              else {
+                $.each(performance, function(index, data) {
+                  console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
+                });
+              }
+              console.groupEnd();
+            }
+            performance = [];
+          }
+        },
+        invoke: function(query, passedArguments, context) {
+          var
+            object = instance,
+            maxDepth,
+            found,
+            response
+          ;
+          passedArguments = passedArguments || queryArguments;
+          context         = element         || context;
+          if(typeof query == 'string' && object !== undefined) {
+            query    = query.split(/[\. ]/);
+            maxDepth = query.length - 1;
+            $.each(query, function(depth, value) {
+              var camelCaseValue = (depth != maxDepth)
+                ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
+                : query
+              ;
+              if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
+                object = object[camelCaseValue];
+              }
+              else if( object[camelCaseValue] !== undefined ) {
+                found = object[camelCaseValue];
+                return false;
+              }
+              else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
+                object = object[value];
+              }
+              else if( object[value] !== undefined ) {
+                found = object[value];
+                return false;
+              }
+              else {
+                module.error(error.method, query);
+                return false;
+              }
+            });
+          }
+          if ( $.isFunction( found ) ) {
+            response = found.apply(context, passedArguments);
+          }
+          else if(found !== undefined) {
+            response = found;
+          }
+          if($.isArray(returnedValue)) {
+            returnedValue.push(response);
+          }
+          else if(returnedValue !== undefined) {
+            returnedValue = [returnedValue, response];
+          }
+          else if(response !== undefined) {
+            returnedValue = response;
+          }
+          return found;
+        }
+      };
+
+      if(methodInvoked) {
+        if(instance === undefined) {
+          module.initialize();
+        }
+        module.invoke(query);
+      }
+      else {
+        if(instance !== undefined) {
+          instance.invoke('destroy');
+        }
+        module.initialize();
+      }
+    })
+  ;
+
+  return (returnedValue !== undefined)
+    ? returnedValue
+    : this
+  ;
+};
+
+$.fn.checkbox.settings = {
+
+  name            : 'Checkbox',
+  namespace       : 'checkbox',
+
+  debug           : false,
+  verbose         : true,
+  performance     : true,
+
+  // delegated event context
+  uncheckable     : 'auto',
+  fireOnInit      : false,
+
+  onChange        : function(){},
+
+  onChecked       : function(){},
+  onUnchecked     : function(){},
+
+  onDeterminate   : function() {},
+  onIndeterminate : function() {},
+
+  onEnabled       : function(){},
+  onDisabled      : function(){},
+
+  className       : {
+    checked       : 'checked',
+    indeterminate : 'indeterminate',
+    disabled      : 'disabled',
+    hidden        : 'hidden',
+    radio         : 'radio',
+    readOnly      : 'read-only'
+  },
+
+  error     : {
+    method       : 'The method you called is not defined'
+  },
+
+  selector : {
+    checkbox : '.ui.checkbox',
+    label    : 'label, .box',
+    input    : 'input[type="checkbox"], input[type="radio"]',
+  }
+
+};
+
+})( jQuery, window , document );

Разница между файлами не показана из-за своего большого размера
+ 9 - 0
jdc/chatServer/trunk/src/main/webapp/assets/components/checkbox.min.css


Некоторые файлы не были показаны из-за большого количества измененных файлов