ccjgmwz há 3 anos atrás
pai
commit
3af05700df
100 ficheiros alterados com 4150 adições e 16649 exclusões
  1. BIN
      .DS_Store
  2. 2 0
      .gitattributes
  3. 3 4
      .gitignore
  4. 0 3
      README.md
  5. 2 1
      pom.xml
  6. 625 187
      sql/unimall_tmp.sql
  7. BIN
      unimall-admin-api/.DS_Store
  8. 2 64
      unimall-admin-api/pom.xml
  9. BIN
      unimall-admin-api/src/.DS_Store
  10. BIN
      unimall-admin-api/src/main/.DS_Store
  11. BIN
      unimall-admin-api/src/main/java/.DS_Store
  12. BIN
      unimall-admin-api/src/main/java/com/.DS_Store
  13. BIN
      unimall-admin-api/src/main/java/com/iotechn/.DS_Store
  14. BIN
      unimall-admin-api/src/main/java/com/iotechn/unimall/.DS_Store
  15. BIN
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/.DS_Store
  16. 0 16
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/CommonUtils.java
  17. 0 77
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/QRCodeGenerator.java
  18. BIN
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/.DS_Store
  19. 60 72
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/admin/AdminService.java
  20. 195 302
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/admin/AdminServiceImpl.java
  21. 72 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/advertisement/AdminAdvertisementService.java
  22. 111 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/advertisement/AdminAdvertisementServiceImpl.java
  23. 40 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/appraise/AdminAppraise.java
  24. 46 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/appraise/AdminAppraiseImpl.java
  25. 62 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/category/AdminCategoryService.java
  26. 304 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/category/AdminCategoryServiceImpl.java
  27. 10 3
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/config/AdminMerchantConfigService.java
  28. 82 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/coupon/AdminCouponService.java
  29. 123 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/coupon/AdminCouponServiceImpl.java
  30. 2 6
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dashboard/DashboardService.java
  31. 44 10
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dashboard/DashboardServiceImpl.java
  32. 50 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dict/DictDataService.java
  33. 77 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dict/DictDataserviceImpl.java
  34. 48 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dict/DictTypeService.java
  35. 86 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dict/DictTypeServiceImpl.java
  36. 62 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/freight/AdminFreightTemplateService.java
  37. 147 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/freight/AdminFreightTemplateServiceImpl.java
  38. 64 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/goods/AdminGoodsService.java
  39. 414 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/goods/AdminGoodsServiceImpl.java
  40. 55 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/goods/AdminGroupShopGoodsService.java
  41. 290 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/goods/AdminGroupShopGoodsServiceImpl.java
  42. 40 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/log/loginLog/SysLogininforService.java
  43. 87 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/log/loginLog/SysLogininforServiceImpl.java
  44. 40 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/log/operLog/OperLogService.java
  45. 87 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/log/operLog/OperLogServiceImpl.java
  46. 0 55
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/message/MessageService.java
  47. 0 85
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/message/MessageServiceImpl.java
  48. 21 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/monitor/online/UserOnlineService.java
  49. 45 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/monitor/online/UserOnlineServiceImpl.java
  50. 11 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/monitor/server/ServerService.java
  51. 22 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/monitor/server/ServerServiceImpl.java
  52. 57 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/order/AdminOrderService.java
  53. 198 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/order/AdminOrderServiceImpl.java
  54. 54 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/recommend/AdminRecommendService.java
  55. 99 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/recommend/AdminRecommendServiceImpl.java
  56. 14 18
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/role/RoleService.java
  57. 5 10
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/role/RoleServiceImpl.java
  58. 0 62
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/sys/DictService.java
  59. 0 106
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/sys/DictServiceImpl.java
  60. 0 39
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/tools/GeneratorService.java
  61. 0 215
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/tools/GeneratorServiceImpl.java
  62. 74 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/tools/gen/GenTableService.java
  63. 179 0
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/tools/gen/GenTableServiceImpl.java
  64. 9 26
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/user/AdminUserService.java
  65. 30 148
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/user/AdminUserServiceImpl.java
  66. 0 127
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/config/SendWxMsg.java
  67. 0 131
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/config/WebSocket.java
  68. 0 18
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/config/WebSocketConfig.java
  69. 0 548
      unimall-admin-api/src/main/java/com/iotechn/unimall/admin/utils/DateUtils.java
  70. 0 48
      unimall-admin-api/src/main/resources/apijs.ftl
  71. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/bg.png
  72. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/breadcrumbs.png
  73. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/checker-bg.png
  74. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/blue/message_catch.png
  75. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/business_rule.png
  76. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/error_catch.png
  77. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/error_throw.png
  78. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/manual.png
  79. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/message_catch.png
  80. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/message_throw.png
  81. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/receive.png
  82. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/script.png
  83. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/send.png
  84. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/service.png
  85. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/signal_catch.png
  86. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/signal_throw.png
  87. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/timer.png
  88. BIN
      unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/user.png
  89. 0 130
      unimall-admin-api/src/main/resources/diagram-viewer/index.html
  90. 0 74
      unimall-admin-api/src/main/resources/diagram-viewer/js/ActivitiRest.js
  91. 0 0
      unimall-admin-api/src/main/resources/diagram-viewer/js/ActivityImpl.js
  92. 0 603
      unimall-admin-api/src/main/resources/diagram-viewer/js/Color.js
  93. 0 270
      unimall-admin-api/src/main/resources/diagram-viewer/js/LineBreakMeasurer.js
  94. 0 387
      unimall-admin-api/src/main/resources/diagram-viewer/js/Polyline.js
  95. 0 2172
      unimall-admin-api/src/main/resources/diagram-viewer/js/ProcessDiagramCanvas.js
  96. 0 1087
      unimall-admin-api/src/main/resources/diagram-viewer/js/ProcessDiagramGenerator.js
  97. 0 125
      unimall-admin-api/src/main/resources/diagram-viewer/js/jquery/jquery.asyncqueue.js
  98. 0 9266
      unimall-admin-api/src/main/resources/diagram-viewer/js/jquery/jquery.js
  99. 0 131
      unimall-admin-api/src/main/resources/diagram-viewer/js/jquery/jquery.progressbar.js
  100. 0 23
      unimall-admin-api/src/main/resources/diagram-viewer/js/jstools.js

BIN
.DS_Store


+ 2 - 0
.gitattributes

@@ -0,0 +1,2 @@
+*.sql linguist-language=java
+*.html linguist-language=java

+ 3 - 4
.gitignore

@@ -48,7 +48,9 @@ mvnw.cmd
 /unimall-core/target/
 /unimall-launcher/target/
 /unimall-plugin-core/target/
-/unimall-app/unpackage/
+/unimall-app/unpackage/dist/
+/unimall-app/unpackage/resources/
+/unimall-app/unpackage/debug/
 /unimall-admin/dist.zip
 
 ###node_modules###
@@ -61,9 +63,6 @@ unimall.log
 unimall.log.*.gz
 unimall.log.*.tmp
 
-###templates###
-/templates/
-
 
 ### plugins ###
 /plugins/

+ 0 - 3
README.md

@@ -1,3 +0,0 @@
-# uni_project
-
-uni极简前后端模板

+ 2 - 1
pom.xml

@@ -6,7 +6,7 @@
 	<parent>
 		<groupId>org.springframework.boot</groupId>
 		<artifactId>spring-boot-starter-parent</artifactId>
-		<version>2.1.5.RELEASE</version>
+		<version>2.1.2.RELEASE</version>
 		<relativePath/> <!-- lookup parent from repository -->
 	</parent>
 	<groupId>com.iotechn</groupId>
@@ -53,6 +53,7 @@
 				<artifactId>okhttp</artifactId>
 				<version>3.10.0</version>
 			</dependency>
+
 			<!-- 良心云 sms -->
 			<dependency>
 				<groupId>com.github.qcloudsms</groupId>

Diff do ficheiro suprimidas por serem muito extensas
+ 625 - 187
sql/unimall_tmp.sql


BIN
unimall-admin-api/.DS_Store


+ 2 - 64
unimall-admin-api/pom.xml

@@ -15,8 +15,6 @@
 
 	<properties>
 		<java.version>1.8</java.version>
-		<activiti.version>5.22.0</activiti.version>
-		<hutool.version>5.2.0</hutool.version>
 	</properties>
 
 	<repositories>
@@ -40,43 +38,12 @@
 	</repositories>
 
 	<dependencies>
-		<dependency>
-			<groupId>com.google.zxing</groupId>
-			<artifactId>core</artifactId>
-			<version>3.3.0</version>
-		</dependency>
-		<dependency>
-			<groupId>com.google.zxing</groupId>
-			<artifactId>javase</artifactId>
-			<version>3.3.0</version>
-		</dependency>
+
 		<dependency>
 			<groupId>com.iotechn</groupId>
 			<artifactId>unimall-core</artifactId>
 			<version>0.0.1-RELEASE</version>
-			<exclusions>
-				<exclusion>
-					<artifactId>activation</artifactId>
-					<groupId>javax.activation</groupId>
-				</exclusion>
-			</exclusions>
-		</dependency>
-		<dependency>
-			<groupId>tk.mybatis</groupId>
-			<artifactId>mapper-spring-boot-starter</artifactId>
-			<version>2.1.5</version>
-		</dependency>
-		<dependency>
-			<groupId>tk.mybatis</groupId>
-			<artifactId>mapper-spring-boot-autoconfigure</artifactId>
-			<version>2.1.5</version>
-		</dependency>
-		<!-- 模板引擎 -->
-		<dependency>
-			<groupId>org.freemarker</groupId>
-			<artifactId>freemarker</artifactId>
 		</dependency>
-
 		<!-- 插件核心依赖 勿删 -->
 		<dependency>
 			<groupId>com.iotechn</groupId>
@@ -100,12 +67,6 @@
 		<dependency>
 			<groupId>com.github.binarywang</groupId>
 			<artifactId>weixin-java-pay</artifactId>
-			<exclusions>
-				<exclusion>
-					<artifactId>commons-logging</artifactId>
-					<groupId>commons-logging</groupId>
-				</exclusion>
-			</exclusions>
 		</dependency>
 
 		<dependency>
@@ -123,29 +84,6 @@
 			<artifactId>spring-boot-starter-test</artifactId>
 			<scope>test</scope>
 		</dependency>
-		<dependency>
-			<groupId>cn.hutool</groupId>
-			<artifactId>hutool-all</artifactId>
-			<version>${hutool.version}</version>
-		</dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-websocket</artifactId>
-        </dependency>
-		<dependency>
-			<groupId>org.apache.tomcat.embed</groupId>
-			<artifactId>tomcat-embed-websocket</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>com.google.zxing</groupId>
-			<artifactId>core</artifactId>
-			<version>3.3.0</version>
-			<scope>compile</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.springframework</groupId>
-			<artifactId>spring-test</artifactId>
-		</dependency>
-    </dependencies>
+	</dependencies>
 
 </project>

BIN
unimall-admin-api/src/.DS_Store


BIN
unimall-admin-api/src/main/.DS_Store


BIN
unimall-admin-api/src/main/java/.DS_Store


BIN
unimall-admin-api/src/main/java/com/.DS_Store


BIN
unimall-admin-api/src/main/java/com/iotechn/.DS_Store


BIN
unimall-admin-api/src/main/java/com/iotechn/unimall/.DS_Store


BIN
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/.DS_Store


+ 0 - 16
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/CommonUtils.java

@@ -1,16 +0,0 @@
-package com.iotechn.unimall.admin;
-
-import com.iotechn.unimall.data.domain.SysDictDataDO;
-
-import java.util.List;
-
-public class CommonUtils {
-    public static  String selectDictLabel(List<SysDictDataDO> datas, String id){
-        for(SysDictDataDO sysDictDataDO : datas){
-            if(sysDictDataDO.getValue().equals(id)){
-                return sysDictDataDO.getLabel();
-            }
-        }
-        return "";
-    }
-}

+ 0 - 77
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/QRCodeGenerator.java

@@ -1,77 +0,0 @@
-package com.iotechn.unimall.admin;
-
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.FileSystems;
-import java.nio.file.Path;
-import java.util.Hashtable;
-
-import com.aliyun.oss.OSSClient;
-import com.aliyun.oss.model.ObjectMetadata;
-import com.aliyun.oss.model.PutObjectRequest;
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.EncodeHintType;
-import com.google.zxing.WriterException;
-import com.google.zxing.client.j2se.MatrixToImageWriter;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.qrcode.QRCodeWriter;
-import com.iotechn.unimall.core.util.GeneratorUtil;
-import org.apache.http.entity.ContentType;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.mock.web.MockMultipartFile;
-import org.springframework.stereotype.Component;
-import org.springframework.web.multipart.MultipartFile;
-
-@Component
-public class QRCodeGenerator implements InitializingBean {
-    @Value("${oss.aliyun.oss.basekUrl}")
-    private String baseUrl;
-    @Value("${oss.aliyun.oss.bucket}")
-    private String bucket;
-    @Autowired
-    private OSSClient ossClient;
-    @Value("${oss.aliyun.oss.endpoint}")
-    private String endpoint;
-
-    private String host;
-    @Override
-    public void afterPropertiesSet() throws Exception {
-        host = "http://" + bucket + "." + endpoint;
-    }
-    public  String generateQRCodeImage(String text, int width, int height,String sendCarNo) throws WriterException, IOException {
-        QRCodeWriter qrCodeWriter = new QRCodeWriter();
-        Hashtable<EncodeHintType, Object> hints = new Hashtable();
-        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
-        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height,hints);
-
-        File file = new File( new String(("templates" + File.separator + sendCarNo+".png").getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
-        Path path = FileSystems.getDefault().getPath(file.getAbsoluteFile().getPath());
-
-        MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
-
-        FileInputStream fileInputStream = new FileInputStream(file.getAbsoluteFile());
-
-        MultipartFile multipartFile = new MockMultipartFile( ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
-        return upload(multipartFile,sendCarNo);
-    }
-    /**
-     * 后台通过服务器间接传文件
-     * @param file
-     * @return
-     * @throws IOException
-     */
-    public  String upload(MultipartFile file,String sendCarNo) throws IOException {
-        ObjectMetadata objectMetadata = new ObjectMetadata();
-        objectMetadata.setContentLength(file.getSize());
-        objectMetadata.setContentType(file.getContentType());
-        PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, "QRCode/" +sendCarNo+".png", file.getInputStream(), objectMetadata);
-        ossClient.putObject(putObjectRequest);
-        return baseUrl + "QRCode/" + sendCarNo+".png";
-    }
-}

BIN
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/.DS_Store


+ 60 - 72
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/admin/AdminService.java

@@ -1,7 +1,5 @@
 package com.iotechn.unimall.admin.api.admin;
 
-
-import com.google.zxing.WriterException;
 import com.iotechn.unimall.core.Const;
 import com.iotechn.unimall.core.annotation.HttpMethod;
 import com.iotechn.unimall.core.annotation.HttpOpenApi;
@@ -9,83 +7,73 @@ import com.iotechn.unimall.core.annotation.HttpParam;
 import com.iotechn.unimall.core.annotation.HttpParamType;
 import com.iotechn.unimall.core.annotation.param.NotNull;
 import com.iotechn.unimall.core.exception.ServiceException;
-import com.iotechn.unimall.data.domain.AdminDO;
-import com.iotechn.unimall.data.domain.UserDO;
 import com.iotechn.unimall.data.dto.AdminDTO;
 import com.iotechn.unimall.data.model.Page;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.List;
-
 /**
  * Created by rize on 2019/4/8.
  */
 @HttpOpenApi(group = "admin", description = "管理员服务")
 public interface AdminService {
 
-    @HttpMethod(description = "管理员登录 返回AccessToken")
-    String login(
-            @NotNull @HttpParam(name = "username", type = HttpParamType.COMMON, description = "用户名") String username,
-            @NotNull @HttpParam(name = "password", type = HttpParamType.COMMON, description = "密码") String password,
-            @NotNull @HttpParam(name = "verifyCode", type = HttpParamType.COMMON, description = "验证码") String verifyCode) throws ServiceException;
-
-    @HttpMethod(description = "管理员登出")
-    String logout(
-            @NotNull @HttpParam(name = Const.ADMIN_ACCESS_TOKEN, type = HttpParamType.HEADER, description = "访问Token") String accessToken,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
-
-    @HttpMethod(description = "管理员信息")
-    AdminDTO info(
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
-
-    @HttpMethod(description = "列表", permission = "admin:admin:list", permissionParentName = "系统管理", permissionName = "管理员")
-    Page<AdminDTO> list(
-            @HttpParam(name = "username", type = HttpParamType.COMMON, description = "管理员名称搜索") String name,
-            @HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
-            @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页长度", valueDef = "20") Integer limit,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-
-    @HttpMethod(description = "创建", permission = "admin:admin:create", permissionParentName = "系统管理", permissionName = "管理员")
-    AdminDTO create(
-            @NotNull @HttpParam(name = "adminDTO", type = HttpParamType.COMMON, description = "欲创建的admin对象JSON") AdminDTO adminDTO,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-
-    @HttpMethod(description = "修改", permission = "admin:admin:update", permissionParentName = "系统管理", permissionName = "管理员")
-    String update(
-            @NotNull @HttpParam(name = "adminDTO", type = HttpParamType.COMMON, description = "欲修改的admin对象JSON") AdminDTO adminDTO,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-
-    @HttpMethod(description = "删除", permission = "admin:admin:delete", permissionParentName = "系统管理", permissionName = "管理员")
-    String delete(
-            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "目标删除Id") Long id,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
-
-    @HttpMethod(description = "更改密码")
-    String newPassword(
-            @HttpParam(name = Const.ADMIN_ACCESS_TOKEN, type = HttpParamType.HEADER, description = "访问Token") String accessToken,
-            @NotNull @HttpParam(name = "oldPassword", type = HttpParamType.COMMON, description = "老密码") String oldPassword,
-            @NotNull @HttpParam(name = "newPassword", type = HttpParamType.COMMON, description = "新密码") String newPassword,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
-
-    @HttpMethod(description = "发送登陆短信")
-    Boolean sendLoginMsg(
-            @NotNull @HttpParam(name = "username", type = HttpParamType.COMMON, description = "用户名") String username,
-            @NotNull @HttpParam(name = "password", type = HttpParamType.COMMON, description = "密码") String password) throws ServiceException;
-
-    @HttpMethod(description = "绑定通知公众号")
-    String bindUniNotify(
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
-    @HttpMethod(description = "用户枚举")
-
-    List<AdminDO> getAdminList(
-            @HttpParam(name = "roleName", type = HttpParamType.COMMON, description = "角色ID") String roleName,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-    @HttpMethod(description = "测试接口")
-    void test() throws IOException, WriterException;
-
+	@HttpMethod(description = "管理员登录 返回AccessToken")
+	public String login(
+			@NotNull @HttpParam(name = "loginIp", type = HttpParamType.IP, description = "用户登陆IP") String loginIp,
+			@NotNull @HttpParam(name = "browserName", type = HttpParamType.BrowserName, description = "浏览器名称") String browserName,
+			@NotNull @HttpParam(name = "browserVersion", type = HttpParamType.BrowserVersion, description = "浏览器版本") String browserVersion,
+			@NotNull @HttpParam(name = "osName", type = HttpParamType.OsName, description = "系统名称") String osName,
+			@NotNull @HttpParam(name = "username", type = HttpParamType.COMMON, description = "用户名") String username,
+			@NotNull @HttpParam(name = "password", type = HttpParamType.COMMON, description = "密码") String password,
+			@NotNull @HttpParam(name = "verifyCode", type = HttpParamType.COMMON, description = "验证码") String verifyCode)
+			throws ServiceException;
+
+	@HttpMethod(description = "管理员登出")
+	public String logout(
+			@NotNull @HttpParam(name = Const.ADMIN_ACCESS_TOKEN, type = HttpParamType.HEADER, description = "访问Token") String accessToken,
+			@NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId)
+			throws ServiceException;
+
+	@HttpMethod(description = "管理员信息")
+	public AdminDTO info(
+			@NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId)
+			throws ServiceException;
+
+	@HttpMethod(description = "列表", permission = "admin:admin:list", permissionParentName = "系统管理", permissionName = "管理员")
+	public Page<AdminDTO> list(
+			@HttpParam(name = "username", type = HttpParamType.COMMON, description = "管理员名称搜索") String name,
+			@HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
+			@HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页长度", valueDef = "20") Integer limit,
+			@NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId)
+			throws ServiceException;
+
+	@HttpMethod(description = "创建", permission = "admin:admin:create", permissionParentName = "系统管理", permissionName = "管理员")
+	public AdminDTO create(
+			@NotNull @HttpParam(name = "adminDTO", type = HttpParamType.COMMON, description = "欲创建的admin对象JSON") AdminDTO adminDTO,
+			@NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId)
+			throws ServiceException;
+
+	@HttpMethod(description = "修改", permission = "admin:admin:update", permissionParentName = "系统管理", permissionName = "管理员")
+	public String update(
+			@NotNull @HttpParam(name = "adminDTO", type = HttpParamType.COMMON, description = "欲修改的admin对象JSON") AdminDTO adminDTO,
+			@NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId)
+			throws ServiceException;
+
+	@HttpMethod(description = "删除", permission = "admin:admin:delete", permissionParentName = "系统管理", permissionName = "管理员")
+	public String delete(@NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "目标删除Id") Long id,
+			@NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId)
+			throws ServiceException;
+
+	@HttpMethod(description = "更改密码")
+	public String newPassword(
+			@HttpParam(name = Const.ADMIN_ACCESS_TOKEN, type = HttpParamType.HEADER, description = "访问Token") String accessToken,
+			@NotNull @HttpParam(name = "oldPassword", type = HttpParamType.COMMON, description = "老密码") String oldPassword,
+			@NotNull @HttpParam(name = "newPassword", type = HttpParamType.COMMON, description = "新密码") String newPassword,
+			@NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId)
+			throws ServiceException;
+
+	@HttpMethod(description = "发送登陆短信")
+	public Boolean sendLoginMsg(
+			@NotNull @HttpParam(name = "username", type = HttpParamType.COMMON, description = "用户名") String username,
+			@NotNull @HttpParam(name = "password", type = HttpParamType.COMMON, description = "密码") String password)
+			throws ServiceException;
 }

+ 195 - 302
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/admin/AdminServiceImpl.java

@@ -3,8 +3,6 @@ package com.iotechn.unimall.admin.api.admin;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.mapper.EntityWrapper;
 import com.baomidou.mybatisplus.mapper.Wrapper;
-import com.google.zxing.WriterException;
-import com.iotechn.unimall.admin.QRCodeGenerator;
 import com.iotechn.unimall.core.Const;
 import com.iotechn.unimall.core.exception.AdminServiceException;
 import com.iotechn.unimall.core.exception.ExceptionDefinition;
@@ -14,42 +12,30 @@ import com.iotechn.unimall.core.notify.SMSClient;
 import com.iotechn.unimall.core.notify.SMSResult;
 import com.iotechn.unimall.core.util.GeneratorUtil;
 import com.iotechn.unimall.core.util.MD5Util;
-import com.iotechn.unimall.core.util.SHAUtil;
 import com.iotechn.unimall.data.component.CacheComponent;
-import com.iotechn.unimall.data.domain.*;
+import com.iotechn.unimall.data.domain.AdminDO;
+import com.iotechn.unimall.data.domain.RoleDO;
+import com.iotechn.unimall.data.domain.RolePermissionDO;
 import com.iotechn.unimall.data.dto.AdminDTO;
 import com.iotechn.unimall.data.enums.AdminStatusType;
 import com.iotechn.unimall.data.enums.RoleStatusType;
-import com.iotechn.unimall.data.enums.TaskStatusType;
 import com.iotechn.unimall.data.mapper.AdminMapper;
 import com.iotechn.unimall.data.mapper.RoleMapper;
 import com.iotechn.unimall.data.mapper.RolePermissionMapper;
 import com.iotechn.unimall.data.model.Page;
+import com.iotechn.unimall.data.util.IpUtils;
 import com.iotechn.unimall.data.util.SessionUtil;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
 import org.apache.ibatis.session.RowBounds;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.jdbc.datasource.DataSourceTransactionManager;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.TransactionDefinition;
-import org.springframework.transaction.TransactionStatus;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.net.URLEncoder;
-import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
 
 /**
  * Created by rize on 2019/4/8.
@@ -57,299 +43,206 @@ import java.util.stream.Collectors;
 @Service
 public class AdminServiceImpl implements AdminService {
 
-    @Autowired
-    private StringRedisTemplate userRedisTemplate;
-    @Autowired
-    private QRCodeGenerator qrCodeGenerator;
-    @Autowired
-    private AdminMapper adminMapper;
+	@Autowired
+	private StringRedisTemplate userRedisTemplate;
 
-    @Autowired
-    private RoleMapper roleMapper;
+	@Autowired
+	private AdminMapper adminMapper;
 
-    @Autowired
-    private RolePermissionMapper rolePermissionMapper;
+	@Autowired
+	private RoleMapper roleMapper;
 
-    @Autowired
-    private CacheComponent cacheComponent;
+	@Autowired
+	private RolePermissionMapper rolePermissionMapper;
 
-    @Autowired
-    private SMSClient smsClient;
+	@Autowired
+	private CacheComponent cacheComponent;
 
-    @Value("${com.iotechn.admin.notify.uninotify.url}")
-    private String uniNotifyUrl;
+	@Autowired
+	private SMSClient smsClient;
 
-    @Value("${com.iotechn.admin.notify.uninotify.app-secret}")
-    private String uniNotifyAppSecret;
+	private final static String ADMIN_MSG_CODE = "admin_msg_code_";
 
-    @Value("${com.iotechn.admin.notify.uninotify.app-id}")
-    private String uniNotifyAppId;
-
-    private  static String ADMIN_MSG_CODE = "admin_msg_code_";
-
-    private static  Logger logger = LoggerFactory.getLogger(AdminServiceImpl.class);
-    @Autowired
-    DataSourceTransactionManager dataSourceTransactionManager;
-    @Autowired
-    TransactionDefinition transactionDefinition;
-    @Override
-    public String login(String username, String password,String verifyCode) throws ServiceException {
-        String accessToken = generateAccessToken();
-        //数据库查管理员
-        List<AdminDO> adminDOS = adminMapper.selectList(
-                new EntityWrapper<AdminDO>()
-                        .eq("username", username));
-        if (CollectionUtils.isEmpty(adminDOS)) {
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_NOT_EXIST);
-        }
-        AdminDO adminDO = adminDOS.get(0);
-        //短信验证码
-        String code = cacheComponent.getRaw(ADMIN_MSG_CODE+adminDO.getPhone() );
-//        if(!"admin".equals(username) && (code == null || verifyCode==null || !code.equals(verifyCode))){
+	@Override
+	public String login(String loginIp, String browserName, String browserVersion, String osName, String username,
+			String password, String verifyCode) throws ServiceException {
+		String accessToken = generateAccessToken();
+		// 数据库查管理员
+		List<AdminDO> adminDOS = adminMapper.selectList(new EntityWrapper<AdminDO>().eq("username", username));
+		if (CollectionUtils.isEmpty(adminDOS)) {
+			throw new AdminServiceException(ExceptionDefinition.ADMIN_NOT_EXIST);
+		}
+		AdminDO adminDO = adminDOS.get(0);
+		// 短信验证码
+//        String code = cacheComponent.getRaw(ADMIN_MSG_CODE+adminDO.getPhone() );
+//        if(!"guest".equals(username) && (code == null || verifyCode==null || !code.equals(verifyCode))){
 //            throw new AdminServiceException(ExceptionDefinition.ADMIN_VERIFYCODE_ERROR);
 //        }
 
-        if (!MD5Util.verify(password, username, adminDO.getPassword())) {
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_PASSWORD_ERROR);
-        }
-        List<Long> ids = JSONObject.parseArray(adminDO.getRoleIds(), Long.class);
-        if (CollectionUtils.isEmpty(ids)) {
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_ROLE_IS_EMPTY);
-        }
-        List<RoleDO> roleDOList = roleMapper.selectList(
-                new EntityWrapper<RoleDO>()
-                        .in("id", ids)
-                        .eq("status", RoleStatusType.ACTIVE.getCode()));
-        List<String> roleNames = new LinkedList<>();
-        roleDOList.forEach(item -> {
-            roleNames.add(item.getName());
-        });
-        AdminDTO adminDTO = new AdminDTO();
-        adminDTO.setRoles(roleNames);
-        BeanUtils.copyProperties(adminDO, adminDTO);
-        adminDTO.setRoleIds(JSONObject.parseArray(adminDO.getRoleIds(), Long.class));
-        adminDTO.setPassword(null);
-        List<RolePermissionDO> rolePermissionDOList = rolePermissionMapper.selectList(
-                new EntityWrapper<RolePermissionDO>()
-                        .in("role_id", ids)
-                        .eq("deleted", 0));
-        List<String> permissionNames = new LinkedList<>();
-        rolePermissionDOList.forEach(item -> {
-            permissionNames.add(item.getPermission());
-        });
-        adminDTO.setPerms(permissionNames);
-        userRedisTemplate.opsForValue().set(Const.ADMIN_REDIS_PREFIX + accessToken, JSONObject.toJSONString(adminDTO), 30, TimeUnit.MINUTES);
-        return accessToken;
-    }
-
-    @Override
-    public String logout(String accessToken, Long adminId) throws ServiceException {
-        userRedisTemplate.delete(Const.ADMIN_REDIS_PREFIX  + accessToken);
-        return "ok";
-    }
-
-    @Override
-    public AdminDTO info(Long adminId) throws ServiceException {
-        return SessionUtil.getAdmin();
-    }
-
-    @Override
-    public Page<AdminDTO> list(String name, Integer page, Integer limit, Long adminId,Long companyId) throws ServiceException {
-        Wrapper<AdminDO> wrapper = new EntityWrapper<AdminDO>();
-        if (!StringUtils.isEmpty(name)) {
-            wrapper.like("username", name);
-        }
-        wrapper.orderBy("id", false);
-        wrapper.eq("company_id",companyId);
-        Integer count = adminMapper.selectCount(wrapper);
-        List<AdminDO> adminDOS = adminMapper.selectPage(new RowBounds((page - 1) * limit, limit), wrapper);
-
-        List<AdminDTO> adminDTOS = new ArrayList<AdminDTO>(adminDOS.size());
-        for (AdminDO adminDO : adminDOS) {
-            AdminDTO adminDTO = new AdminDTO();
-            BeanUtils.copyProperties(adminDO, adminDTO);
-            adminDTO.setRoleIds(JSONObject.parseArray(adminDO.getRoleIds(), Long.class));
-            adminDTO.setPassword(null);
-            adminDTOS.add(adminDTO);
-        }
-        return new Page<>(adminDTOS, page, limit, count);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public AdminDTO create(AdminDTO adminDTO, Long adminId,Long companyId) throws ServiceException {
-        AdminDO adminDO = new AdminDO();
-        Integer count = adminMapper.selectCount(
-                new EntityWrapper<AdminDO>()
-                        .eq("username", adminDTO.getUsername()));
-        if (count > 0) {
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_USER_NAME_REPEAT);
-        }
-        BeanUtils.copyProperties(adminDTO, adminDO);
-        adminDO.setPassword(MD5Util.md5(adminDO.getPassword(), adminDO.getUsername()));
-        adminDO.setRoleIds(JSONObject.toJSONString(adminDTO.getRoleIds()));
-        adminDO.setGmtUpdate(new Date());
-        adminDO.setCompanyId(companyId);
-        adminDO.setGmtCreate(adminDO.getGmtUpdate());
-        adminDO.setStatus(AdminStatusType.ACTIVE.getCode());
-        adminDO.setLastLoginIp("0.0.0.0");
-        adminDO.setGmtLastLogin("1997-01-20 00:00:00");
-        if (adminMapper.insert(adminDO) > 0) {
-            adminDTO.setId(adminDO.getId());
-            return adminDTO;
-        }
-        throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-    }
-
-    @Override
-    public String update(AdminDTO adminDTO, Long adminId,Long companyId) throws ServiceException {
-        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
-        try{
-            Long id = adminDTO.getId();
-            if (id == null) {
-                throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-            }
-            AdminDO adminDO = new AdminDO();
-            BeanUtils.copyProperties(adminDTO, adminDO);
-            Wrapper wrapper = new EntityWrapper();
-            wrapper.eq("admin_id", adminDTO.getId());
-            Date now = new Date();
-            dataSourceTransactionManager.commit(transactionStatus);
-
-            adminDO.setCompanyId(companyId);
-            adminDO.setGmtUpdate(new Date());
-            AdminDO adminDOExist = adminMapper.selectById(id);
-            if (!StringUtils.isEmpty(adminDO.getPassword()) && !StringUtils.isEmpty(adminDOExist.getUsername())&&adminDO.getPassword()!=null) {
-                adminDO.setPassword(MD5Util.md5(adminDO.getPassword(), adminDOExist.getUsername()));
-            }
-            adminDO.setUsername(null);
-            if (!CollectionUtils.isEmpty(adminDTO.getRoleIds())) {
-                adminDO.setRoleIds(JSONObject.toJSONString(adminDTO.getRoleIds()));
-            }
-            else {
-                adminDO.setRoleIds(JSONObject.toJSONString(adminDTO.getRoleIds()));
-            }
-            if (adminMapper.updateById(adminDO) > 0) {
-                return "ok";
-            }
-            else{
-                dataSourceTransactionManager.rollback(transactionStatus);
-                throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-            }
-        }
-        catch (Exception e){
-            //手动回滚事务
-            dataSourceTransactionManager.rollback(transactionStatus);
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-        }
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public String delete(Long id, Long adminId) throws ServiceException {
-        if (adminMapper.deleteById(id) > 0) {
-            return "ok";
-        }
-        throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public String newPassword(String accessToken, String oldPassword, String newPassword, Long adminId) throws ServiceException {
-        AdminDO adminDOExist = adminMapper.selectById(adminId);
-        if (!MD5Util.md5(oldPassword, adminDOExist.getUsername()).equals(adminDOExist.getPassword())) {
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_PASSWORD_ERROR);
-        }
-        AdminDO adminDO = new AdminDO();
-        adminDO.setId(adminId);
-        adminDO.setPassword(MD5Util.md5(newPassword, adminDOExist.getUsername()));
-        if (adminMapper.updateById(adminDO) > 0) {
-            //logout(accessToken, adminId);
-            return "ok";
-        }
-        throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-    }
-
-    @Override
-    public Boolean sendLoginMsg(String username,String password) throws ServiceException {
-        if ("admin".equals(username)) {
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_GUEST_NOT_NEED_VERIFY_CODE);
-        }
-        AdminDO adminDO = new AdminDO();
-        adminDO.setUsername(username);
-        adminDO.setPassword(MD5Util.md5(password,username));
-        AdminDO admin = adminMapper.selectOne(adminDO);
-        if(admin == null){
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_USER_NOT_EXITS);
-        }
-        String code = GeneratorUtil.genSixVerifyCode();
-        cacheComponent.putRaw(ADMIN_MSG_CODE+admin.getPhone(), code,300 );
-        SMSResult smsResult = smsClient.sendAdminLoginVerify(admin.getPhone(), code);
-        if(!smsResult.isSucc()){
-            throw new ThirdPartServiceException(smsResult.getMsg(), ExceptionDefinition.ADMIN_VERIFY_CODE_SEND_FAIL.getCode());
-        }
-        return true;
-    }
-
-    @Override
-    public String bindUniNotify(Long adminId) throws ServiceException {
-        try {
-            OkHttpClient okHttpClient = new OkHttpClient();
-            TreeSet<String> set = new TreeSet<>();
-            set.add("getRegisterUrl");
-            long timestamp = System.currentTimeMillis();
-            set.add(timestamp + "");
-            set.add("developer");
-            set.add(SessionUtil.getAdmin().getUsername());
-            set.add(this.uniNotifyAppSecret);
-            set.add(this.uniNotifyAppId);
-            String json = okHttpClient
-                    .newCall(new Request.Builder()
-                            .get()
-                            .url(this.uniNotifyUrl + "?_gp=developer&_mt=getRegisterUrl&userId=" + SessionUtil.getAdmin().getUsername()
-                                    + "&appId=" + this.uniNotifyAppId + "&timestamp=" + timestamp + "&sign=" + SHAUtil.shaEncode(URLEncoder.encode(set.stream().collect(Collectors.joining()), "utf-8")))
-                            .build()).execute().body().string();
-            JSONObject jsonObject = JSONObject.parseObject(json);
-            Integer errcode = jsonObject.getInteger("errno");
-            if (errcode == 200) {
-                return jsonObject.getString("data");
-            }
-            throw new AdminServiceException(jsonObject.getString("errmsg"), ExceptionDefinition.THIRD_PART_SERVICE_EXCEPTION.getCode());
-        } catch (ServiceException e) {
-            throw e;
-        } catch (IOException e) {
-            throw new AdminServiceException(ExceptionDefinition.THIRD_PART_IO_EXCEPTION);
-        } catch (Exception e) {
-            logger.error("[绑定通知] 异常", e);
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-        }
-    }
-
-    @Override
-    public List<AdminDO> getAdminList(String role, Long adminId,Long companyId) throws ServiceException {
-        Wrapper wrapper = new EntityWrapper<>();
-        wrapper.like("name",role);
-        wrapper.eq("company_id",companyId);
-        List<RoleDO> list = roleMapper.selectList(wrapper);
-        Long roleId = 0l;
-        if(list.size() >0){
-            roleId = list.get(0).getId();
-        }
-        wrapper = new EntityWrapper<>();
-        wrapper.like("role_ids",roleId+"");
-        List<AdminDO> AdminDOList = adminMapper.selectList(wrapper);
-
-        return AdminDOList;
-    }
-
-
-    private String generateAccessToken() {
-        return (UUID.randomUUID().toString().replace("-", ""));
-    }
+		if (!MD5Util.verify(password, username, adminDO.getPassword())) {
+			throw new AdminServiceException(ExceptionDefinition.ADMIN_PASSWORD_ERROR);
+		}
+		List<Long> ids = JSONObject.parseArray(adminDO.getRoleIds(), Long.class);
+		if (CollectionUtils.isEmpty(ids)) {
+			throw new AdminServiceException(ExceptionDefinition.ADMIN_ROLE_IS_EMPTY);
+		}
+		List<RoleDO> roleDOList = roleMapper
+				.selectList(new EntityWrapper<RoleDO>().in("id", ids).eq("status", RoleStatusType.ACTIVE.getCode()));
+		List<String> roleNames = new LinkedList<>();
+		roleDOList.forEach(item -> {
+			roleNames.add(item.getName());
+		});
+		AdminDTO adminDTO = new AdminDTO();
+		adminDTO.setRoles(roleNames);
+		BeanUtils.copyProperties(adminDO, adminDTO);
+		adminDTO.setRoleIds(JSONObject.parseArray(adminDO.getRoleIds(), Long.class));
+		adminDTO.setPassword(null);
+		List<RolePermissionDO> rolePermissionDOList = rolePermissionMapper
+				.selectList(new EntityWrapper<RolePermissionDO>().in("role_id", ids).eq("deleted", 0));
+		List<String> permissionNames = new LinkedList<>();
+		rolePermissionDOList.forEach(item -> {
+			permissionNames.add(item.getPermission());
+		});
+		adminDTO.setPerms(permissionNames);
+		JSONObject loginUserInfo = (JSONObject) JSONObject.toJSON(adminDTO);
+		loginUserInfo.put("loginIp", loginIp);
+		loginUserInfo.put("loginTime", new Date());
+		loginUserInfo.put("browser", browserName + "(" + browserVersion + ")");
+		loginUserInfo.put("osName", osName);
+		userRedisTemplate.opsForValue().set(Const.ADMIN_REDIS_PREFIX + accessToken,
+				JSONObject.toJSONString(loginUserInfo), 30, TimeUnit.MINUTES);
+		return accessToken;
+	}
+
+	@Override
+	public String logout(String accessToken, Long adminId) throws ServiceException {
+		userRedisTemplate.delete(Const.ADMIN_REDIS_PREFIX + accessToken);
+		return "ok";
+	}
+
+	@Override
+	public AdminDTO info(Long adminId) throws ServiceException {
+		return SessionUtil.getAdmin();
+	}
+
+	@Override
+	public Page<AdminDTO> list(String name, Integer page, Integer limit, Long adminId) throws ServiceException {
+		Wrapper<AdminDO> wrapper = new EntityWrapper<AdminDO>();
+		if (!StringUtils.isEmpty(name)) {
+			wrapper.like("username", name);
+		}
+		wrapper.orderBy("id", false);
+		Integer count = adminMapper.selectCount(wrapper);
+		List<AdminDO> adminDOS = adminMapper.selectPage(new RowBounds((page - 1) * limit, limit), wrapper);
+		List<AdminDTO> adminDTOS = new ArrayList<AdminDTO>(adminDOS.size());
+		for (AdminDO adminDO : adminDOS) {
+			AdminDTO adminDTO = new AdminDTO();
+			BeanUtils.copyProperties(adminDO, adminDTO);
+			adminDTO.setRoleIds(JSONObject.parseArray(adminDO.getRoleIds(), Long.class));
+			adminDTO.setPassword(null);
+			adminDTOS.add(adminDTO);
+		}
+		return new Page<>(adminDTOS, page, limit, count);
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public AdminDTO create(AdminDTO adminDTO, Long adminId) throws ServiceException {
+		AdminDO adminDO = new AdminDO();
+		Integer count = adminMapper.selectCount(new EntityWrapper<AdminDO>().eq("username", adminDTO.getUsername()));
+		if (count > 0) {
+			throw new AdminServiceException(ExceptionDefinition.ADMIN_USER_NAME_REPEAT);
+		}
+		BeanUtils.copyProperties(adminDTO, adminDO);
+		adminDO.setPassword(MD5Util.md5(adminDO.getPassword(), adminDO.getUsername()));
+		adminDO.setRoleIds(JSONObject.toJSONString(adminDTO.getRoleIds()));
+		adminDO.setGmtUpdate(new Date());
+		adminDO.setGmtCreate(adminDO.getGmtUpdate());
+		adminDO.setStatus(AdminStatusType.ACTIVE.getCode());
+		adminDO.setLastLoginIp("0.0.0.0");
+		adminDO.setGmtLastLogin("1997-01-20 00:00:00");
+		if (adminMapper.insert(adminDO) > 0) {
+			adminDTO.setId(adminDO.getId());
+			return adminDTO;
+		}
+		throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public String update(AdminDTO adminDTO, Long adminId) throws ServiceException {
+		Long id = adminDTO.getId();
+		if (id == null) {
+			throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
+		}
+		AdminDO adminDO = new AdminDO();
+		BeanUtils.copyProperties(adminDTO, adminDO);
+		adminDO.setGmtUpdate(new Date());
+		AdminDO adminDOExist = adminMapper.selectById(id);
+		if (!StringUtils.isEmpty(adminDO.getPassword()) && !StringUtils.isEmpty(adminDOExist.getUsername())) {
+			adminDO.setPassword(MD5Util.md5(adminDO.getPassword(), adminDOExist.getUsername()));
+		}
+		adminDO.setUsername(null);
+		if (!CollectionUtils.isEmpty(adminDTO.getRoleIds())) {
+			adminDO.setRoleIds(JSONObject.toJSONString(adminDTO.getRoleIds()));
+		}
+		if (adminMapper.updateById(adminDO) > 0) {
+			return "ok";
+		}
+		throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public String delete(Long id, Long adminId) throws ServiceException {
+		if (adminMapper.deleteById(id) > 0) {
+			return "ok";
+		}
+		throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public String newPassword(String accessToken, String oldPassword, String newPassword, Long adminId)
+			throws ServiceException {
+		AdminDO adminDOExist = adminMapper.selectById(adminId);
+		if (!MD5Util.md5(oldPassword, adminDOExist.getUsername()).equals(adminDOExist.getPassword())) {
+			throw new AdminServiceException(ExceptionDefinition.ADMIN_PASSWORD_ERROR);
+		}
+		AdminDO adminDO = new AdminDO();
+		adminDO.setId(adminId);
+		adminDO.setPassword(MD5Util.md5(newPassword, adminDOExist.getUsername()));
+		if (adminMapper.updateById(adminDO) > 0) {
+			// logout(accessToken, adminId);
+			return "ok";
+		}
+		throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
+	}
+
+	@Override
+	public Boolean sendLoginMsg(String username, String password) throws ServiceException {
+		if ("guest".equals(username)) {
+			throw new AdminServiceException(ExceptionDefinition.ADMIN_GUEST_NOT_NEED_VERIFY_CODE);
+		}
+		AdminDO adminDO = new AdminDO();
+		adminDO.setUsername(username);
+		adminDO.setPassword(MD5Util.md5(password, username));
+		AdminDO admin = adminMapper.selectOne(adminDO);
+		if (admin == null) {
+			throw new AdminServiceException(ExceptionDefinition.ADMIN_USER_NOT_EXITS);
+		}
+		String code = GeneratorUtil.genSixVerifyCode();
+		cacheComponent.putRaw(ADMIN_MSG_CODE + admin.getPhone(), code, 300);
+		SMSResult smsResult = smsClient.sendAdminLoginVerify(admin.getPhone(), code);
+		if (!smsResult.isSucc()) {
+			throw new ThirdPartServiceException(smsResult.getMsg(),
+					ExceptionDefinition.ADMIN_VERIFY_CODE_SEND_FAIL.getCode());
+		}
+		return true;
+	}
+
+	private String generateAccessToken() {
+		return (UUID.randomUUID().toString().replace("-", ""));
+	}
 
-    @Override
-    public void test() throws IOException, WriterException {
-        String result= qrCodeGenerator.generateQRCodeImage("/pages/tran/my_car_detail?id=91&中天昊元",350,350,"CAR1235654656");
-        logger.info(result);
-    }
 }

+ 72 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/advertisement/AdminAdvertisementService.java

@@ -0,0 +1,72 @@
+package com.iotechn.unimall.admin.api.advertisement;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.annotation.param.Range;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.AdvertisementDO;
+import com.iotechn.unimall.data.dto.RecommendDTO;
+import com.iotechn.unimall.data.enums.StatusType;
+import com.iotechn.unimall.data.model.Page;
+
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * Description:
+ * User: kbq
+ * Date: 2019-07-08
+ * Time: 下午8:23
+ */
+
+@HttpOpenApi(group = "admin.advertisement", description = "广告推销")
+public interface AdminAdvertisementService {
+
+    @HttpMethod(description = "创建", permission = "promote:advertisement:create", permissionParentName = "推广管理", permissionName = "广告管理")
+    public Boolean addAdvertisement(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "adType", type = HttpParamType.COMMON, description = "广告类型") Integer adType,
+            @HttpParam(name = "title", type = HttpParamType.COMMON, description = "广告标题") String title,
+            @NotNull @HttpParam(name = "url", type = HttpParamType.COMMON, description = "广告地址") String url,
+            @NotNull @HttpParam(name = "imgUrl", type = HttpParamType.COMMON, description = "广告图片地址") String imgUrl,
+            @NotNull @HttpParam(name = "status", type = HttpParamType.COMMON, description = "广告状态") Integer status,
+            @NotNull @HttpParam(name = "color", type = HttpParamType.COMMON, description = "广告图片颜色") String color) throws ServiceException;
+
+    @HttpMethod(description = "删除", permission = "promote:advertisement:delete", permissionParentName = "推广管理", permissionName = "广告管理")
+    public Boolean deleteAdvertisement(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "adType", type = HttpParamType.COMMON, description = "广告类型") Integer adType,
+            @NotNull @HttpParam(name = "adId", type = HttpParamType.COMMON, description = "广告ID") Long adId) throws ServiceException;
+
+    @HttpMethod(description = "修改", permission = "promote:advertisement:update", permissionParentName = "推广管理", permissionName = "广告管理")
+    public Boolean updateAdvertisement(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "adId", type = HttpParamType.COMMON, description = "广告ID") Long adId,
+            @NotNull @HttpParam(name = "adType", type = HttpParamType.COMMON, description = "广告类型") Integer adType,
+            @HttpParam(name = "title", type = HttpParamType.COMMON, description = "广告标题") String title,
+            @HttpParam(name = "url", type = HttpParamType.COMMON, description = "广告地址") String url,
+            @HttpParam(name = "imgUrl", type = HttpParamType.COMMON, description = "广告图片地址") String imgUrl,
+            @HttpParam(name = "status", type = HttpParamType.COMMON, description = "广告状态") Integer status,
+            @HttpParam(name = "color", type = HttpParamType.COMMON, description = "广告图片颜色") String color) throws ServiceException;
+
+
+    @HttpMethod(description = "查询", permission = "promote:advertisement:query", permissionParentName = "推广管理", permissionName = "广告管理")
+    public Page<AdvertisementDO> queryAdvertisement(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @HttpParam(name = "adType", type = HttpParamType.COMMON, description = "广告类型") Integer adType,
+            @Range(min = 1) @HttpParam(name = "pageNo", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer pageNo,
+            @Range(min = 1) @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页面长度", valueDef = "10") Integer limit,
+            @HttpParam(name = "status", type = HttpParamType.COMMON, description = "广告状态") Integer status) throws ServiceException;
+
+    @HttpMethod(description = "查询", permission = "promote:advertisement:query", permissionParentName = "推广管理", permissionName = "广告管理")
+    public Page<AdvertisementDO> queryAllAdvertisement(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @Range(min = 1) @HttpParam(name = "pageNo", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer pageNo,
+            @Range(min = 1) @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页面长度", valueDef = "10") Integer pageSize
+    ) throws ServiceException;
+
+
+}

+ 111 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/advertisement/AdminAdvertisementServiceImpl.java

@@ -0,0 +1,111 @@
+package com.iotechn.unimall.admin.api.advertisement;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.iotechn.unimall.core.exception.AdminServiceException;
+import com.iotechn.unimall.core.exception.ExceptionDefinition;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.component.CacheComponent;
+import com.iotechn.unimall.data.domain.AdvertisementDO;
+import com.iotechn.unimall.data.domain.OrderDO;
+import com.iotechn.unimall.data.enums.AdvertisementType;
+import com.iotechn.unimall.data.mapper.AdvertisementMapper;
+import com.iotechn.unimall.data.model.Page;
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * Description:
+ * User: kbq
+ * Date: 2019-07-08
+ * Time: 下午9:24
+ */
+@Service
+public class AdminAdvertisementServiceImpl implements AdminAdvertisementService {
+
+    @Autowired
+    private AdvertisementMapper advertisementMapper;
+    @Autowired
+    private CacheComponent cacheComponent;
+
+    private  final  static String  ADVERTISEMENT_NAME = "ADVERTISEMENT_TYPE_";
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean addAdvertisement(Long adminId, Integer adType, String title, String url, String imgUrl, Integer status,String color) throws ServiceException {
+
+        Date now = new Date();
+        AdvertisementDO advertisementDO = new AdvertisementDO(adType,title,url,imgUrl,status,color);
+        advertisementDO.setGmtCreate(now);
+        advertisementDO.setGmtUpdate(now);
+
+        if(advertisementMapper.insert(advertisementDO) > 0){
+            cacheComponent.delPrefixKey(ADVERTISEMENT_NAME);
+            return true;
+        }
+        throw new AdminServiceException(ExceptionDefinition.ADVERTISEMENT_SQL_ADD_FAILED);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteAdvertisement(Long adminId,Integer adType, Long adId) throws ServiceException {
+
+        if(advertisementMapper.delete(new EntityWrapper<AdvertisementDO>()
+                .eq("id",adId)
+                .eq("ad_type",adType)) > 0){
+            cacheComponent.delPrefixKey(ADVERTISEMENT_NAME);
+            return true;
+        }
+        throw new AdminServiceException(ExceptionDefinition.ADVERTISEMENT_SQL_DELETE_FAILED);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updateAdvertisement(Long adminId,Long adId, Integer adType, String title, String url, String imgUrl, Integer status,String color) throws ServiceException {
+        AdvertisementDO advertisementDO = new AdvertisementDO(adType,title,url,imgUrl,status,color);
+        advertisementDO.setId(adId);
+        advertisementDO.setGmtUpdate(new Date());
+        if(advertisementMapper.updateById(advertisementDO)>0){
+            cacheComponent.delPrefixKey(ADVERTISEMENT_NAME);
+            return  true;
+        }
+        throw new AdminServiceException(ExceptionDefinition.ADVERTISEMENT_SQL_UPDATE_FAILED);
+    }
+
+    @Override
+    public Page<AdvertisementDO> queryAdvertisement(Long adminId, Integer adType, Integer pageNo, Integer limit, Integer status) throws ServiceException {
+        Wrapper<AdvertisementDO> wrapper = new EntityWrapper<AdvertisementDO>();
+        if (adType != null) {
+            wrapper.eq("ad_type", adType);
+        }
+        if (status != null) {
+            wrapper.eq("status", status);
+        }
+
+        List<AdvertisementDO> advertisementDOList = advertisementMapper.selectPage(new RowBounds(limit *(pageNo - 1), limit),wrapper);
+        Integer count = advertisementMapper.selectCount(wrapper);
+
+        Page<AdvertisementDO> page = new Page<>(advertisementDOList,pageNo, limit,count);
+
+        return page;
+
+    }
+
+    //冗余,未使用
+    @Override
+    public Page<AdvertisementDO> queryAllAdvertisement(Long adminId,Integer pageNo,Integer pageSize) throws ServiceException {
+
+        List<AdvertisementDO> advertisementDOList = advertisementMapper.getAllAdvertisement(pageSize*(pageNo-1),pageSize);
+        Integer count = advertisementMapper.selectCount(null);
+        Page<AdvertisementDO> page = new Page<>(advertisementDOList,pageNo,pageSize,count);
+        return page;
+
+    }
+}

+ 40 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/appraise/AdminAppraise.java

@@ -0,0 +1,40 @@
+package com.iotechn.unimall.admin.api.appraise;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.dto.appraise.AppraiseResponseDTO;
+import com.iotechn.unimall.data.model.Page;
+
+/**
+ * Created with IntelliJ IDEA.
+ * Description:
+ * User: kbq
+ * Date: 2019-07-15
+ * Time: 下午3:41
+ */
+@HttpOpenApi(group = "admin.appraise", description = "评论")
+public interface AdminAppraise {
+
+    @HttpMethod(description = "删除", permission = "operation:appraise:delete", permissionParentName = "运营管理", permissionName = "评论管理")
+    public boolean deleteAppraise(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "评论id") Long id) throws ServiceException;
+
+
+    @HttpMethod(description = "查询", permission = "operation:appraise:query", permissionParentName = "运营管理", permissionName = "评论管理")
+    public Page<AppraiseResponseDTO> getAppraiseList(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @HttpParam(name = "id", type = HttpParamType.COMMON, description = "评论id") Long id,
+            @HttpParam(name = "userName", type = HttpParamType.COMMON, description = "用户姓名") String userName,
+            @HttpParam(name = "spuName", type = HttpParamType.COMMON, description = "商品名字") String spuName,
+            @HttpParam(name = "orderId", type = HttpParamType.COMMON, description = "订单ID") Long orderId,
+            @HttpParam(name = "score", type = HttpParamType.COMMON, description = "评论id") Integer score,
+            @HttpParam(name = "content", type = HttpParamType.COMMON, description = "评论id") String content,
+            @HttpParam(name = "pageNo", type = HttpParamType.COMMON, description = "页码") Integer pageNo,
+            @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度") Integer limit) throws ServiceException;
+
+}

+ 46 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/appraise/AdminAppraiseImpl.java

@@ -0,0 +1,46 @@
+package com.iotechn.unimall.admin.api.appraise;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.dto.appraise.AppraiseResponseDTO;
+import com.iotechn.unimall.data.mapper.AppraiseMapper;
+import com.iotechn.unimall.data.model.Page;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * Description:
+ * User: kbq
+ * Date: 2019-07-15
+ * Time: 下午3:56
+ */
+@Service
+public class AdminAppraiseImpl implements  AdminAppraise {
+
+    @Autowired
+    private AppraiseMapper appraiseMapper;
+
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteAppraise(Long adminId, Long id) throws ServiceException {
+        return appraiseMapper.deleteById(id) > 0;
+    }
+
+    @Override
+    public Page<AppraiseResponseDTO> getAppraiseList(Long adminId, Long id, String userName, String spuName, Long orderId, Integer score, String content,Integer pageNo,Integer limit) throws ServiceException {
+
+        Integer count = appraiseMapper.countAppraiseCondition(id,userName ,spuName , orderId, score, content);
+
+        List<AppraiseResponseDTO> appraiseResponseDTOList = appraiseMapper.selectAppraiseCondition(id,userName ,spuName , orderId, score, content,(pageNo-1)*limit,limit);
+
+        Page<AppraiseResponseDTO> page = new Page<AppraiseResponseDTO>(appraiseResponseDTOList,pageNo,limit,count);
+
+        return page;
+    }
+}

+ 62 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/category/AdminCategoryService.java

@@ -0,0 +1,62 @@
+package com.iotechn.unimall.admin.api.category;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.annotation.param.Range;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.CategoryDO;
+import com.iotechn.unimall.data.dto.CategoryDTO;
+import com.iotechn.unimall.data.dto.CategoryTreeNodeDTO;
+import com.iotechn.unimall.data.model.Page;
+
+import java.util.List;
+
+/**
+ * Created by rize on 2019/7/12.
+ */
+@HttpOpenApi(group = "admin.category", description = "类目管理服务")
+public interface AdminCategoryService {
+
+    @HttpMethod(description = "获取二级类目树")
+    public List<CategoryTreeNodeDTO> categorySecondLevelTree() throws ServiceException;
+
+    @HttpMethod(description = "获取类目树")
+    public List<CategoryTreeNodeDTO> categoryTree() throws ServiceException;
+
+    @HttpMethod(description = "创建", permission = "operation:category:create", permissionParentName = "商品管理", permissionName = "类目管理")
+    public CategoryDO addCategory(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "title", type = HttpParamType.COMMON, description = "类目标题") String title,
+            @HttpParam(name = "parentId", type = HttpParamType.COMMON, description = "类目父节点", valueDef = "0") Long parentId,
+            @HttpParam(name = "iconUrl", type = HttpParamType.COMMON, description = "类目图标") String iconUrl,
+            @HttpParam(name = "picUrl", type = HttpParamType.COMMON, description = "类目图片") String picUrl,
+            @HttpParam(name = "level", type = HttpParamType.COMMON, description = "类目等级") Integer level) throws ServiceException;
+
+    @HttpMethod(description = "删除", permission = "operation:category:delete", permissionParentName = "商品管理", permissionName = "类目管理")
+    public boolean deleteCategory(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "类目ID") Long id) throws ServiceException;
+
+    @HttpMethod(description = "修改", permission = "operation:category:update", permissionParentName = "商品管理", permissionName = "类目管理")
+    public CategoryTreeNodeDTO updateCategory(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "类目ID") Long id,
+            @NotNull @HttpParam(name = "title", type = HttpParamType.COMMON, description = "类目标题") String title,
+            @NotNull @HttpParam(name = "parentId", type = HttpParamType.COMMON, description = "类目父节点") Long parentId,
+            @HttpParam(name = "iconUrl", type = HttpParamType.COMMON, description = "类目图标") String iconUrl,
+            @HttpParam(name = "picUrl", type = HttpParamType.COMMON, description = "类目图片") String picUrl,
+            @HttpParam(name = "level", type = HttpParamType.COMMON, description = "类目等级") Integer level) throws ServiceException;
+
+    @HttpMethod(description = "查询", permission = "operation:category:query", permissionParentName = "商品管理", permissionName = "类目管理")
+    public Page<CategoryTreeNodeDTO> queryCategory(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @HttpParam(name = "id", type = HttpParamType.COMMON, description = "类目ID") Long id,
+            @HttpParam(name = "title", type = HttpParamType.COMMON, description = "类目标题") String title,
+            @HttpParam(name = "level", type = HttpParamType.COMMON, description = "类目等级") Integer level,
+            @HttpParam(name = "parentId", type = HttpParamType.COMMON, description = "父类目id") Long parentId,
+            @Range(min = 1) @HttpParam(name = "pageNo", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer pageNo,
+            @Range(min = 1) @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "10") Integer limit) throws ServiceException;
+}

+ 304 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/category/AdminCategoryServiceImpl.java

@@ -0,0 +1,304 @@
+package com.iotechn.unimall.admin.api.category;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.iotechn.unimall.biz.service.category.CategoryBizService;
+import com.iotechn.unimall.core.exception.*;
+import com.iotechn.unimall.data.component.CacheComponent;
+import com.iotechn.unimall.data.domain.CategoryDO;
+import com.iotechn.unimall.data.domain.SpuDO;
+import com.iotechn.unimall.data.dto.CategoryTreeNodeDTO;
+import com.iotechn.unimall.data.mapper.CategoryMapper;
+import com.iotechn.unimall.data.mapper.SpuMapper;
+import com.iotechn.unimall.data.model.Page;
+import com.iotechn.unimall.plugin.core.inter.IPluginUpdateCategory;
+import com.iotechn.unimall.plugin.core.manager.PluginsManager;
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Created by rize on 2019/7/12.
+ */
+@Service
+public class AdminCategoryServiceImpl implements AdminCategoryService {
+
+    @Autowired
+    private CategoryMapper categoryMapper;
+
+    @Autowired
+    private SpuMapper spuMapper;
+
+    @Autowired
+    private CategoryBizService categoryBizService;
+
+    @Autowired
+    private CacheComponent cacheComponent;
+
+    @Autowired
+    private PluginsManager pluginsManager;
+
+    private static final String CA_CATEGORY_TREE = "CA_CATEGORY_TREE";
+
+    private static final String ADMIN_QUERY_CATEGORY_LIST = "ADMIN_QUERY_CATEGORY_LIST";
+
+    private static final String CA_CATEGORY_SECOND_LEVEL_TREE = "CA_CATEGORY_SECOND_LEVEL_TREE";
+
+    /**
+     * @return
+     * @throws ServiceException
+     */
+
+
+    /*获取两级目录树*/
+    public List<CategoryTreeNodeDTO> categorySecondLevelTree() throws ServiceException {
+        List<CategoryTreeNodeDTO> objList = cacheComponent.getObjList(CA_CATEGORY_SECOND_LEVEL_TREE, CategoryTreeNodeDTO.class);
+        if (objList != null) {
+            return objList;
+        }
+        List<CategoryTreeNodeDTO> list = categoryBizService.categorySecondLevelTree();
+        cacheComponent.putObj(CA_CATEGORY_SECOND_LEVEL_TREE, list, 60 * 60);
+        return list;
+    }
+
+
+    /*获取三级目录树。*/
+    //TODO 做下优化
+    @Override
+    public List<CategoryTreeNodeDTO> categoryTree() throws ServiceException {
+        List<CategoryTreeNodeDTO> objList = cacheComponent.getObjList(CA_CATEGORY_TREE, CategoryTreeNodeDTO.class);
+        if (objList != null) {
+            return objList;
+        }
+        List<CategoryDO> categoryDOS = categoryMapper.selectList(new EntityWrapper<>());
+        List<CategoryTreeNodeDTO> list = categoryDOS.stream().filter((item) -> (item.getParentId().equals(0l))).map(item -> {
+            CategoryTreeNodeDTO dto = new CategoryTreeNodeDTO();
+            dto.setLabel(item.getTitle());
+            dto.setLevel(0);
+            dto.setFullName(dto.getLabel());
+            dto.setValue(item.getId());
+            dto.setChildren(new LinkedList<>());
+            return dto;
+        }).collect(Collectors.toList());
+        list.forEach(item -> {
+            categoryDOS.forEach(categoryDO -> {
+                if (categoryDO.getParentId().equals(item.getValue())) {
+                    CategoryTreeNodeDTO categoryTreeNodeDTO = new CategoryTreeNodeDTO();
+                    categoryTreeNodeDTO.setChildren(new LinkedList<>());
+                    categoryTreeNodeDTO.setValue(categoryDO.getId());
+                    categoryTreeNodeDTO.setLabel(categoryDO.getTitle());
+                    categoryTreeNodeDTO.setLevel(1);
+                    categoryTreeNodeDTO.setParent(item.getValue());
+                    categoryTreeNodeDTO.setFullName(item.getFullName() + "/" + categoryDO.getTitle());
+                    item.getChildren().add(categoryTreeNodeDTO);
+                    categoryDOS.forEach(subCategoryDO -> {
+                        if (subCategoryDO.getParentId().equals(categoryTreeNodeDTO.getValue())) {
+                            CategoryTreeNodeDTO childCategoryNodeDTO = new CategoryTreeNodeDTO();
+                            childCategoryNodeDTO.setLabel(subCategoryDO.getTitle());
+                            childCategoryNodeDTO.setValue(subCategoryDO.getId());
+                            childCategoryNodeDTO.setLevel(2);
+                            childCategoryNodeDTO.setParent(categoryTreeNodeDTO.getValue());
+                            childCategoryNodeDTO.setFullName(categoryTreeNodeDTO.getFullName() + "/" + subCategoryDO.getTitle());
+                            categoryTreeNodeDTO.getChildren().add(childCategoryNodeDTO);
+                        }
+                    });
+                }
+            });
+        });
+        cacheComponent.putObj(CA_CATEGORY_TREE, list, 60 * 60);
+        return list;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public CategoryDO addCategory(Long adminId, String title, Long parentId, String iconUrl, String picUrl, Integer level) throws ServiceException {
+        CategoryDO parent = null;
+        CategoryDO categoryDO = new CategoryDO();
+        if (!parentId.equals(0l)) {
+            parent = categoryMapper.selectById(parentId);
+            if (parent == null) {
+                throw new AdminServiceException(ExceptionDefinition.PARENT_NODE_INFORMATION_ERROR);
+            }
+            categoryDO.setLevel(parent.getLevel() + 1);
+        } else {
+            categoryDO.setLevel(0);
+        }
+        categoryDO.setParentId(parentId);
+        categoryDO.setIconUrl(iconUrl);
+        categoryDO.setPicUrl(picUrl);
+        categoryDO.setTitle(title);
+        Date now = new Date();
+        categoryDO.setGmtCreate(now);
+        categoryDO.setGmtUpdate(now);
+
+        if (categoryMapper.insert(categoryDO) <= 0) {
+            throw new AdminServiceException(ExceptionDefinition.DATABASE_INSERT_FAILURE);
+        }
+        cacheComponent.del(CA_CATEGORY_TREE);
+        cacheComponent.del(ADMIN_QUERY_CATEGORY_LIST);
+        cacheComponent.del(CA_CATEGORY_SECOND_LEVEL_TREE);
+        cacheComponent.del(CategoryBizService.CA_CATEGORY_ID_HASH);
+        cacheComponent.del(CategoryBizService.CA_CATEGORY_LIST);
+        pluginInvokeUpdateCategory(categoryDO.getId());
+        return categoryDO;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteCategory(Long adminId, Long id) throws ServiceException {
+        Integer count_category = categoryMapper.selectCount(new EntityWrapper<CategoryDO>().eq("parent_id", id));
+        Integer count_spu = spuMapper.selectCount(new EntityWrapper<SpuDO>().eq("category_id", id));
+
+        if (count_category != 0 || count_spu != 0) {
+            throw new AppServiceException(ExceptionDefinition.CATEGORY_OUGHT_TO_EMPTY);
+        }
+        cacheComponent.del(CA_CATEGORY_TREE);
+        cacheComponent.del(ADMIN_QUERY_CATEGORY_LIST);
+        cacheComponent.del(CA_CATEGORY_SECOND_LEVEL_TREE);
+        cacheComponent.del(CategoryBizService.CA_CATEGORY_ID_HASH);
+        cacheComponent.del(CategoryBizService.CA_CATEGORY_LIST);
+        pluginInvokeUpdateCategory(id);
+        return categoryMapper.deleteById(id) > 0;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public CategoryTreeNodeDTO updateCategory(Long adminId, Long id, String title, Long parentId, String iconUrl, String picUrl, Integer level) throws ServiceException {
+        CategoryDO categoryDO = new CategoryDO();
+        if (id == null || parentId == null) {
+            throw new AdminServiceException(ExceptionDefinition.CATEGORY_OR_PARENT_NODE_IS_EMPTY);
+        }
+        categoryDO.setId(parentId);
+        CategoryDO categoryParent = categoryMapper.selectOne(categoryDO);
+
+        //传入父节点等于自身抛出异常
+        if (id.equals(parentId)) {
+            throw new AdminServiceException(ExceptionDefinition.PARENT_CAN_NOT_EQUALS_ONESELF);
+        }
+
+        if (categoryParent == null && !parentId.equals(0L)) {
+            throw new AdminServiceException(ExceptionDefinition.NOT_FIND_PARENT_NODE);
+        }
+        if (parentId.equals(0L)) {
+            categoryDO.setLevel(0);
+        } else {
+            categoryDO.setLevel(categoryParent.getLevel() + 1);
+        }
+        categoryDO.setId(id);
+        categoryDO.setGmtUpdate(new Date());
+        categoryDO.setParentId(parentId);
+        categoryDO.setTitle(title);
+        categoryDO.setPicUrl(picUrl);
+        categoryDO.setIconUrl(iconUrl);
+        if (categoryMapper.updateById(categoryDO) <= 0) {
+            throw new AdminServiceException(ExceptionDefinition.CATEGORY_UPDATE_FAILURE);
+        }
+        CategoryTreeNodeDTO categoryTreeNodeDTO = new CategoryTreeNodeDTO();
+        List<CategoryTreeNodeDTO> list = getCategoryList();
+        for (CategoryTreeNodeDTO temp : list) {
+            if (categoryDO.getId().equals(temp.getValue())) {
+                BeanUtils.copyProperties(temp, categoryTreeNodeDTO);
+                break;
+            }
+        }
+        cacheComponent.del(CA_CATEGORY_TREE);
+        cacheComponent.del(ADMIN_QUERY_CATEGORY_LIST);
+        cacheComponent.del(CA_CATEGORY_SECOND_LEVEL_TREE);
+        cacheComponent.del(CategoryBizService.CA_CATEGORY_ID_HASH);
+        cacheComponent.del(CategoryBizService.CA_CATEGORY_LIST);
+        pluginInvokeUpdateCategory(categoryDO.getId());
+        return categoryTreeNodeDTO;
+    }
+
+    //首先的到所有的类目的List<CategoryTreeNodeDTO>,在根据SQL查询得到的数据转化成传往前端的数据
+    @Override
+    public Page<CategoryTreeNodeDTO> queryCategory(Long adminId, Long id, String title, Integer level, Long parentId, Integer pageNo, Integer limit) throws ServiceException {
+        EntityWrapper wrapper = new EntityWrapper();
+        if (id != null) {
+            wrapper.eq("id", id);
+        }
+        if (title != null) {
+            wrapper.like("title", title);
+        }
+        if (level != null) {
+            wrapper.eq("level", level);
+        }
+        if (parentId != null) {
+            wrapper.eq("parent_id", parentId);
+        }
+        wrapper.orderBy("level");
+        Integer count = categoryMapper.selectCount(wrapper);
+
+        List<CategoryDO> categoryDOS = categoryMapper.selectPage(new RowBounds((pageNo - 1) * limit, limit), wrapper);
+        List<CategoryTreeNodeDTO> totalCategory = getCategoryList();
+        List<CategoryTreeNodeDTO> list = categoryDOS.stream().map(item -> {
+            CategoryTreeNodeDTO dto = new CategoryTreeNodeDTO();
+            for (CategoryTreeNodeDTO temp : totalCategory) {
+                if (temp.getValue().equals(item.getId())) {
+                    BeanUtils.copyProperties(temp, dto);
+                    return dto;
+                }
+            }
+            BeanUtils.copyProperties(item, dto);
+            ;
+            return dto;
+        }).collect(Collectors.toList());
+        Page<CategoryTreeNodeDTO> page = new Page<>(list, pageNo, limit, count);
+        return page;
+    }
+
+
+    //TODO 可以做出父节点查询所有子节点
+    //获得所有类目按类目等级排序的类目list,
+    private List<CategoryTreeNodeDTO> getCategoryList() {
+        List<CategoryTreeNodeDTO> objList = cacheComponent.getObjList(ADMIN_QUERY_CATEGORY_LIST, CategoryTreeNodeDTO.class);
+        if (objList != null) {
+            return objList;
+        }
+        EntityWrapper wrapper = new EntityWrapper();
+        wrapper.orderBy("level");
+        List<CategoryDO> categoryDOS = categoryMapper.selectList(wrapper);
+        List<CategoryTreeNodeDTO> list = categoryDOS.stream().map(item -> {
+            CategoryTreeNodeDTO dto = new CategoryTreeNodeDTO();
+            dto.setLabel(item.getTitle());
+            dto.setLevel(item.getLevel());
+            dto.setValue(item.getId());
+            dto.setParent(item.getParentId());
+            dto.setIconUrl(item.getIconUrl());
+            dto.setPicUrl(item.getPicUrl());
+            if (item.getLevel() == 0) {
+                dto.setFullName(dto.getLabel());
+            }
+            return dto;
+        }).collect(Collectors.toList());
+
+        for (CategoryTreeNodeDTO cOne : list) {
+
+            for (CategoryTreeNodeDTO cTwo : list) {
+                if (cOne.getParent().equals(cTwo.getValue())) {
+                    cOne.setFullName(cTwo.getFullName() + "/" + cOne.getLabel());
+                    break;
+                }
+            }
+
+        }
+        cacheComponent.putObj(ADMIN_QUERY_CATEGORY_LIST, list, 60 * 60);
+        return list;
+    }
+
+    private void pluginInvokeUpdateCategory(Long categoryId) {
+        List<IPluginUpdateCategory> plugins = pluginsManager.getPlugins(IPluginUpdateCategory.class);
+        if (!CollectionUtils.isEmpty(plugins)) {
+            for (IPluginUpdateCategory updateGoods : plugins) {
+                updateGoods.invokeCategoryUpdate(categoryId);
+            }
+        }
+    }
+
+
+}

+ 10 - 3
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/config/AdminMerchantConfigService.java

@@ -5,8 +5,15 @@ import com.iotechn.unimall.core.annotation.HttpOpenApi;
 import com.iotechn.unimall.core.annotation.HttpParam;
 import com.iotechn.unimall.core.annotation.HttpParamType;
 import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.annotation.param.Range;
 import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.CategoryDO;
+import com.iotechn.unimall.data.domain.ConfigDO;
+import com.iotechn.unimall.data.dto.CategoryTreeNodeDTO;
 import com.iotechn.unimall.data.dto.ConfigDTO;
+import com.iotechn.unimall.data.model.Page;
+
+import java.util.List;
 
 /**
  * Created with IntelliJ IDEA.
@@ -20,7 +27,7 @@ import com.iotechn.unimall.data.dto.ConfigDTO;
 public interface AdminMerchantConfigService {
 
     @HttpMethod(description = "创建", permission = "promote:merchant:create", permissionParentName = "推广管理", permissionName = "商铺信息管理")
-    boolean addMerchant(
+    public boolean addMerchant(
             @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
             @NotNull @HttpParam(name = "title", type = HttpParamType.COMMON, description = "商铺标题") String title,
             @HttpParam(name = "logoUrl", type = HttpParamType.COMMON, description = "商铺logo") String logoUrl,
@@ -30,7 +37,7 @@ public interface AdminMerchantConfigService {
     ) throws ServiceException;
 
     @HttpMethod(description = "修改", permission = "promote:merchant:update", permissionParentName = "推广管理", permissionName = "商铺信息管理")
-    boolean updateMerchant(
+    public boolean updateMerchant(
             @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
             @NotNull @HttpParam(name = "title", type = HttpParamType.COMMON, description = "商铺标题") String title,
             @HttpParam(name = "logoUrl", type = HttpParamType.COMMON, description = "商铺logo") String logoUrl,
@@ -40,7 +47,7 @@ public interface AdminMerchantConfigService {
     ) throws ServiceException;
 
     @HttpMethod(description = "查询", permission = "promote:merchant:query", permissionParentName = "推广管理", permissionName = "商铺信息管理")
-    ConfigDTO getMerchant(
+    public ConfigDTO getMerchant(
             @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
 
 

+ 82 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/coupon/AdminCouponService.java

@@ -0,0 +1,82 @@
+package com.iotechn.unimall.admin.api.coupon;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.CouponDO;
+import com.iotechn.unimall.data.dto.CouponAdminDTO;
+import com.iotechn.unimall.data.dto.CouponDTO;
+import com.iotechn.unimall.data.model.Page;
+
+import java.util.Date;
+
+/**
+ * Created with IntelliJ IDEA.
+ * Description:
+ * User: kbq
+ * Date: 2019-07-12
+ * Time: 下午10:47
+ */
+
+@HttpOpenApi(group = "admin.coupon", description = "优惠卷")
+public interface AdminCouponService {
+
+    @HttpMethod(description = "创建", permission = "promote:coupon:create", permissionParentName = "推广管理", permissionName = "优惠管理")
+    public CouponDO addCoupon(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "title", type = HttpParamType.COMMON, description = "优惠卷标题") String title,
+            @NotNull @HttpParam(name = "type", type = HttpParamType.COMMON, description = "优惠卷类别,如满减") Integer type,
+            @HttpParam(name = "description", type = HttpParamType.COMMON, description = "优惠卷描述") String description,
+            @NotNull @HttpParam(name = "total", type = HttpParamType.COMMON, description = "优惠卷总数") Integer total,
+            @NotNull @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "用户限制领取") Integer limit,
+            @NotNull @HttpParam(name = "discount", type = HttpParamType.COMMON, description = "优惠价格") Integer discount,
+            @NotNull @HttpParam(name = "min", type = HttpParamType.COMMON, description = "满足优惠的最低价格") Integer min,
+            @NotNull @HttpParam(name = "status", type = HttpParamType.COMMON, description = "优惠卷状态") Integer status,
+            @HttpParam(name = "categoryId", type = HttpParamType.COMMON, description = "优惠类别") Long categoryId,
+            @HttpParam(name = "days", type = HttpParamType.COMMON, description = "优惠时长") Integer days,
+            @HttpParam(name = "gmtStart", type = HttpParamType.COMMON, description = "优惠开始时间") Long gmtStart,
+            @HttpParam(name = "gmtEnd", type = HttpParamType.COMMON, description = "优惠结束时间") Long gmtEnd) throws ServiceException;
+
+    @HttpMethod(description = "删除", permission = "promote:coupon:delete", permissionParentName = "推广管理", permissionName = "优惠管理")
+    public Boolean deleteCoupon(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "优惠卷ID") Long id) throws ServiceException;
+
+    @HttpMethod(description = "修改", permission = "promote:coupon:update", permissionParentName = "推广管理", permissionName = "优惠管理")
+    public Boolean updateCoupon(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "优惠卷ID") Long id,
+            @NotNull @HttpParam(name = "title", type = HttpParamType.COMMON, description = "优惠卷标题") String title,
+            @NotNull @HttpParam(name = "type", type = HttpParamType.COMMON, description = "优惠卷类别,如满减") Integer type,
+            @HttpParam(name = "description", type = HttpParamType.COMMON, description = "优惠卷描述") String description,
+            @NotNull @HttpParam(name = "total", type = HttpParamType.COMMON, description = "优惠卷总数") Integer total,
+            @NotNull @HttpParam(name = "surplus", type = HttpParamType.COMMON, description = "优惠卷剩余") Integer surplus,
+            @NotNull @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "用户限制领取") Integer limit,
+            @NotNull @HttpParam(name = "discount", type = HttpParamType.COMMON, description = "优惠价格") Integer discount,
+            @NotNull @HttpParam(name = "min", type = HttpParamType.COMMON, description = "满足优惠的最低价格") Integer min,
+            @NotNull @HttpParam(name = "status", type = HttpParamType.COMMON, description = "优惠卷状态") Integer status,
+            @HttpParam(name = "categoryId", type = HttpParamType.COMMON, description = "优惠类别") Long categoryId,
+            @HttpParam(name = "days", type = HttpParamType.COMMON, description = "优惠时长") Integer days,
+            @HttpParam(name = "gmtStart", type = HttpParamType.COMMON, description = "优惠开始时间") Date gmtStart,
+            @HttpParam(name = "gmtEnd", type = HttpParamType.COMMON, description = "优惠结束时间") Date gmtEnd) throws ServiceException;
+
+    @HttpMethod(description = "修改", permission = "promote:coupon:update", permissionParentName = "推广管理", permissionName = "优惠管理")
+    public Boolean updateCouponStatus(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "优惠卷ID") Long id,
+            @NotNull @HttpParam(name = "status", type = HttpParamType.COMMON, description = "优惠卷状态") Integer status) throws ServiceException;
+
+
+    @HttpMethod(description = "查询", permission = "promote:coupon:query", permissionParentName = "推广管理", permissionName = "优惠管理")
+    public Page<CouponAdminDTO> queryCouponByTitle(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @HttpParam(name = "title", type = HttpParamType.COMMON, description = "优惠卷标题") String title,
+            @HttpParam(name = "type", type = HttpParamType.COMMON, description = "优惠卷类型") Integer type,
+            @HttpParam(name = "status", type = HttpParamType.COMMON, description = "优惠卷状态") Integer status,
+            @HttpParam(name = "pageNo", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer pageNo,
+            @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "10") Integer limit) throws ServiceException;
+
+}

+ 123 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/coupon/AdminCouponServiceImpl.java

@@ -0,0 +1,123 @@
+package com.iotechn.unimall.admin.api.coupon;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.iotechn.unimall.core.exception.AdminServiceException;
+import com.iotechn.unimall.core.exception.ExceptionDefinition;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.CouponDO;
+import com.iotechn.unimall.data.dto.CouponAdminDTO;
+import com.iotechn.unimall.data.mapper.CouponMapper;
+import com.iotechn.unimall.data.mapper.UserCouponMapper;
+import com.iotechn.unimall.data.model.Page;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * Description:
+ * User: kbq
+ * Date: 2019-07-12
+ * Time: 下午11:26
+ */
+@Service
+public class AdminCouponServiceImpl implements AdminCouponService {
+
+    @Autowired
+    private CouponMapper couponMapper;
+
+    @Autowired
+    private UserCouponMapper userCouponMapper;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public CouponDO addCoupon(Long adminId, String title, Integer type, String description, Integer total, Integer limit, Integer discount, Integer min, Integer status, Long categoryId, Integer days, Long gmtStart, Long gmtEnd) throws ServiceException {
+
+        Date start = null;
+        Date end = null;
+        if (gmtEnd != null && gmtStart != null) {
+            start = new Date(gmtStart);
+            end = new Date(gmtEnd);
+        }
+
+        CouponDO couponDO = new CouponDO(title, type, description, total, total, limit, discount, min, status, categoryId, days, start, end);
+
+        Date now = new Date();
+        couponDO.setGmtCreate(now);
+        couponDO.setGmtUpdate(now);
+        if (couponMapper.insert(couponDO) > 0) {
+            return couponDO;
+        }
+        throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteCoupon(Long adminId, Long id) throws ServiceException {
+        EntityWrapper wrapperC = new EntityWrapper();
+        wrapperC.eq("id", id);
+        if (couponMapper.delete(wrapperC) <= 0) {
+            throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
+        }
+        EntityWrapper wrapperUC = new EntityWrapper();
+        wrapperUC.eq("coupon_id", id);
+        userCouponMapper.delete(wrapperUC);
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updateCoupon(Long adminId, Long id, String title, Integer type, String description, Integer total, Integer surplus, Integer limit, Integer discount, Integer min, Integer status, Long categoryId, Integer days, Date gmtStart, Date gmtEnd) throws ServiceException {
+        CouponDO couponDO = new CouponDO(title, type, description, total, surplus, limit, discount, min, status, categoryId, days, gmtStart, gmtEnd);
+        couponDO.setId(id);
+        List<CouponDO> couponDOList = couponMapper.selectList(new EntityWrapper<CouponDO>().eq("id", id));
+        if (CollectionUtils.isEmpty(couponDOList)) {
+            throw new AdminServiceException(ExceptionDefinition.COUPON_NOT_EXIST);
+        }
+        Date now = new Date();
+        couponDO.setGmtCreate(couponDOList.get(0).getGmtCreate());
+        couponDO.setGmtUpdate(now);
+        return couponMapper.updateAllColumnById(couponDO) > 0;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updateCouponStatus(Long adminId, Long id, Integer status) throws ServiceException {
+        CouponDO couponDO = new CouponDO();
+        couponDO.setId(id);
+        couponDO.setStatus(status);
+        couponDO.setGmtUpdate(new Date());
+        return couponMapper.updateById(couponDO) > 0;
+    }
+
+    @Override
+    public Page<CouponAdminDTO> queryCouponByTitle(Long adminId, String title, Integer type, Integer status, Integer pageNo, Integer limit) throws ServiceException {
+        EntityWrapper wrapper = new EntityWrapper();
+        Date now = new Date();
+        if (!StringUtils.isEmpty(title)) {
+            wrapper.like("title", title);
+        }
+        if (type != null) {
+            wrapper.eq("type", type);
+        }
+        if (status != null) {
+            if (status >= 0 && status < 2) {
+                wrapper.eq("status", status);
+                wrapper.andNew().gt("gmt_end", now).or().isNotNull("days"); //coupon -> conpon.gt("gmt_end", now).or().isNotNull("days")
+            } else if (status < 0) {
+                wrapper.lt("gmt_end", now);
+            } else {
+                throw new AdminServiceException(ExceptionDefinition.COUPON_CHECK_DATA_FAILED);
+            }
+        }
+        Integer count = couponMapper.selectCount(wrapper);
+        List<CouponAdminDTO> couponDTOList = couponMapper.getAdminCouponList(title, type, status, now, (pageNo - 1) * limit, limit);
+        Page<CouponAdminDTO> page = new Page<CouponAdminDTO>(couponDTOList, pageNo, limit, count);
+        return page;
+    }
+}

+ 2 - 6
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dashboard/DashboardService.java

@@ -14,11 +14,7 @@ import com.iotechn.unimall.core.exception.ServiceException;
 public interface DashboardService {
 
     @HttpMethod(description = "聚合数据")
-    Object integral(
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "companyId") Long companyId) throws ServiceException;
-    @HttpMethod(description = "获取adminId")
-    String getAdminId(
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
+    public Object integral(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
 
 }

+ 44 - 10
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dashboard/DashboardServiceImpl.java

@@ -1,14 +1,19 @@
 package com.iotechn.unimall.admin.api.dashboard;
 
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
 import com.iotechn.unimall.core.exception.ServiceException;
-import com.iotechn.unimall.data.domain.AdminDO;
+import com.iotechn.unimall.data.domain.OrderDO;
+import com.iotechn.unimall.data.domain.SpuDO;
 import com.iotechn.unimall.data.dto.DashboardIntegralDTO;
-import com.iotechn.unimall.data.mapper.*;
+import com.iotechn.unimall.data.enums.OrderStatusType;
+import com.iotechn.unimall.data.mapper.OrderMapper;
+import com.iotechn.unimall.data.mapper.SpuMapper;
 import com.iotechn.unimall.data.model.KVModel;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
@@ -20,15 +25,27 @@ import java.util.List;
 public class DashboardServiceImpl implements DashboardService {
 
     @Autowired
-    private AdminMapper adminMapper;
+    private OrderMapper orderMapper;
+
+    @Autowired
+    private SpuMapper spuMapper;
+
     @Override
-    public Object integral(Long adminId,Long companyId) throws ServiceException {
+    public Object integral(Long adminId) throws ServiceException {
         DashboardIntegralDTO dto = new DashboardIntegralDTO();
-        AdminDO adminDO = adminMapper.selectById(adminId);
-        dto.setCompanyId(adminDO.getCompanyId());
+        Integer orderWaitStock = orderMapper.selectCount(new EntityWrapper<OrderDO>().eq("status", OrderStatusType.WAIT_STOCK.getCode()));
+        Integer spuCount = spuMapper.selectCount(new EntityWrapper<SpuDO>());
+        List<KVModel<String, Long>> area = orderMapper.selectAreaStatistics();
+        List<KVModel<String, Long>> channel = orderMapper.selectChannelStatistics();
+        dto.setArea(area);
+        dto.setChannel(channel);
+        dto.setWaitStockCount(orderWaitStock);
+        dto.setGoodsCount(spuCount);
         Integer days = 7;
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
         String startDay = sdf.format(new Date(System.currentTimeMillis() - 1000l * 60 * 60 * 24 * days));
+        List<KVModel<String, Long>> orderCountKVList = orderMapper.selectOrderCountStatistics(startDay);
+        List<KVModel<String, Long>> orderSumKVList = orderMapper.selectOrderSumStatistics(startDay);
         SimpleDateFormat sdfDay = new SimpleDateFormat("yyyy-MM-dd");
         List<Object[]> orderCount = new LinkedList<>();
         Object[] orderCountNameArray = new Object[days];
@@ -42,11 +59,28 @@ public class DashboardServiceImpl implements DashboardService {
         orderSum.add(orderSumNameArray);
         orderSum.add(orderSumValueArray);
         dto.setDaysSum(orderSum);
+        //这里是在补全 group by 为 0 的情况
+        for (int i = 0; i < days; i++) {
+            Date date = new Date(System.currentTimeMillis() - 1000l * 60 * 60 * 24 * i);
+            String key = sdfDay.format(date);
+            int i1 = orderCountKVList.indexOf(new KVModel<>(key, null));
+            if (i1 >= 0) {
+                orderCountNameArray[days - i - 1] = key;
+                orderCountValueArray[days - i - 1] = orderCountKVList.get(i1).getValue();
+            } else {
+                orderCountNameArray[days - i - 1] = key;
+                orderCountValueArray[days - i - 1] = 0;
+            }
 
+            int i2 = orderSumKVList.indexOf(new KVModel<>(key, null));
+            if (i2 >= 0) {
+                orderSumNameArray[days - i - 1] = key;
+                orderSumValueArray[days - i - 1] = orderSumKVList.get(i2).getValue();
+            } else {
+                orderSumNameArray[days - i - 1] = key;
+                orderSumValueArray[days - i - 1] = 0;
+            }
+        }
         return dto;
     }
-    @Override
-    public String getAdminId(Long adminId) throws ServiceException {
-        return adminId+"";
-    }
 }

+ 50 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dict/DictDataService.java

@@ -0,0 +1,50 @@
+package com.iotechn.unimall.admin.api.dict;
+
+import java.util.List;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.sys.dict.SysDictData;
+import com.iotechn.unimall.data.model.Page;
+
+@HttpOpenApi(group = "admin.dictData", description = "字典数据服务")
+public interface DictDataService {
+	@HttpMethod(description = "创建", permission = "admin:dictData:add", permissionParentName = "系统管理", permissionName = "字典管理")
+	public Boolean add(
+			@NotNull @HttpParam(name = "dictData", type = HttpParamType.COMMON, description = "字典信息") SysDictData dictData)
+			throws ServiceException;
+
+	@HttpMethod(description = "列表", permission = "admin:dictData:list", permissionParentName = "系统管理", permissionName = "字典管理")
+	public Page<SysDictData> list(
+			@HttpParam(name = "dictType", type = HttpParamType.COMMON, description = "字典类型") String dictType,
+			@HttpParam(name = "dictLabel", type = HttpParamType.COMMON, description = "字典标签") String dictLabel,
+			@HttpParam(name = "status", type = HttpParamType.COMMON, description = "状态") String status,
+			@HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
+			@HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "20") Integer limit)
+			throws ServiceException;
+
+	@HttpMethod(description = "删除", permission = "admin:dictData:delete", permissionParentName = "系统管理", permissionName = "字典管理")
+	public Boolean delete(
+			@NotNull @HttpParam(name = "dictCodes", type = HttpParamType.COMMON, description = "字典Id") String dictCodes)
+			throws ServiceException;
+
+	@HttpMethod(description = "修改", permission = "admin:dictData:update", permissionParentName = "系统管理", permissionName = "字典管理")
+	public Boolean update(
+			@NotNull @HttpParam(name = "dictData", type = HttpParamType.COMMON, description = "字典信息") SysDictData dictData)
+			throws ServiceException;
+
+	@HttpMethod(description = "查询", permission = "admin:dictData:get", permissionParentName = "系统管理", permissionName = "字典管理")
+	public SysDictData get(
+			@HttpParam(name = "dictCode", type = HttpParamType.COMMON, description = "字典ID") String dictCode)
+			throws ServiceException;
+
+	@HttpMethod(description = "根据字典类型查询所属数据", permission = "admin:dictData:selectDictDataByType", permissionParentName = "系统管理", permissionName = "字典管理")
+	public List<SysDictData> selectDictDataByType(
+			@HttpParam(name = "dictType", type = HttpParamType.COMMON, description = "字典类型") String dictType)
+			throws ServiceException;
+
+}

+ 77 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dict/DictDataserviceImpl.java

@@ -0,0 +1,77 @@
+package com.iotechn.unimall.admin.api.dict;
+
+import java.util.List;
+
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.sys.dict.SysDictData;
+import com.iotechn.unimall.data.mapper.sys.dict.SysDictDataMapper;
+import com.iotechn.unimall.data.model.Page;
+/**
+ * 
+ * @author dyl
+ *
+ */
+@Service
+public class DictDataserviceImpl implements DictDataService{
+
+	@Autowired
+	private SysDictDataMapper dictDataMapper;
+	
+	@Override
+	public Boolean add(SysDictData dictData) throws ServiceException {
+		return dictDataMapper.insert(dictData)>0;
+	}
+
+	@Override
+	public Page<SysDictData> list(String dictType, String dictLabel, String status,Integer page, Integer limit)
+			throws ServiceException {
+		Wrapper<SysDictData> wrapper = new EntityWrapper<SysDictData>();
+		if (!StringUtils.isEmpty(dictType)) {
+			wrapper.eq("dict_type", dictType);
+		}
+		if (!StringUtils.isEmpty(dictType)) {
+			wrapper.like("dict_label", dictLabel);
+		}
+		if (!StringUtils.isEmpty(status)) {
+			wrapper.like("status", status);
+		}
+		List<SysDictData> SysDictDataS = dictDataMapper.selectPage(new RowBounds((page - 1) * limit, limit), wrapper);
+		Integer count = dictDataMapper.selectCount(wrapper);
+		return new Page<SysDictData>(SysDictDataS, page, limit, count);
+	}
+
+	@Override
+	public Boolean delete(String dictCodes) throws ServiceException {
+		String[] ids=dictCodes.split(",");
+		Wrapper<SysDictData> wrapper = new EntityWrapper<SysDictData>();
+		wrapper.in("dict_code", ids);
+		return dictDataMapper.delete(wrapper)>0;
+	}
+
+	@Override
+	public Boolean update(SysDictData dictData) throws ServiceException {
+		return dictDataMapper.updateById(dictData)>0;
+	}
+
+	@Override
+	public SysDictData get(String dictCode) throws ServiceException {
+		return dictDataMapper.selectById(dictCode);
+	}
+
+	@Override
+	public List<SysDictData> selectDictDataByType(String dictType) throws ServiceException {
+		Wrapper<SysDictData> wrapper = new EntityWrapper<SysDictData>();
+        if (!StringUtils.isEmpty(dictType)) {
+            wrapper.eq("dict_type", dictType);
+        }
+		return dictDataMapper.selectList(wrapper);
+	}
+
+}

+ 48 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dict/DictTypeService.java

@@ -0,0 +1,48 @@
+package com.iotechn.unimall.admin.api.dict;
+
+import java.util.List;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.sys.dict.SysDictType;
+import com.iotechn.unimall.data.model.Page;
+
+@HttpOpenApi(group = "admin.dictType", description = "字典类型服务")
+public interface DictTypeService {
+	@HttpMethod(description = "创建", permission = "admin:dictType:add", permissionParentName = "系统管理", permissionName = "字典管理")
+	public Boolean add(
+			@NotNull @HttpParam(name = "dictType", type = HttpParamType.COMMON, description = "字典信息") SysDictType dictType)
+			throws ServiceException;
+
+	@HttpMethod(description = "列表", permission = "admin:dictType:list", permissionParentName = "系统管理", permissionName = "字典管理")
+	public Page<SysDictType> list(
+			@HttpParam(name = "dictName", type = HttpParamType.COMMON, description = "字典名称") String dictName,
+			@HttpParam(name = "dictType", type = HttpParamType.COMMON, description = "字典类型") String dictType,
+			@HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
+			@HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "20") Integer limit)
+			throws ServiceException;
+
+	@HttpMethod(description = "删除", permission = "admin:dictType:delete", permissionParentName = "系统管理", permissionName = "字典管理")
+	public Boolean delete(
+			@NotNull @HttpParam(name = "dictIds", type = HttpParamType.COMMON, description = "字典Id") String dictIds)
+			throws ServiceException;
+
+	@HttpMethod(description = "修改", permission = "admin:dictType:update", permissionParentName = "系统管理", permissionName = "字典管理")
+	public Boolean update(
+			@NotNull @HttpParam(name = "dictType", type = HttpParamType.COMMON, description = "字典信息") SysDictType dictType)
+			throws ServiceException;
+
+	@HttpMethod(description = "查询", permission = "admin:dictType:get", permissionParentName = "系统管理", permissionName = "字典管理")
+	public SysDictType get(
+			@HttpParam(name = "dictId", type = HttpParamType.COMMON, description = "字典ID") Long dictId)
+			throws ServiceException;
+
+	@HttpMethod(description = "字典选择框列表", permission = "admin:dictType:optionselect", permissionParentName = "系统管理", permissionName = "字典管理")
+	public List<SysDictType> optionselect()throws ServiceException;
+
+
+}

+ 86 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/dict/DictTypeServiceImpl.java

@@ -0,0 +1,86 @@
+package com.iotechn.unimall.admin.api.dict;
+
+import java.util.List;
+
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.iotechn.unimall.core.exception.AdminServiceException;
+import com.iotechn.unimall.core.exception.ExceptionDefinition;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.sys.dict.SysDictType;
+import com.iotechn.unimall.data.mapper.sys.dict.SysDictTypeMapper;
+import com.iotechn.unimall.data.model.Page;
+
+/**
+ * 
+ * @author dyl
+ *
+ */
+@Service
+public class DictTypeServiceImpl implements DictTypeService {
+
+	@Autowired
+	private SysDictTypeMapper typeMapper;
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public Boolean add(SysDictType sysDictType) throws ServiceException {
+		Long dictId;
+		if (sysDictType.getDictId() == null)
+			dictId = -1L;
+		else
+			dictId = sysDictType.getDictId();
+		SysDictType dictType = typeMapper.checkDictTypeUnique(sysDictType);
+		if (dictType != null && dictType.getDictId().longValue() != dictId.longValue()) {
+			throw new AdminServiceException(ExceptionDefinition.DICT_TYPE_HAS_EXISTED);
+		}
+		return typeMapper.insert(sysDictType) > 0;
+	}
+
+	@Override
+	public Page<SysDictType> list(String dictName, String dictType, Integer page, Integer limit)
+			throws ServiceException {
+		Wrapper<SysDictType> wrapper = new EntityWrapper<SysDictType>();
+		if (!StringUtils.isEmpty(dictName)) {
+			wrapper.like("dict_name", dictName);
+		}
+		if (!StringUtils.isEmpty(dictType)) {
+			wrapper.eq("dict_type", dictType);
+		}
+		List<SysDictType> SysDictTypeS = typeMapper.selectPage(new RowBounds((page - 1) * limit, limit), wrapper);
+		Integer count = typeMapper.selectCount(wrapper);
+		return new Page<SysDictType>(SysDictTypeS, page, limit, count);
+	}
+
+	@Override
+	public Boolean delete(String dictIds) throws ServiceException {
+		String[] ids=dictIds.split(",");
+		Wrapper<SysDictType> wrapper = new EntityWrapper<SysDictType>();
+		wrapper.in("dict_id", ids);
+		return typeMapper.delete(wrapper) > 0;
+	}
+
+	@Override
+	public Boolean update(SysDictType dictType) throws ServiceException {
+
+		return typeMapper.updateById(dictType) > 0;
+	}
+
+	@Override
+	public SysDictType get(Long dictId) throws ServiceException {
+		return typeMapper.selectById(dictId);
+	}
+
+	@Override
+	public List<SysDictType> optionselect() throws ServiceException {
+		return typeMapper.selectDictTypeAll();
+	}
+
+
+}

+ 62 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/freight/AdminFreightTemplateService.java

@@ -0,0 +1,62 @@
+package com.iotechn.unimall.admin.api.freight;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.annotation.param.Range;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.FreightTemplateCarriageDO;
+import com.iotechn.unimall.data.dto.freight.FreightTemplateDTO;
+
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * Description:
+ * User: kbq
+ * Date: 2019-07-07
+ * Time: 下午3:37
+ */
+@HttpOpenApi(group = "admin.freight", description = "运费模板")
+public interface AdminFreightTemplateService {
+
+    @HttpMethod(description = "创建", permission = "operation:freight:create", permissionParentName = "运营管理", permissionName = "运费模板管理")
+    public boolean addFreightTemplate(
+            @NotNull @HttpParam(name = "templateName", type = HttpParamType.COMMON, description = "模板名称") String templateName,
+            @HttpParam(name = "spuLocation", type = HttpParamType.COMMON, description = "宝贝地址") String spuLocation,
+            @NotNull @HttpParam(name = "deliveryDeadline", type = HttpParamType.COMMON, description = "发货期限") Integer deliveryDeadline,
+            @NotNull @HttpParam(name = "defaultFreePrice", type = HttpParamType.COMMON, description = "默认满价包邮系列") Integer defaultFreePrice,
+            @NotNull @HttpParam(name = "defaultFirstNum", type = HttpParamType.COMMON, description = "默认首费") Integer defaultFirstNum,
+            @NotNull @Range(min = 1) @HttpParam(name = "defaultFirstPrice", type = HttpParamType.COMMON, description = "默认首件数量") Integer defaultFirstPrice,
+            @NotNull @HttpParam(name = "defaultContinueNum", type = HttpParamType.COMMON, description = "默认续费") Integer defaultContinueNum,
+            @NotNull @Range(min = 1) @HttpParam(name = "defaultContinuePrice", type = HttpParamType.COMMON, description = "默认续件数量") Integer defaultContinuePrice,
+            @HttpParam(name = "freightTemplateCarriageDOList", type = HttpParamType.COMMON, description = "特殊运费区") List freightTemplateCarriageDOList,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId
+    ) throws ServiceException;
+
+    @HttpMethod(description = "删除", permission = "operation:freight:delete", permissionParentName = "运营管理", permissionName = "运费模板管理")
+    public boolean deleteFreightTemplate(
+            @NotNull @HttpParam(name = "templateId", type = HttpParamType.COMMON, description = "模板ID") Long templateId,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
+
+    @HttpMethod(description = "更新", permission = "operation:freight:update", permissionParentName = "运营管理", permissionName = "运费模板管理")
+    public boolean updateFreightTemplate(
+            @NotNull @HttpParam(name = "templateId", type = HttpParamType.COMMON, description = "模板名称") Long templateId,
+            @NotNull @HttpParam(name = "templateName", type = HttpParamType.COMMON, description = "模板名称") String templateName,
+            @HttpParam(name = "spuLocation", type = HttpParamType.COMMON, description = "宝贝地址") String spuLocation,
+            @NotNull @HttpParam(name = "deliveryDeadline", type = HttpParamType.COMMON, description = "发货期限") Integer deliveryDeadline,
+            @NotNull @HttpParam(name = "defaultFreePrice", type = HttpParamType.COMMON, description = "默认满价包邮系列") Integer defaultFreePrice,
+            @NotNull @Range(min = 1) @HttpParam(name = "defaultFirstNum", type = HttpParamType.COMMON, description = "默认首费") Integer defaultFirstNum,
+            @NotNull @Range(min = 0) @HttpParam(name = "defaultFirstPrice", type = HttpParamType.COMMON, description = "默认首件数量") Integer defaultFirstPrice,
+            @NotNull @Range(min = 1) @HttpParam(name = "defaultContinueNum", type = HttpParamType.COMMON, description = "默认续费") Integer defaultContinueNum,
+            @NotNull @Range(min = 0) @HttpParam(name = "defaultContinuePrice", type = HttpParamType.COMMON, description = "默认续件数量") Integer defaultContinuePrice,
+            @HttpParam(name = "freightTemplateCarriageDOList", type = HttpParamType.COMMON, description = "特殊运费区") List templateCarriageDOList,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
+
+    @HttpMethod(description = "查询", permission = "operation:freight:query", permissionParentName = "运营管理", permissionName = "运费模板管理")
+    public List<FreightTemplateDTO> getAllFreightTemplate(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
+
+}

+ 147 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/freight/AdminFreightTemplateServiceImpl.java

@@ -0,0 +1,147 @@
+package com.iotechn.unimall.admin.api.freight;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.iotechn.unimall.biz.service.goods.GoodsBizService;
+import com.iotechn.unimall.core.exception.AdminServiceException;
+import com.iotechn.unimall.core.exception.ExceptionDefinition;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.component.CacheComponent;
+import com.iotechn.unimall.data.domain.FreightTemplateCarriageDO;
+import com.iotechn.unimall.data.domain.FreightTemplateDO;
+import com.iotechn.unimall.data.domain.SpuDO;
+import com.iotechn.unimall.data.dto.freight.FreightTemplateDTO;
+import com.iotechn.unimall.data.mapper.FreightTemplateCarriageMapper;
+import com.iotechn.unimall.data.mapper.FreightTemplateMapper;
+import com.iotechn.unimall.data.mapper.SpuMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Created with IntelliJ IDEA.
+ * Description:
+ * User: kbq
+ * Date: 2019-07-07
+ * Time: 下午4:25
+ */
+@Service
+public class AdminFreightTemplateServiceImpl implements AdminFreightTemplateService {
+
+    @Autowired
+    private FreightTemplateMapper freightTemplateMapper;
+
+    @Autowired
+    private FreightTemplateCarriageMapper freightTemplateCarriageMapper;
+
+    @Autowired
+    private SpuMapper spuMapper;
+
+    @Autowired
+    private CacheComponent cacheComponent;
+
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean addFreightTemplate(String templateName, String spuLocation, Integer deliveryDeadline, Integer defaultFreePrice, Integer defaultFirstNum, Integer defaultFirstPrice, Integer defaultContinueNum, Integer defaultContinuePrice, List freightTemplateCarriageDOList, Long adminId) throws ServiceException {
+        Date now = new Date();
+        FreightTemplateDO freightTemplateDO = new FreightTemplateDO(templateName, spuLocation, deliveryDeadline, defaultFreePrice, defaultFirstNum, defaultFirstPrice, defaultContinueNum, defaultContinuePrice);
+        freightTemplateDO.setGmtCreate(now);
+        freightTemplateDO.setGmtUpdate(now);
+        int judgeSQL = freightTemplateMapper.insert(freightTemplateDO); //插入模板主表
+        if (judgeSQL <= 0) {
+            throw new AdminServiceException(ExceptionDefinition.FREIGHT_TEMPLATE_INSERT_FAILED);
+        }
+        if (CollectionUtils.isEmpty(freightTemplateCarriageDOList)) {
+            return true;
+        }
+        List<FreightTemplateCarriageDO> collect = (List<FreightTemplateCarriageDO>) freightTemplateCarriageDOList.stream().map(item -> {
+            FreightTemplateCarriageDO t = JSONObject.toJavaObject((JSON) item, FreightTemplateCarriageDO.class);
+            return t;
+        }).collect(Collectors.toList());
+        insertFreightTemplateCarriage(freightTemplateDO, collect, now);
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteFreightTemplate(Long templateId, Long adminId) throws ServiceException {
+        if (spuMapper.selectCount(new EntityWrapper<SpuDO>().eq("freight_template_id", templateId)) > 0) {
+            throw new AdminServiceException(ExceptionDefinition.FREIGHT_SPU_QUERY_HAS);
+        }
+        if (freightTemplateMapper.delete(new EntityWrapper<FreightTemplateDO>().eq("id", templateId)) <= 0) {
+            throw new AdminServiceException(ExceptionDefinition.FREIGHT_TEMPLATE_DELETE_FAILED);
+        }
+        if (freightTemplateCarriageMapper.delete(
+                new EntityWrapper<FreightTemplateCarriageDO>()
+                        .eq("template_id", templateId)) > 0) {
+            cacheComponent.delPrefixKey(GoodsBizService.CA_SPU_PREFIX);
+            return true;
+        }
+        throw new AdminServiceException(ExceptionDefinition.FREIGHT_TEMPLATE_UPDATE_FAILED);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean updateFreightTemplate(Long templateId, String templateName, String spuLocation, Integer deliveryDeadline, Integer defaultFreePrice, Integer defaultFirstNum, Integer defaultFirstPrice, Integer defaultContinueNum, Integer defaultContinuePrice, List freightTemplateCarriageDOList, Long adminId) throws ServiceException {
+        Date now = new Date();
+        FreightTemplateDO freightTemplateDO = new FreightTemplateDO(templateName, spuLocation, deliveryDeadline, defaultFreePrice, defaultFirstNum, defaultFirstPrice, defaultContinueNum, defaultContinuePrice);
+        freightTemplateDO.setId(templateId);
+        freightTemplateDO.setGmtUpdate(now);
+        if (freightTemplateMapper.updateById(freightTemplateDO) <= 0) {    //如果主表修改失败
+            throw new AdminServiceException(ExceptionDefinition.FREIGHT_TEMPLATE_UPDATE_FAILED);
+        }
+        freightTemplateCarriageMapper.delete(new EntityWrapper<FreightTemplateCarriageDO>().eq("template_id", templateId));
+        if (CollectionUtils.isEmpty(freightTemplateCarriageDOList)) {
+            return true;
+        }
+        List<FreightTemplateCarriageDO> collect = (List<FreightTemplateCarriageDO>) freightTemplateCarriageDOList.stream().map(item -> {
+            FreightTemplateCarriageDO t = JSONObject.toJavaObject((JSON) item, FreightTemplateCarriageDO.class);
+            return t;
+        }).collect(Collectors.toList());
+        insertFreightTemplateCarriage(freightTemplateDO, collect, now);
+        cacheComponent.delPrefixKey(GoodsBizService.CA_SPU_PREFIX);
+        return true;
+    }
+
+    private void insertFreightTemplateCarriage(FreightTemplateDO freightTemplateDO, List<FreightTemplateCarriageDO> freightTemplateCarriageDOList, Date now) throws ServiceException {
+        //表中设定可默认值,所以就不检查是否为空
+        for (FreightTemplateCarriageDO freightTemplateCarriageDO : freightTemplateCarriageDOList) {
+            freightTemplateCarriageDO.setTemplateId(freightTemplateDO.getId());
+            freightTemplateCarriageDO.setGmtCreate(now);
+            freightTemplateCarriageDO.setGmtUpdate(now);
+            Integer judgeSQL = freightTemplateCarriageMapper.insert(freightTemplateCarriageDO);
+            if (judgeSQL <= 0) {
+                throw new AdminServiceException(ExceptionDefinition.FREIGHT_CARRIAGE_INSERT_FAILED);
+            }
+        }
+    }
+
+    @Override
+    public List<FreightTemplateDTO> getAllFreightTemplate(Long adminId) throws ServiceException {
+        List<FreightTemplateDO> freightTemplateDOList = freightTemplateMapper.selectList(null); //查出主表所有数据
+        List<FreightTemplateDTO> freightTemplateDTOList = new ArrayList<>();
+        if (freightTemplateDOList == null || freightTemplateDOList.size() == 0) { //如果主表没有记录
+            return freightTemplateDTOList;
+        }
+        for (FreightTemplateDO freightTemplateDO : freightTemplateDOList) {  //查出副表中,主表每条数据对应的数据
+            FreightTemplateDTO freightTemplateDTO = new FreightTemplateDTO();
+            List<FreightTemplateCarriageDO> freightTemplateCarriageDOList = freightTemplateCarriageMapper.selectList(new EntityWrapper<FreightTemplateCarriageDO>()
+                    .eq("template_id", freightTemplateDO.getId()));
+            freightTemplateDTO.setFreightTemplateDO(freightTemplateDO);
+            freightTemplateDTO.setFreightTemplateCarriageDOList(freightTemplateCarriageDOList);
+            freightTemplateDTOList.add(freightTemplateDTO);
+        }
+        return freightTemplateDTOList;
+    }
+
+
+}

+ 64 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/goods/AdminGoodsService.java

@@ -0,0 +1,64 @@
+package com.iotechn.unimall.admin.api.goods;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.dto.goods.SpuDTO;
+import com.iotechn.unimall.data.dto.goods.SpuTreeNodeDTO;
+import com.iotechn.unimall.data.model.Page;
+
+import java.util.List;
+
+/**
+ * Created by rize on 2019/7/11.
+ */
+@HttpOpenApi(group = "admin.goods", description = "管理员商品服务")
+public interface AdminGoodsService {
+
+    @HttpMethod(description = "获取SPU树")
+    public List<SpuTreeNodeDTO> getSpuBigTree(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
+
+
+    @HttpMethod(description = "创建", permission = "operation:goods:create", permissionParentName = "商品管理", permissionName = "商品管理")
+    public String create(
+            @NotNull @HttpParam(name = "spuDTO", type = HttpParamType.COMMON, description = "商品JSON数据") SpuDTO spuDTO,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
+
+
+    @HttpMethod(description = "编辑", permission = "operation:goods:edit", permissionParentName = "商品管理", permissionName = "商品管理")
+    public String edit(
+            @NotNull @HttpParam(name = "spuDTO", type = HttpParamType.COMMON, description = "商品JSON数据") SpuDTO spuDTO,
+            @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
+
+    @HttpMethod(description = "列表", permission = "operation:goods:list", permissionParentName = "商品管理", permissionName = "商品管理")
+    public Page<SpuDTO> list(
+            @HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
+            @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "20") Integer limit,
+            @HttpParam(name = "categoryId", type = HttpParamType.COMMON, description = "搜索分类") Long categoryId,
+            @HttpParam(name = "title", type = HttpParamType.COMMON, description = "搜索标题") String title,
+            @HttpParam(name = "barcode", type = HttpParamType.COMMON, description = "商品条形码") String barcode,
+            @HttpParam(name = "status", type = HttpParamType.COMMON, description = "商品状态") Integer status,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
+
+    @HttpMethod(description = "详情", permission = "operation:goods:detail", permissionParentName = "商品管理", permissionName = "商品管理")
+    public SpuDTO detail(
+            @NotNull @HttpParam(name = "spuId", type = HttpParamType.COMMON, description = "商品Id") Long spuId,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
+
+    @HttpMethod(description = "上下架", permission = "operation:goods:edit", permissionParentName = "商品管理", permissionName = "商品管理")
+    public SpuDTO freezeOrActivation(
+            @NotNull @HttpParam(name = "spuId", type = HttpParamType.COMMON, description = "商品Id") Long spuId,
+            @NotNull @HttpParam(name = "status", type = HttpParamType.COMMON, description = "商品想要变为的状态") Integer status,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
+
+
+    @HttpMethod(description = "删除", permission = "operation:goods:delete", permissionParentName = "商品管理", permissionName = "商品管理")
+    public String delete(
+            @NotNull @HttpParam(name = "spuId", type = HttpParamType.COMMON, description = "商品Id") Long spuId,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
+
+}

+ 414 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/goods/AdminGoodsServiceImpl.java

@@ -0,0 +1,414 @@
+package com.iotechn.unimall.admin.api.goods;
+
+import com.baomidou.mybatisplus.entity.Column;
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.iotechn.unimall.biz.service.goods.GoodsBizService;
+import com.iotechn.unimall.core.Const;
+import com.iotechn.unimall.core.exception.AdminServiceException;
+import com.iotechn.unimall.core.exception.ExceptionDefinition;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.component.CacheComponent;
+import com.iotechn.unimall.data.domain.*;
+import com.iotechn.unimall.data.dto.goods.SpuDTO;
+import com.iotechn.unimall.data.dto.goods.SpuTreeNodeDTO;
+import com.iotechn.unimall.data.enums.BizType;
+import com.iotechn.unimall.data.enums.SpuStatusType;
+import com.iotechn.unimall.data.mapper.*;
+import com.iotechn.unimall.data.model.Page;
+import com.iotechn.unimall.plugin.core.inter.IPluginUpdateGoods;
+import com.iotechn.unimall.plugin.core.manager.PluginsManager;
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Created by rize on 2019/7/11.
+ */
+@Service
+public class AdminGoodsServiceImpl implements AdminGoodsService {
+
+    @Autowired
+    private CategoryMapper categoryMapper;
+
+    @Autowired
+    private SpuMapper spuMapper;
+
+    @Autowired
+    private SkuMapper skuMapper;
+
+    @Autowired
+    private SpuAttributeMapper spuAttributeMapper;
+
+    @Autowired
+    private ImgMapper imgMapper;
+
+    @Autowired
+    private CartMapper cartMapper;
+
+    @Autowired
+    private GoodsBizService goodsBizService;
+
+    @Autowired
+    private PluginsManager pluginsManager;
+
+    @Autowired
+    private CacheComponent cacheComponent;
+
+    private static final Column[] spuBaseColumns = {
+            Column.create().column("id"),
+            Column.create().column("original_price").as("originalPrice"),
+            Column.create().column("price"),
+            Column.create().column("vip_price").as("vipPrice"),
+            Column.create().column("title"),
+            Column.create().column("sales"),
+            Column.create().column("img"),
+            Column.create().column("description"),
+            Column.create().column("category_id").as("categoryId"),
+            Column.create().column("freight_template_id").as("freightTemplateId"),
+            Column.create().column("unit"),
+            Column.create().column("status")};
+
+    /**
+     * 后台低频接口, 无需缓存
+     * @return
+     * @throws ServiceException
+     */
+    public List<SpuTreeNodeDTO> getSpuBigTree(Long adminId) throws  ServiceException{
+        List<CategoryDO> categoryDOS = categoryMapper.selectList(new EntityWrapper<CategoryDO>().orderBy("level"));
+        List<SpuDO> spuDOS = spuMapper.getSpuTitleAll();
+        List<SpuTreeNodeDTO> list = new ArrayList<>();
+        Integer recordLevelOne = 0;
+        Integer recordLevelTwo = 0;
+        for (int i = 0; i < categoryDOS.size(); i++) {
+            if(i != 0 && categoryDOS.get(i-1).getLevel().equals(0) && categoryDOS.get(i).getLevel().equals(1)){
+                recordLevelOne = i;
+            }
+            if(i != 0 && categoryDOS.get(i-1).getLevel().equals(1) && categoryDOS.get(i).getLevel().equals(2)){
+                recordLevelTwo = i;
+                break;
+            }
+        }
+
+        for (int i = 0; i < recordLevelOne; i++) {
+            CategoryDO categoryOnI = categoryDOS.get(i);    //一级类目
+            SpuTreeNodeDTO dtoOnI = new SpuTreeNodeDTO();
+            dtoOnI.setLabel(categoryOnI.getTitle());
+            dtoOnI.setValue("C_" + categoryOnI.getId());
+            dtoOnI.setId(categoryOnI.getId());
+            dtoOnI.setChildren(new LinkedList<>());
+            for (int j = recordLevelOne; j < recordLevelTwo; j++) {
+                CategoryDO categoryOnJ = categoryDOS.get(j);    //二级类目
+                if(!categoryOnJ.getParentId().equals(dtoOnI.getId())){
+                    continue;
+                }
+
+                SpuTreeNodeDTO dtoOnJ = new SpuTreeNodeDTO();
+                dtoOnJ.setLabel(categoryOnJ.getTitle());
+                dtoOnJ.setValue("C_" + categoryOnJ.getId());
+                dtoOnJ.setId(categoryOnJ.getId());
+                dtoOnJ.setChildren(new LinkedList<>());
+                
+                for (int p = recordLevelTwo; p <categoryDOS.size() ; p++) {
+                    CategoryDO categoryOnP = categoryDOS.get(p);    //三级类目
+                    if(!categoryOnP.getParentId().equals(dtoOnJ.getId())){
+                        continue;
+                    }
+
+                    SpuTreeNodeDTO dtoOnP = new SpuTreeNodeDTO();
+                    dtoOnP.setLabel(categoryOnP.getTitle());
+                    dtoOnP.setValue("C_" + categoryOnP.getId());
+                    dtoOnP.setId(categoryOnP.getId());
+                    dtoOnP.setChildren(new LinkedList<>());
+
+                    for (int k = 0; k < spuDOS.size(); k++) {
+                        if(k != 0 && spuDOS.get(k-1).getCategoryId().equals(dtoOnP.getId()) && !spuDOS.get(k).getCategoryId().equals(dtoOnP.getId())){
+                            break;
+                        }
+                        SpuDO spuDO = spuDOS.get(k);        //商品
+                        if(spuDO.getCategoryId().equals(dtoOnP.getId())){
+                            SpuTreeNodeDTO dtoOnK = new SpuTreeNodeDTO();
+                            dtoOnK.setLabel(spuDO.getTitle());
+                            dtoOnK.setValue("G_" + spuDO.getId());
+                            dtoOnK.setId(spuDO.getId());
+                            dtoOnK.setChildren(new LinkedList<>());
+                            dtoOnP.getChildren().add(dtoOnK);
+                        }
+                    }
+                    dtoOnJ.getChildren().add(dtoOnP);
+                }
+                dtoOnI.getChildren().add(dtoOnJ);
+            }
+            list.add(dtoOnI);
+        }
+        return list;
+    }
+
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String create(SpuDTO spuDTO, Long adminId) throws ServiceException {
+        //参数校验
+        if (CollectionUtils.isEmpty(spuDTO.getSkuList())) {
+            throw new AdminServiceException(ExceptionDefinition.GOODS_SKU_LIST_EMPTY);
+        }
+        if (spuDTO.getId() != null) {
+            throw new AdminServiceException(ExceptionDefinition.GOODS_CREATE_HAS_ID);
+        }
+        if (spuDTO.getOriginalPrice() < spuDTO.getPrice() || spuDTO.getPrice() < spuDTO.getVipPrice() || spuDTO.getOriginalPrice() < spuDTO.getVipPrice()) {
+            throw new AdminServiceException(ExceptionDefinition.GOODS_PRICE_CHECKED_FAILED);
+        }
+        //校验Sku是否重复
+        List<String> barCodes = spuDTO.getSkuList().stream().map(item -> item.getBarCode()).collect(Collectors.toList());
+        List<SkuDO> existSkuDO = skuMapper.selectList(new EntityWrapper<SkuDO>().in("bar_code", barCodes));
+        if (!CollectionUtils.isEmpty(existSkuDO)) {
+            String spuIds = existSkuDO.stream().map(item -> item.getSpuId().toString()).collect(Collectors.joining(","));
+            String skuIds = existSkuDO.stream().map(item -> item.getBarCode()).collect(Collectors.joining(","));
+            throw new AdminServiceException(ExceptionDefinition
+                    .buildVariableException(ExceptionDefinition.GOODS_CREATE_BARCODE_REPEAT, spuIds, skuIds));
+        }
+        Date now = new Date();
+        SpuDO spuDO = new SpuDO();
+        BeanUtils.copyProperties(spuDTO, spuDO);
+        spuDO.setGmtUpdate(now);
+        spuDO.setGmtCreate(now);
+        spuDO.setSales(0);
+        spuMapper.insert(spuDO);
+        spuDTO.setId(spuDO.getId());
+        //插入SKU表
+        for (SkuDO skuDO : spuDTO.getSkuList()) {
+            if (skuDO.getOriginalPrice() < skuDO.getPrice() || skuDO.getPrice() < skuDO.getVipPrice() || skuDO.getOriginalPrice() < skuDO.getVipPrice()) {
+                throw new AdminServiceException(ExceptionDefinition.GOODS_PRICE_CHECKED_FAILED);
+            }
+            skuDO.setSpuId(spuDO.getId());
+            skuDO.setGmtUpdate(now);
+            skuDO.setGmtCreate(now);
+            skuDO.setFreezeStock(0);
+            skuMapper.insert(skuDO);
+        }
+        //插入spuAttr
+        insertSpuAttribute(spuDTO, now);
+        //插入IMG
+        insertSpuImg(spuDTO, spuDO.getId(), now);
+        goodsBizService.clearGoodsCache(spuDO.getId());
+        pluginUpdateInvoke(spuDO.getId());
+
+        cacheComponent.delPrefixKey(GoodsBizService.CA_SPU_PAGE_PREFIX);
+        return "ok";
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String edit(SpuDTO spuDTO, Long adminId) throws ServiceException {
+        if (spuDTO.getId() == null) {
+            throw new AdminServiceException(ExceptionDefinition.PARAM_CHECK_FAILED);
+        }
+        if (CollectionUtils.isEmpty(spuDTO.getSkuList())) {
+            throw new AdminServiceException(ExceptionDefinition.GOODS_SKU_LIST_EMPTY);
+        }
+        if (spuDTO.getOriginalPrice() < spuDTO.getPrice() || spuDTO.getPrice() < spuDTO.getVipPrice() || spuDTO.getOriginalPrice() < spuDTO.getVipPrice()) {
+            throw new AdminServiceException(ExceptionDefinition.GOODS_PRICE_CHECKED_FAILED);
+        }
+        Date now = new Date();
+        SpuDO spuDO = new SpuDO();
+        BeanUtils.copyProperties(spuDTO, spuDO);
+        spuDO.setGmtUpdate(now);
+        spuMapper.updateById(spuDO);
+        List<String> barCodes = new LinkedList<>();
+        for (SkuDO skuDO : spuDTO.getSkuList()) {
+            if (skuDO.getOriginalPrice() < skuDO.getPrice() || skuDO.getPrice() < skuDO.getVipPrice() || skuDO.getOriginalPrice() < skuDO.getVipPrice()) {
+                throw new AdminServiceException(ExceptionDefinition.GOODS_PRICE_CHECKED_FAILED);
+            }
+            skuDO.setId(null);
+            skuDO.setSpuId(spuDO.getId());
+            skuDO.setGmtUpdate(now);
+            skuDO.setFreezeStock(0);
+            if (skuMapper.update(skuDO,
+                    new EntityWrapper<SkuDO>()
+                            .eq("bar_code", skuDO.getBarCode())) <= 0) {
+                skuDO.setGmtCreate(now);
+                skuMapper.insert(skuDO);
+            }
+            barCodes.add(skuDO.getBarCode());
+        }
+        //删除多余barCode
+        skuMapper.delete(new EntityWrapper<SkuDO>().eq("spu_id", spuDO.getId()).notIn("bar_code",barCodes));
+        //插入spuAttr
+        spuAttributeMapper.delete(new EntityWrapper<SpuAttributeDO>().eq("spu_id", spuDTO.getId()));
+        insertSpuAttribute(spuDTO, now);
+        imgMapper.delete(new EntityWrapper<ImgDO>().eq("biz_id", spuDO.getId()).eq("biz_type", BizType.GOODS.getCode()));
+        //插入IMG
+        insertSpuImg(spuDTO, spuDO.getId(), now);
+        goodsBizService.clearGoodsCache(spuDTO.getId());
+        pluginUpdateInvoke(spuDTO.getId());
+
+        cacheComponent.delPrefixKey(GoodsBizService.CA_SPU_PAGE_PREFIX);
+        return "ok";
+    }
+
+    private void insertSpuAttribute(SpuDTO spuDTO, Date now) {
+        if (!CollectionUtils.isEmpty(spuDTO.getAttributeList())) {
+            for (SpuAttributeDO spuAttributeDO : spuDTO.getAttributeList()) {
+                spuAttributeDO.setSpuId(spuDTO.getId());
+                spuAttributeDO.setGmtUpdate(now);
+                spuAttributeDO.setGmtCreate(now);
+                spuAttributeMapper.insert(spuAttributeDO);
+            }
+        }
+    }
+
+    private void insertSpuImg(SpuDTO spuDTO, Long bizId, Date now) {
+        List<String> imgList = spuDTO.getImgList();
+        List<ImgDO> imgDOList = imgList.stream().map(item -> {
+            ImgDO imgDO = new ImgDO();
+            imgDO.setBizType(BizType.GOODS.getCode());
+            imgDO.setBizId(bizId);
+            imgDO.setUrl(item);
+            imgDO.setGmtCreate(now);
+            imgDO.setGmtUpdate(now);
+            return imgDO;
+        }).collect(Collectors.toList());
+        imgMapper.insertImgs(imgDOList);
+    }
+
+    @Override
+    public Page<SpuDTO> list(Integer page, Integer limit, Long categoryId, String title,String barcode, Integer status, Long adminId) throws ServiceException {
+        Wrapper<SpuDO> wrapper = new EntityWrapper<SpuDO>();
+
+        if (!StringUtils.isEmpty(title)) {
+            wrapper.like("title", title);
+        }
+
+        if (categoryId != null && categoryId != 0L) {
+            List<CategoryDO> childrenList = categoryMapper.selectList(new EntityWrapper<CategoryDO>().eq("parent_id", categoryId));
+            // 传入类目拥有的三级类目集合
+            LinkedList<Long> childrenIds = new LinkedList<>();
+
+            // 传入类目没有子类目
+            if (CollectionUtils.isEmpty(childrenList)) {
+                // 则传入类目为三级类目
+                childrenIds.add(categoryId);
+            } else {
+
+                CategoryDO categoryDO = categoryMapper.selectById(categoryId);
+
+                // 检验传入类目是一级还是二级类目
+                if (categoryDO.getParentId() != 0L) {
+                    //二级分类
+                    childrenList.forEach(item -> {
+                        childrenIds.add(item.getId());
+                    });
+                } else {
+                    //一级分类
+                    childrenList.forEach(item -> {
+                        List<CategoryDO> leafList = categoryMapper.selectList(new EntityWrapper<CategoryDO>().eq("parent_id", item.getId()));
+                        if (!CollectionUtils.isEmpty(leafList)) {
+                            leafList.forEach(leafItem -> {
+                                childrenIds.add(leafItem.getId());
+                            });
+                        }
+                    });
+                }
+            }
+            wrapper.in("category_id", childrenIds);
+        }
+
+        if(status != null){
+            wrapper.eq("status", status.intValue() <= SpuStatusType.STOCK.getCode()?SpuStatusType.STOCK.getCode():SpuStatusType.SELLING.getCode());
+        }
+
+        if(barcode != null){
+            List<SkuDO> skuDOList = skuMapper.selectList(new EntityWrapper<SkuDO>().eq("bar_code", barcode));
+            if(!CollectionUtils.isEmpty(skuDOList)){
+                SkuDO skuDO = skuDOList.get(0);
+                wrapper.eq("id",skuDO.getSpuId());
+            }
+        }
+
+        wrapper.setSqlSelect(spuBaseColumns);
+        List<SpuDO> spuDOS = spuMapper.selectPage(new RowBounds((page - 1) * limit, limit), wrapper);
+
+        //组装SPU
+        List<SpuDTO> spuDTOList = new ArrayList<>();
+        spuDOS.forEach(item -> {
+            SpuDTO spuDTO = new SpuDTO();
+            BeanUtils.copyProperties(item, spuDTO);
+            List<SkuDO> skuDOList = skuMapper.selectList(new EntityWrapper<SkuDO>().eq("spu_id", item.getId()));
+            spuDTO.setSkuList(skuDOList);
+            spuDTOList.add(spuDTO);
+        });
+
+        Integer count = spuMapper.selectCount(wrapper);
+        Page<SpuDTO> dtoPage = new Page<>(spuDTOList, page, limit, count);
+
+        return dtoPage;
+    }
+
+    @Override
+    public SpuDTO detail(Long spuId, Long adminId) throws ServiceException {
+        return goodsBizService.getGoods(spuId, null);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String delete(Long spuId, Long adminId) throws ServiceException {
+        if (spuMapper.deleteById(spuId) <= 0) {
+            throw new AdminServiceException(ExceptionDefinition.GOODS_NOT_EXIST);
+        }
+        cartMapper.delete(new EntityWrapper<CartDO>().in("sku_id", skuMapper.getSkuIds(spuId)));
+        skuMapper.delete(new EntityWrapper<SkuDO>().eq("spu_id", spuId));
+        imgMapper.delete(new EntityWrapper<ImgDO>().eq("biz_id", spuId).eq("biz_type", BizType.GOODS.getCode()));
+        spuAttributeMapper.delete(new EntityWrapper<SpuAttributeDO>().eq("spu_id", spuId));
+        goodsBizService.clearGoodsCache(spuId);
+        pluginUpdateInvoke(spuId);
+
+        cacheComponent.delPrefixKey(GoodsBizService.CA_SPU_PAGE_PREFIX);
+        return "ok";
+    }
+
+    private void pluginUpdateInvoke(Long spuId) {
+        List<IPluginUpdateGoods> plugins = pluginsManager.getPlugins(IPluginUpdateGoods.class);
+        if (!CollectionUtils.isEmpty(plugins)) {
+            for (IPluginUpdateGoods updateGoods : plugins) {
+                updateGoods.invokeGoodsUpdate(spuId);
+            }
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public SpuDTO freezeOrActivation(Long spuId, Integer status, Long adminId) throws ServiceException {
+        SpuDO spuDO = spuMapper.selectById(spuId);
+
+        if(spuDO == null){
+            throw new AdminServiceException(ExceptionDefinition.GOODS_NOT_EXIST);
+        }
+
+        status = status <= SpuStatusType.STOCK.getCode() ? SpuStatusType.STOCK.getCode() : SpuStatusType.SELLING.getCode();
+
+        if(spuDO.getStatus().intValue() == status.intValue()){
+            throw new AdminServiceException(ExceptionDefinition.GOODS_NEED_STATUS_ERROR);
+        }
+
+        spuDO.setStatus(status);
+        spuDO.setGmtUpdate(new Date());
+        if(spuMapper.updateById(spuDO) <= 0){
+            throw new AdminServiceException(ExceptionDefinition.GOODS_UPDATE_SQL_FAILED);
+        }
+
+        SpuDTO spuDTO = new SpuDTO();
+        BeanUtils.copyProperties(spuDO,spuDTO);
+        List<SkuDO> skuDOList = skuMapper.selectList(new EntityWrapper<SkuDO>().eq("spu_id", spuDO.getId()));
+        spuDTO.setSkuList(skuDOList);
+
+        cacheComponent.delPrefixKey(GoodsBizService.CA_SPU_PAGE_PREFIX);
+        return spuDTO;
+    }
+}

+ 55 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/goods/AdminGroupShopGoodsService.java

@@ -0,0 +1,55 @@
+package com.iotechn.unimall.admin.api.goods;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.annotation.param.Range;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.GroupShopSkuDO;
+import com.iotechn.unimall.data.dto.goods.GroupShopDTO;
+import com.iotechn.unimall.data.dto.goods.SpuDTO;
+import com.iotechn.unimall.data.model.Page;
+
+import java.util.List;
+
+@HttpOpenApi(group = "admin.groupShop", description = "管理团购商品服务")
+public interface AdminGroupShopGoodsService {
+
+    @HttpMethod(description = "增加", permission = "operation:groupShop:create", permissionParentName = "商品管理", permissionName = "团购商品管理")
+    public String addGroupShopSpu(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId,
+            @NotNull @HttpParam(name = "spuId", type = HttpParamType.COMMON, description = "spuId") Long spuId,
+            @NotNull @HttpParam(name = "gmtStart", type = HttpParamType.COMMON, description = "团购开始时间戳") Long gmtStart,
+            @NotNull @HttpParam(name = "gmtEnd", type = HttpParamType.COMMON, description = "团购结束时间戳") Long gmtEnd,
+            @NotNull @Range(min = 1) @HttpParam(name = "minimumNumber", type = HttpParamType.COMMON, description = "团购最低人数") Integer minimumNumber,
+            @NotNull @HttpParam(name = "automaticRefund", type = HttpParamType.COMMON, description = "团购人数未满是否自动退款")  Integer automaticRefund,
+            @NotNull @HttpParam(name = "groupShopSkuList", type = HttpParamType.COMMON, description = "团购sku链表") List groupShopSkuList) throws ServiceException;
+
+    @HttpMethod(description = "删除", permission = "operation:groupShop:delete", permissionParentName = "商品管理", permissionName = "团购商品管理")
+    public String deleteGroupShopSpu(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId,
+            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "团购商品的Id") Long id) throws  ServiceException;
+
+    @HttpMethod(description = "修改", permission = "operation:groupShop:update", permissionParentName = "商品管理", permissionName = "团购商品管理")
+    public GroupShopDTO editGroupShopSpu(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId,
+            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "团购商品spuID") Long id,
+            @NotNull @HttpParam(name = "spuId", type = HttpParamType.COMMON, description = "spuId") Long spuId,
+            @NotNull @HttpParam(name = "gmtStart", type = HttpParamType.COMMON, description = "团购开始时间戳") Long gmtStart,
+            @NotNull @HttpParam(name = "gmtEnd", type = HttpParamType.COMMON, description = "团购结束时间戳") Long gmtEnd,
+            @NotNull @Range(min = 1) @HttpParam(name = "minimumNumber", type = HttpParamType.COMMON, description = "团购最低人数") Integer minimumNumber,
+            @NotNull @HttpParam(name = "automaticRefund", type = HttpParamType.COMMON, description = "团购人数未满是否自动退款")  Integer automaticRefund,
+            @NotNull @HttpParam(name = "groupShopSkuList", type = HttpParamType.COMMON, description = "团购sku链表") List groupShopSkuDOList ) throws ServiceException;
+
+    @HttpMethod(description = "查询", permission = "operation:groupShop:query", permissionParentName = "商品管理", permissionName = "团购商品管理")
+    public Page<GroupShopDTO> queryGroupShop(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId,
+            @HttpParam(name = "id", type = HttpParamType.COMMON, description = "团购商品的ID") Long id,
+            @HttpParam(name = "spuName", type = HttpParamType.COMMON, description = "团购商品的名称") String spuName,
+            @HttpParam(name = "status", type = HttpParamType.COMMON, description = "团购商品的状态") Integer status,
+            @Range(min = 1) @HttpParam(name = "page", type = HttpParamType.COMMON, description = "团购商品页码", valueDef = "1") Integer page,
+            @Range(min = 1) @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "团购商品长度", valueDef = "20") Integer limit ) throws ServiceException;
+
+}

+ 290 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/goods/AdminGroupShopGoodsServiceImpl.java

@@ -0,0 +1,290 @@
+package com.iotechn.unimall.admin.api.goods;/*
+@PackageName:com.iotechn.unimall.admin.api.goods
+@ClassName: AdminGroupShopGoodsServiceImpl
+@Description:
+@author kbq
+@date 19-11-13下午4:21
+*/
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.iotechn.unimall.admin.api.order.AdminOrderService;
+import com.iotechn.unimall.core.exception.AdminServiceException;
+import com.iotechn.unimall.core.exception.ExceptionDefinition;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.component.CacheComponent;
+import com.iotechn.unimall.data.domain.*;
+import com.iotechn.unimall.data.dto.goods.GroupShopSkuDTO;
+import com.iotechn.unimall.data.dto.goods.GroupShopDTO;
+import com.iotechn.unimall.data.enums.GroupShopAutomaticRefundType;
+import com.iotechn.unimall.data.enums.StatusType;
+import com.iotechn.unimall.data.mapper.*;
+import com.iotechn.unimall.data.model.Page;
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Comparator;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+@EnableScheduling
+public class AdminGroupShopGoodsServiceImpl implements AdminGroupShopGoodsService {
+
+    @Autowired
+    private SkuMapper skuMapper;
+
+    @Autowired
+    private SpuMapper spuMapper;
+
+    @Autowired
+    private GroupShopMapper groupShopMapper;
+
+    @Autowired
+    private GroupShopSkuMapper groupShopSkuMapper;
+
+    @Autowired
+    private CacheComponent cacheComponent;
+
+    private static final String GROUP_SHOP_CACHE = "CA_GROUP_SHOP";
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String addGroupShopSpu(Long adminId, Long spuId, Long gmtStart, Long gmtEnd, Integer minimumNumber, Integer automaticRefund, List groupShopSkuList) throws ServiceException {
+        // 1.转化为对应的GroupShopSkuDo类的链表
+        List<GroupShopSkuDO> groupShopSkuDOList = (List<GroupShopSkuDO>) groupShopSkuList.stream().map(t -> {
+            GroupShopSkuDO groupShopSkuDO = JSONObject.toJavaObject((JSON) t, GroupShopSkuDO.class);
+            return groupShopSkuDO;
+        }).sorted(Comparator.comparingInt(o -> ((GroupShopSkuDO) o).getSkuGroupShopPrice())).collect(Collectors.toList());
+
+        if (gmtStart.compareTo(gmtEnd) >= 0) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_START_MUST_LESS_THAN_END);
+        }
+
+        // 2.检验数据库中是否存在spuId对应的sku
+        SpuDO spuDO = spuMapper.selectById(spuId);
+        List<SkuDO> skuDOList = skuMapper.selectList((new EntityWrapper<SkuDO>().eq("spu_id", spuId)));
+        if (spuDO == null || CollectionUtils.isEmpty(skuDOList)) {
+            throw new AdminServiceException(ExceptionDefinition.SPU_NO_EXITS_OR_ONLY_SPU);
+        }
+        // 2.1 检验groupShop表中是否存在此商品
+        Integer count = groupShopMapper.selectCount((new EntityWrapper<GroupShopDO>().eq("spu_id", spuId)));
+        if (count > 0) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_ALREADY_EXIT);
+        }
+
+        Date timeStart = new Date(gmtStart);
+        Date timeEnd = new Date(gmtEnd);
+        Date now = new Date();
+        GroupShopDO groupShopDO = new GroupShopDO();
+
+        groupShopDO.setAlreadyBuyNumber(0);
+        groupShopDO.setMinimumNumber(minimumNumber);
+        groupShopDO.setGmtStart(timeStart);
+        groupShopDO.setGmtEnd(timeEnd);
+        groupShopDO.setAutomaticRefund(automaticRefund.compareTo(0) > 0 ? GroupShopAutomaticRefundType.YES.getCode() : GroupShopAutomaticRefundType.NO.getCode());
+        groupShopDO.setSpuId(spuId);
+        groupShopDO.setMinPrice(groupShopSkuDOList.get(0).getSkuGroupShopPrice());
+        groupShopDO.setMaxPrice(groupShopSkuDOList.get(groupShopSkuDOList.size() - 1).getSkuGroupShopPrice());
+        groupShopDO.setGmtCreate(now);
+        groupShopDO.setGmtUpdate(now);
+        // 3.设置是否在活动时间的状态
+        setGroupShopStatus(now, gmtStart, gmtEnd, spuDO, groupShopDO);
+        if (groupShopMapper.insert(groupShopDO) <= 0) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_SPU_ADD_SQL_QUERY_ERROR);
+        }
+
+        if (skuDOList.size() != groupShopSkuDOList.size()) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_SKU_NUMBER_ERROR);
+        }
+        // 4.插入groupShopSkuList
+        this.insertGroupShopSkuList(groupShopSkuDOList, skuDOList, groupShopDO.getId(), now);
+        cacheComponent.delPrefixKey(GROUP_SHOP_CACHE);
+        return "ok";
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String deleteGroupShopSpu(Long adminId, Long id) throws ServiceException {
+
+        GroupShopDO groupShopDO = groupShopMapper.selectById(id);
+        if (groupShopDO == null) {
+            throw new AdminServiceException(ExceptionDefinition.SPU_NO_EXITS_OR_ONLY_SPU);
+        }
+
+        if (groupShopDO.getStatus() > 0) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_ALREAD_ATCIVE);
+        }
+
+        if (groupShopMapper.deleteById(id) <= 0) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_SPU_DELETE_SQL_QUERY_ERROR);
+        }
+        if (groupShopSkuMapper.delete((new EntityWrapper<GroupShopSkuDO>().eq("group_shop_id", id))) <= 0) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_SKU_DELETE_SQL_QUERY_ERROR);
+        }
+
+        cacheComponent.delPrefixKey(GROUP_SHOP_CACHE);
+        return "ok";
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public GroupShopDTO editGroupShopSpu(Long adminId, Long id, Long spuId, Long gmtStart, Long gmtEnd, Integer minimumNumber, Integer automaticRefund, List groupShopSkuList) throws ServiceException {
+        // 1.转化为对应的GroupShopSkuDo类的链表
+        List<GroupShopSkuDO> groupShopSkuDOList = (List<GroupShopSkuDO>) groupShopSkuList.stream().map(t -> {
+            GroupShopSkuDO groupShopSkuDO = JSONObject.toJavaObject((JSON) t, GroupShopSkuDO.class);
+            return groupShopSkuDO;
+        }).sorted(Comparator.comparingInt(o -> ((GroupShopSkuDO) o).getSkuGroupShopPrice())).collect(Collectors.toList());
+
+        if (gmtStart.compareTo(gmtEnd) >= 0) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_START_MUST_LESS_THAN_END);
+        }
+
+        SpuDO spuDO = spuMapper.selectById(spuId);
+        List<SkuDO> skuDOList = skuMapper.selectList((new EntityWrapper<SkuDO>().eq("spu_id", spuId)));
+        if (spuDO == null || CollectionUtils.isEmpty(skuDOList)) {
+            throw new AdminServiceException(ExceptionDefinition.SPU_NO_EXITS_OR_ONLY_SPU);
+        }
+
+        GroupShopDO groupShopDO = groupShopMapper.selectById(id);
+        if (groupShopDO == null) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_SPU_NO_EXITS);
+        }
+
+        if (groupShopDO.getStatus() > 0) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_ALREAD_ATCIVE);
+        }
+
+        Date timeStart = new Date(gmtStart);
+        Date timeEnd = new Date(gmtEnd);
+        Date now = new Date();
+
+        groupShopDO.setMinimumNumber(minimumNumber);
+        groupShopDO.setGmtStart(timeStart);
+        groupShopDO.setGmtEnd(timeEnd);
+        groupShopDO.setAutomaticRefund(automaticRefund.compareTo(0) > 0 ? StatusType.ACTIVE.getCode() : StatusType.LOCK.getCode());
+        groupShopDO.setSpuId(spuId);
+        groupShopDO.setMinPrice(groupShopSkuDOList.get(0).getSkuGroupShopPrice());
+        groupShopDO.setMinPrice(groupShopSkuDOList.get(groupShopSkuDOList.size() - 1).getSkuGroupShopPrice());
+        groupShopDO.setGmtUpdate(now);
+        this.setGroupShopStatus(now, gmtStart, gmtEnd, spuDO, groupShopDO);
+        if (groupShopMapper.updateById(groupShopDO) <= 0) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_SPU_UPDATE_SQL_QUERY_ERROR);
+        }
+
+        if (groupShopSkuMapper.delete((new EntityWrapper<GroupShopSkuDO>().eq("group_shop_id", id))) <= 0) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_SKU_DELETE_SQL_QUERY_ERROR);
+        }
+
+        if (skuDOList.size() != groupShopSkuDOList.size()) {
+            throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_SKU_NUMBER_ERROR);
+        }
+        // 4.插入groupShopSkuList
+        this.insertGroupShopSkuList(groupShopSkuDOList, skuDOList, groupShopDO.getId(), now);
+        cacheComponent.delPrefixKey(GROUP_SHOP_CACHE);
+        return new GroupShopDTO();
+    }
+
+    @Override
+    public Page<GroupShopDTO> queryGroupShop(Long adminId, Long id, String spuName, Integer status, Integer page, Integer limit) throws ServiceException {
+        EntityWrapper<GroupShopDO> groupShopSpuDOEntityWrapper = new EntityWrapper<GroupShopDO>();
+        if (id != null) {
+            groupShopSpuDOEntityWrapper.eq("id", id);
+        }
+
+        if (status != null) {
+            groupShopSpuDOEntityWrapper.eq("status", status);
+        }
+
+        if (spuName != null) {
+            EntityWrapper<SpuDO> spuDOEntityWrapper = new EntityWrapper<>();
+            spuDOEntityWrapper.setSqlSelect("id");
+            spuDOEntityWrapper.like("title", spuName);
+            List<Object> objectList = spuMapper.selectObjs(spuDOEntityWrapper);
+            List<String> collect = objectList.stream().map(s -> String.valueOf(s)).collect(Collectors.toList());
+            groupShopSpuDOEntityWrapper.in("spu_id", collect);
+        }
+
+        List<GroupShopDO> groupShopDOList = groupShopMapper.selectPage(new RowBounds((page - 1) * limit, limit), groupShopSpuDOEntityWrapper);
+        Integer count = groupShopMapper.selectCount(groupShopSpuDOEntityWrapper);
+        List<GroupShopDTO> groupShopDTOList = new LinkedList<>();
+
+        for (GroupShopDO groupShopDO : groupShopDOList) {
+            GroupShopDTO groupShopDTO = new GroupShopDTO();
+            SpuDO spuDO = spuMapper.selectById(groupShopDO.getSpuId());
+            BeanUtils.copyProperties(spuDO, groupShopDTO);
+            BeanUtils.copyProperties(groupShopDO, groupShopDTO);
+            /**
+             * 添加groupShopSkuDTOList
+             */
+            List<SkuDO> skuDOList = skuMapper.selectList((new EntityWrapper<SkuDO>().eq("spu_id", spuDO.getId())));
+            List<GroupShopSkuDO> groupShopSkuDOList = groupShopSkuMapper.selectList((new EntityWrapper<GroupShopSkuDO>()).eq("group_shop_id", groupShopDO.getId()));
+            List<GroupShopSkuDTO> groupShopSkuDTOList = groupShopSkuDOList.stream().map(s -> {
+                GroupShopSkuDTO groupShopSkuDTO = new GroupShopSkuDTO();
+                BeanUtils.copyProperties(s, groupShopSkuDTO);
+                return groupShopSkuDTO;
+            }).collect(Collectors.toList());
+
+            for (SkuDO skuDO : skuDOList) {
+                for (GroupShopSkuDTO groupShopSkuDTO : groupShopSkuDTOList) {
+                    if (groupShopSkuDTO.getSkuId().equals(skuDO.getId())) {
+                        BeanUtils.copyProperties(skuDO, groupShopSkuDTO);
+                        break;
+                    }
+                }
+            }
+            groupShopDTO.setGroupShopSkuDTOList(groupShopSkuDTOList);
+            groupShopDTOList.add(groupShopDTO);
+        }
+        return new Page<GroupShopDTO>(groupShopDTOList, page, limit, count);
+    }
+
+    private void setGroupShopStatus(Date now, Long gmtStart, Long gmtEnd, SpuDO spuDO, GroupShopDO groupShopDO) {
+        if (now.getTime() >= gmtStart.longValue() && now.getTime() < gmtEnd.longValue()) {
+            //3.1 商品本身是否处于下架状态
+            if (spuDO.getStatus().equals(StatusType.ACTIVE.getCode())) {
+                groupShopDO.setStatus(StatusType.ACTIVE.getCode());
+            } else {
+                groupShopDO.setStatus(StatusType.LOCK.getCode());
+            }
+        } else {
+            groupShopDO.setStatus(StatusType.LOCK.getCode());
+        }
+    }
+
+    private void insertGroupShopSkuList(List<GroupShopSkuDO> groupShopSkuDOList, List<SkuDO> skuDOList, Long groupShopId, Date now) throws ServiceException {
+        for (GroupShopSkuDO groupShopSkuDO : groupShopSkuDOList) {
+            boolean judge = false;
+            for (SkuDO sku : skuDOList) {
+                if (sku.getId().equals(groupShopSkuDO.getSkuId())) {
+                    judge = true;
+                    break;
+                }
+            }
+
+            if (!judge) {
+                throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_SKU_ID_ERROR);
+            }
+
+            if (groupShopSkuDO.getSkuGroupShopPrice() == null || groupShopSkuDO.getSkuGroupShopPrice().equals(0)) {
+                throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_SKU_PRICE_ERROR);
+            }
+
+            groupShopSkuDO.setGroupShopId(groupShopId);
+            groupShopSkuDO.setGmtCreate(now);
+            groupShopSkuDO.setGmtUpdate(now);
+            if (groupShopSkuMapper.insert(groupShopSkuDO) <= 0) {
+                throw new AdminServiceException(ExceptionDefinition.GROUP_SHOP_SKU_ADD_SQL_QUERY_ERROR);
+            }
+        }
+    }
+
+}

+ 40 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/log/loginLog/SysLogininforService.java

@@ -0,0 +1,40 @@
+package com.iotechn.unimall.admin.api.log.loginLog;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.log.SysLogininfor;
+import com.iotechn.unimall.data.model.Page;
+
+@HttpOpenApi(group = "admin.log.logininfor", description = "登陆日志管理")
+public interface SysLogininforService {
+	@HttpMethod(description = "登陆日志列表", permission = "admin:log:logininfor:list", permissionParentName = "日志管理", permissionName = "登陆日志管理")
+	public Page<SysLogininfor> list(
+			@HttpParam(name = "ipaddr", type = HttpParamType.COMMON, description = "登录地址") String ipaddr,
+			@HttpParam(name = "userName", type = HttpParamType.COMMON, description = "用户名称") String userName,
+			@HttpParam(name = "status", type = HttpParamType.COMMON, description = "状态") String status,
+			@HttpParam(name = "beginTime", type = HttpParamType.COMMON, description = "登陆开始时间") String beginTime,
+			@HttpParam(name = "endTime", type = HttpParamType.COMMON, description = "登陆结束时间") String endTime,
+			@HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
+			@HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "20") Integer limit)
+			throws ServiceException;
+	@HttpMethod(description = "删除登陆日志", permission = "admin:log:logininfor:delete", permissionParentName = "日志管理", permissionName = "登陆日志管理")
+	public Boolean delete(
+			@NotNull @HttpParam(name = "infoIds", type = HttpParamType.COMMON, description = "日志Id") String infoIds)
+			throws ServiceException;
+	
+	@HttpMethod(description = "清空登陆日志", permission = "admin:log:logininfor:clean", permissionParentName = "日志管理", permissionName = "登陆日志管理")
+	public Boolean clean()throws ServiceException;
+	
+	@HttpMethod(description = "导出日志列表", permission = "admin:log:logininfor:export", permissionParentName = "日志管理", permissionName = "登陆日志管理")
+	public String export(
+			@HttpParam(name = "ipaddr", type = HttpParamType.COMMON, description = "登录地址") String ipaddr,
+			@HttpParam(name = "userName", type = HttpParamType.COMMON, description = "用户名称") String userName,
+			@HttpParam(name = "status", type = HttpParamType.COMMON, description = "状态") String status,
+			@HttpParam(name = "beginTime", type = HttpParamType.COMMON, description = "登陆开始时间") String beginTime,
+			@HttpParam(name = "endTime", type = HttpParamType.COMMON, description = "登陆结束时间") String endTime)
+			throws ServiceException;
+}

+ 87 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/log/loginLog/SysLogininforServiceImpl.java

@@ -0,0 +1,87 @@
+package com.iotechn.unimall.admin.api.log.loginLog;
+
+import java.util.List;
+
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.log.SysLogininfor;
+import com.iotechn.unimall.data.mapper.log.SysLogininforMapper;
+import com.iotechn.unimall.data.model.Page;
+import com.iotechn.unimall.data.util.ExcelUtil;
+
+/**
+ * 
+ * @author dyl
+ *
+ */
+@Service
+public class SysLogininforServiceImpl implements SysLogininforService {
+
+	@Autowired
+	private SysLogininforMapper logininforMapper;
+
+	@Override
+	public Page<SysLogininfor> list(String ipaddr, String userName, String status, String beginTime, String endTime,
+			Integer page, Integer limit) throws ServiceException {
+		Wrapper<SysLogininfor> wrapper = new EntityWrapper<SysLogininfor>();
+		if (!StringUtils.isEmpty(ipaddr)) {
+			wrapper.like("ipaddr", ipaddr);
+		}
+		if (!StringUtils.isEmpty(userName)) {
+			wrapper.like("user_name", userName);
+		}
+		if (!StringUtils.isEmpty(status)) {
+			wrapper.eq("status", status);
+		}
+		if (!StringUtils.isEmpty(beginTime) && !StringUtils.isEmpty(endTime)) {
+			wrapper.between("login_time", beginTime, endTime);
+		}
+		wrapper.orderBy("info_id", false);
+		List<SysLogininfor> SysOperLogS = logininforMapper.selectPage(new RowBounds((page - 1) * limit, limit), wrapper);
+		Integer count = logininforMapper.selectCount(wrapper);
+		return new Page<SysLogininfor>(SysOperLogS, page, limit, count);
+	}
+
+	@Override
+	public Boolean delete(String infoIds) throws ServiceException {
+		String[] ids = infoIds.split(",");
+		Wrapper<SysLogininfor> wrapper = new EntityWrapper<SysLogininfor>();
+		wrapper.in("info_id", ids);
+		return logininforMapper.delete(wrapper) > 0;
+	}
+
+	@Override
+	public Boolean clean() throws ServiceException {
+		Wrapper<SysLogininfor> wrapper = new EntityWrapper<SysLogininfor>();
+		wrapper.eq("1", 1);
+		return logininforMapper.delete(wrapper) > 0;
+	}
+
+	@Override
+	public String export(String ipaddr, String userName, String status, String beginTime, String endTime)
+			throws ServiceException {
+		Wrapper<SysLogininfor> wrapper = new EntityWrapper<SysLogininfor>();
+		if (!StringUtils.isEmpty(ipaddr)) {
+			wrapper.like("ipaddr", ipaddr);
+		}
+		if (!StringUtils.isEmpty(userName)) {
+			wrapper.like("user_name", userName);
+		}
+		if (!StringUtils.isEmpty(status)) {
+			wrapper.eq("status", status);
+		}
+		if (!StringUtils.isEmpty(beginTime) && !StringUtils.isEmpty(endTime)) {
+			wrapper.between("login_time", beginTime, endTime);
+		}
+		List<SysLogininfor> list = logininforMapper.selectList(wrapper);
+		ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
+		return util.exportExcel(list, "操作日志");
+	}
+
+}

+ 40 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/log/operLog/OperLogService.java

@@ -0,0 +1,40 @@
+package com.iotechn.unimall.admin.api.log.operLog;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.log.SysOperLog;
+import com.iotechn.unimall.data.model.Page;
+
+@HttpOpenApi(group = "admin.log.operlog", description = "操作日志管理")
+public interface OperLogService {
+	@HttpMethod(description = "操作日志列表", permission = "admin:log:operlog:list", permissionParentName = "日志管理", permissionName = "操作日志管理")
+	public Page<SysOperLog> list(
+			@HttpParam(name = "title", type = HttpParamType.COMMON, description = "系统模块") String title,
+			@HttpParam(name = "operName", type = HttpParamType.COMMON, description = "操作人员") String operName,
+			@HttpParam(name = "businessType", type = HttpParamType.COMMON, description = "操作类型") String businessType,
+			@HttpParam(name = "beginTime", type = HttpParamType.COMMON, description = "操作开始时间") String beginTime,
+			@HttpParam(name = "endTime", type = HttpParamType.COMMON, description = "操作结束时间") String endTime,
+			@HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
+			@HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "20") Integer limit)
+			throws ServiceException;
+	@HttpMethod(description = "删除操作日志", permission = "admin:log:operlog:delete", permissionParentName = "日志管理", permissionName = "操作日志管理")
+	public Boolean delete(
+			@NotNull @HttpParam(name = "operIds", type = HttpParamType.COMMON, description = "日志Id") String operIds)
+			throws ServiceException;
+	
+	@HttpMethod(description = "清空操作日志", permission = "admin:log:operlog:clean", permissionParentName = "日志管理", permissionName = "操作日志管理")
+	public Boolean clean()throws ServiceException;
+	
+	@HttpMethod(description = "导出日志列表", permission = "admin:log:operlog:export", permissionParentName = "日志管理", permissionName = "操作日志管理")
+	public String export(
+			@HttpParam(name = "title", type = HttpParamType.COMMON, description = "系统模块") String title,
+			@HttpParam(name = "operName", type = HttpParamType.COMMON, description = "操作人员") String operName,
+			@HttpParam(name = "businessType", type = HttpParamType.COMMON, description = "操作类型") String businessType,
+			@HttpParam(name = "beginTime", type = HttpParamType.COMMON, description = "操作开始时间") String beginTime,
+			@HttpParam(name = "endTime", type = HttpParamType.COMMON, description = "操作结束时间") String endTime)
+			throws ServiceException;
+}

+ 87 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/log/operLog/OperLogServiceImpl.java

@@ -0,0 +1,87 @@
+package com.iotechn.unimall.admin.api.log.operLog;
+
+import java.util.List;
+
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.log.SysOperLog;
+import com.iotechn.unimall.data.mapper.log.SysOperLogMapper;
+import com.iotechn.unimall.data.model.Page;
+import com.iotechn.unimall.data.util.ExcelUtil;
+
+/**
+ * 
+ * @author dyl
+ *
+ */
+@Service
+public class OperLogServiceImpl implements OperLogService {
+
+	@Autowired
+	private SysOperLogMapper operLogMapper;
+
+	@Override
+	public Page<SysOperLog> list(String title, String operName, String businessType, String beginTime, String endTime,
+			Integer page, Integer limit) throws ServiceException {
+		Wrapper<SysOperLog> wrapper = new EntityWrapper<SysOperLog>();
+		if (!StringUtils.isEmpty(title)) {
+			wrapper.like("title", title);
+		}
+		if (!StringUtils.isEmpty(operName)) {
+			wrapper.like("oper_name", operName);
+		}
+		if (!StringUtils.isEmpty(businessType)) {
+			wrapper.eq("business_type", businessType);
+		}
+		if (!StringUtils.isEmpty(beginTime) && !StringUtils.isEmpty(endTime)) {
+			wrapper.between("oper_time", beginTime, endTime);
+		}
+		wrapper.orderBy("oper_id", false);
+		List<SysOperLog> SysOperLogS = operLogMapper.selectPage(new RowBounds((page - 1) * limit, limit), wrapper);
+		Integer count = operLogMapper.selectCount(wrapper);
+		return new Page<SysOperLog>(SysOperLogS, page, limit, count);
+	}
+
+	@Override
+	public Boolean delete(String operIds) throws ServiceException {
+		String[] ids = operIds.split(",");
+		Wrapper<SysOperLog> wrapper = new EntityWrapper<SysOperLog>();
+		wrapper.in("oper_id", ids);
+		return operLogMapper.delete(wrapper) > 0;
+	}
+
+	@Override
+	public Boolean clean() throws ServiceException {
+		Wrapper<SysOperLog> wrapper = new EntityWrapper<SysOperLog>();
+		wrapper.eq("1", 1);
+		return operLogMapper.delete(wrapper) > 0;
+	}
+
+	@Override
+	public String export(String title, String operName, String businessType, String beginTime, String endTime)
+			throws ServiceException {
+		Wrapper<SysOperLog> wrapper = new EntityWrapper<SysOperLog>();
+		if (!StringUtils.isEmpty(title)) {
+			wrapper.like("title", title);
+		}
+		if (!StringUtils.isEmpty(operName)) {
+			wrapper.like("oper_name", operName);
+		}
+		if (!StringUtils.isEmpty(businessType)) {
+			wrapper.eq("business_type", businessType);
+		}
+		if (!StringUtils.isEmpty(beginTime) && !StringUtils.isEmpty(endTime)) {
+			wrapper.between("oper_time", beginTime, endTime);
+		}
+		List<SysOperLog> list = operLogMapper.selectList(wrapper);
+		ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
+		return util.exportExcel(list, "操作日志");
+	}
+
+}

+ 0 - 55
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/message/MessageService.java

@@ -1,55 +0,0 @@
-package com.iotechn.unimall.admin.api.message;
-
-import com.iotechn.unimall.core.annotation.HttpMethod;
-import com.iotechn.unimall.core.annotation.HttpOpenApi;
-import com.iotechn.unimall.core.annotation.HttpParam;
-import com.iotechn.unimall.core.annotation.HttpParamType;
-import com.iotechn.unimall.core.annotation.param.NotNull;
-import com.iotechn.unimall.core.exception.ServiceException;
-import com.iotechn.unimall.data.model.Page;
-import com.iotechn.unimall.data.domain.MessageDO;
-
-import java.util.Date;
-
-/**
- * Generate Code By Unimall
- */
-@HttpOpenApi(group = "admin.message", description = "消息管理")
-public interface MessageService {
-
-    @HttpMethod(description = "删除", permission = "message:message:delete", permissionParentName = "系统管理", permissionName = "消息管理")
-    public boolean delete(
-            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "id") Long id,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
-
-
-    @HttpMethod(description = "查询", permission = "message:message:list", permissionParentName = "系统管理", permissionName = "消息管理")
-    public Page<MessageDO> list(
-            @HttpParam(name = "customer", type = HttpParamType.COMMON, description = "客户") String customer,
-            @HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
-            @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "20") Integer limit,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-
-    @HttpMethod(description = "添加", permission = "message:message:create", permissionParentName = "系统管理", permissionName = "消息管理")
-    public MessageDO create(
-            @NotNull @HttpParam(name = "customer", type = HttpParamType.COMMON, description = "客户") String customer,
-            @NotNull @HttpParam(name = "operation", type = HttpParamType.COMMON, description = "操作") String operation,
-            @NotNull @HttpParam(name = "result", type = HttpParamType.COMMON, description = "结果") String result,
-//            @NotNull @HttpParam(name = "gmtCreate", type = HttpParamType.COMMON, description = "创建时间") Date gmtCreate,
-//            @NotNull @HttpParam(name = "gmtUpdate", type = HttpParamType.COMMON, description = "更新时间") Date gmtUpdate,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-
-    @HttpMethod(description = "编辑", permission = "message:message:edit", permissionParentName = "系统管理", permissionName = "消息管理")
-    public String edit(
-            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "主键") Long id,
-            @NotNull @HttpParam(name = "customer", type = HttpParamType.COMMON, description = "客户") String customer,
-            @NotNull @HttpParam(name = "operation", type = HttpParamType.COMMON, description = "操作") String operation,
-            @NotNull @HttpParam(name = "result", type = HttpParamType.COMMON, description = "结果") String result,
-//            @NotNull @HttpParam(name = "gmtCreate", type = HttpParamType.COMMON, description = "创建时间") Date gmtCreate,
-//            @NotNull @HttpParam(name = "gmtUpdate", type = HttpParamType.COMMON, description = "更新时间") Date gmtUpdate,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-
-}

+ 0 - 85
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/message/MessageServiceImpl.java

@@ -1,85 +0,0 @@
-package com.iotechn.unimall.admin.api.message;
-
-
-import com.iotechn.unimall.core.exception.AdminServiceException;
-import com.iotechn.unimall.core.exception.ExceptionDefinition;
-import com.iotechn.unimall.core.exception.ServiceException;
-import com.iotechn.unimall.data.model.Page;
-import com.baomidou.mybatisplus.mapper.EntityWrapper;
-import com.baomidou.mybatisplus.mapper.Wrapper;
-import com.iotechn.unimall.data.domain.MessageDO;
-import com.iotechn.unimall.data.mapper.MessageMapper;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.apache.ibatis.session.RowBounds;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Generate Code By Unimall
- */
-@Service
-public class MessageServiceImpl implements MessageService {
-
-    @Autowired
-    private MessageMapper messageMapper;
-
-    @Override
-    public boolean delete(Long id,  Long adminId) throws ServiceException {
-        return messageMapper.deleteById(id) > 0;
-    }
-
-    @Override
-    public Page<MessageDO> list(String customer, Integer page, Integer limit, Long adminId,Long companyId) throws ServiceException {
-        Wrapper<MessageDO> wrapper = new EntityWrapper<MessageDO>();
-        if (customer != null) {
-            wrapper.like("customer", customer);
-        }
-        wrapper.orderBy("gmt_create",false);
-        wrapper.orderBy("gmt_update",false);
-        wrapper.eq("company_id",companyId);
-        List<MessageDO> list = messageMapper.selectPage(new RowBounds((page - 1) * limit, limit), wrapper);
-        Integer count = messageMapper.selectCount(wrapper);
-        return new Page<MessageDO>(list, page, limit, count);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public MessageDO create(String customer, String operation, String result,  Long adminId,Long companyId) throws ServiceException {
-         Date now = new Date();
-         MessageDO insertDO = new MessageDO();
-         insertDO.setCustomer(customer);
-         insertDO.setOperation(operation);
-         insertDO.setResult(result);
-//         insertDO.setGmtCreate(gmtCreate);
-//         insertDO.setGmtUpdate(gmtUpdate);
-         insertDO.setGmtUpdate(now);
-         insertDO.setGmtCreate(now);
-         insertDO.setCompanyId(companyId);
-         if (messageMapper.insert(insertDO) > 0) {
-             return insertDO;
-         }
-         throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public String edit(Long id, String customer, String operation, String result, Long adminId,Long companyId) throws ServiceException {
-         Date now = new Date();
-         MessageDO updateDO = new MessageDO();
-         updateDO.setId(id);
-         updateDO.setCustomer(customer);
-         updateDO.setOperation(operation);
-         updateDO.setResult(result);
-//         updateDO.setGmtCreate(gmtCreate);
-//         updateDO.setGmtUpdate(gmtUpdate);
-         updateDO.setGmtUpdate(now);
-         updateDO.setCompanyId(companyId);
-         if (messageMapper.updateById(updateDO) > 0) {
-             return "ok";
-         }
-         throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-    }
-
-}

+ 21 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/monitor/online/UserOnlineService.java

@@ -0,0 +1,21 @@
+package com.iotechn.unimall.admin.api.monitor.online;
+
+import java.util.List;
+
+import com.alibaba.fastjson.JSONObject;
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.exception.ServiceException;
+
+@HttpOpenApi(group = "admin.monitor.online", description = "在线用户管理")
+public interface UserOnlineService {
+	@HttpMethod(description = "在线用户列表", permission = "admin:monitor:online:list", permissionParentName = "系统管理", permissionName = "在线用户管理")
+	public List<JSONObject> list() throws ServiceException;
+	
+	@HttpMethod(description = "强退用户", permission = "admin:monitor:online:forceLogout", permissionParentName = "系统管理", permissionName = "在线用户管理")
+	public Boolean forceLogout(
+			@HttpParam(name = "tokenId", type = HttpParamType.COMMON, description = "用户token") String tokenId)
+			throws ServiceException;
+}

+ 45 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/monitor/online/UserOnlineServiceImpl.java

@@ -0,0 +1,45 @@
+package com.iotechn.unimall.admin.api.monitor.online;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+
+import com.alibaba.fastjson.JSONObject;
+import com.iotechn.unimall.core.Const;
+import com.iotechn.unimall.core.exception.ServiceException;
+/**
+ * 
+ * @author dyl
+ *
+ */
+@Service
+public class UserOnlineServiceImpl implements UserOnlineService {
+	@Autowired
+	private StringRedisTemplate userRedisTemplate;
+	
+	@Override
+	public List<JSONObject> list() throws ServiceException {
+		List<JSONObject> loginList=new ArrayList<JSONObject>();
+		Set<String> keys = userRedisTemplate.keys(Const.ADMIN_REDIS_PREFIX+"*");
+		Iterator<String> it1 = keys.iterator();
+		while (it1.hasNext()) {
+			String tokenId=it1.next();
+			JSONObject json = JSONObject.parseObject(userRedisTemplate.opsForValue().get(tokenId));
+			json.put("tokenId", tokenId.split("_")[2]);
+			json.put("expireTime", userRedisTemplate.getExpire(tokenId));
+			loginList.add(json);
+		}
+		return loginList;
+	}
+
+	@Override
+	public Boolean forceLogout(String tokenId) throws ServiceException {
+		return userRedisTemplate.delete(Const.ADMIN_REDIS_PREFIX  + tokenId);
+	}
+
+}

+ 11 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/monitor/server/ServerService.java

@@ -0,0 +1,11 @@
+package com.iotechn.unimall.admin.api.monitor.server;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.data.domain.monitor.Server;
+
+@HttpOpenApi(group = "admin.monitor.server", description = "服务监控数据")
+public interface ServerService {
+	@HttpMethod(description = "获取服务监控数据", permission = "admin:monitor:server:getInfo", permissionParentName = "系统管理", permissionName = "服务监控数据")
+	public Server getInfo()throws Exception;
+}

+ 22 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/monitor/server/ServerServiceImpl.java

@@ -0,0 +1,22 @@
+package com.iotechn.unimall.admin.api.monitor.server;
+
+import org.springframework.stereotype.Service;
+
+import com.iotechn.unimall.data.domain.monitor.Server;
+
+/**
+ * 
+ * @author dyl
+ *
+ */
+@Service
+public class ServerServiceImpl implements ServerService {
+
+	@Override
+	public Server getInfo() throws Exception {
+		Server server = new Server();
+		server.copyTo();
+		return server;
+	}
+
+}

+ 57 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/order/AdminOrderService.java

@@ -0,0 +1,57 @@
+package com.iotechn.unimall.admin.api.order;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.annotation.param.Range;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.OrderDO;
+import com.iotechn.unimall.data.dto.order.OrderDTO;
+import com.iotechn.unimall.data.model.Page;
+
+import java.util.List;
+
+/**
+ * Created by rize on 2019/7/10.
+ */
+@HttpOpenApi(group = "admin.order", description = "管理员订单服务")
+public interface AdminOrderService {
+
+    @HttpMethod(description = "列表", permission = "operation:order:list", permissionParentName = "运营管理", permissionName = "订单管理")
+    public Page<OrderDO> list(
+            @HttpParam(name = "page", type = HttpParamType.COMMON, description = "订单页码", valueDef = "1") Integer page,
+            @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "20") Integer limit,
+            @HttpParam(name = "status", type = HttpParamType.COMMON, description = "订单状态") Integer status,
+            @HttpParam(name = "orderNo", type = HttpParamType.COMMON, description = "订单号") String orderNo,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
+
+
+    @HttpMethod(description = "退款", permission = "operation:order:refund", permissionParentName = "运营管理", permissionName = "订单管理")
+    public String refund(
+            @NotNull @HttpParam(name = "orderNo", type = HttpParamType.COMMON, description = "订单号") String orderNo,
+            @NotNull @HttpParam(name = "type", type = HttpParamType.COMMON, description = "0.拒绝退款 1.同意退款") Integer type,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
+
+
+    @HttpMethod(description = "发货", permission = "operation:order:ship", permissionParentName = "运营管理", permissionName = "订单管理")
+    public String ship(
+            @NotNull @HttpParam(name = "orderNo", type = HttpParamType.COMMON, description = "订单号") String orderNo,
+            @NotNull @HttpParam(name = "shipCode", type = HttpParamType.COMMON, description = "承运商Code") String shipCode,
+            @HttpParam(name = "shipNo", type = HttpParamType.COMMON, description = "运单号") String shipNo,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
+
+    @HttpMethod(description = "详情", permission = "operation:order:detail", permissionParentName = "运营管理", permissionName = "订单管理")
+    public OrderDTO detail(
+            @NotNull @HttpParam(name = "orderId", type = HttpParamType.COMMON, description = "订单Id") Long orderNo,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
+
+
+    @HttpMethod(description = "根据传入时间和订单状态查询订单信息")
+    public List<OrderDTO> queryToExcel(
+            @HttpParam(name = "gmtStart", type = HttpParamType.COMMON, description = "查询开始时间") Long gmtStart,
+            @HttpParam(name = "gmtEnd", type = HttpParamType.COMMON, description = "查询结束时间") Long gmtEnd,
+            @HttpParam(name = "status", type = HttpParamType.COMMON, description = "订单状态", valueDef = "20") Integer status,
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
+}

+ 198 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/order/AdminOrderServiceImpl.java

@@ -0,0 +1,198 @@
+package com.iotechn.unimall.admin.api.order;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
+import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.iotechn.unimall.biz.service.order.OrderBizService;
+import com.iotechn.unimall.core.exception.AdminServiceException;
+import com.iotechn.unimall.core.exception.ExceptionDefinition;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.component.LockComponent;
+import com.iotechn.unimall.data.domain.OrderDO;
+import com.iotechn.unimall.data.domain.OrderSkuDO;
+import com.iotechn.unimall.data.domain.UserDO;
+import com.iotechn.unimall.data.dto.order.OrderDTO;
+import com.iotechn.unimall.data.enums.OrderStatusType;
+import com.iotechn.unimall.data.enums.UserLoginType;
+import com.iotechn.unimall.data.mapper.OrderMapper;
+import com.iotechn.unimall.data.mapper.OrderSkuMapper;
+import com.iotechn.unimall.data.mapper.UserMapper;
+import com.iotechn.unimall.data.model.Page;
+import org.apache.ibatis.session.RowBounds;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Created by rize on 2019/7/10.
+ */
+@Service
+public class AdminOrderServiceImpl implements AdminOrderService {
+
+    private static final Logger logger = LoggerFactory.getLogger(AdminOrderServiceImpl.class);
+
+    @Autowired
+    private OrderBizService orderBizService;
+
+    @Autowired
+    private WxPayService wxPayService;
+
+    @Autowired
+    private OrderMapper orderMapper;
+
+    @Autowired
+    private OrderSkuMapper orderSkuMapper;
+
+    @Autowired
+    private LockComponent lockComponent;
+
+    @Autowired
+    private UserMapper userMapper;
+
+    @Value("${com.iotechn.unimall.wx.mini.app-id}")
+    private String wxMiNiAppid;
+
+    @Value("${com.iotechn.unimall.wx.app.app-id}")
+    private String wxAppAppid;
+
+    @Override
+    public Page<OrderDO> list(Integer pageNo, Integer pageSize, Integer status, String orderNo, Long adminId) throws ServiceException {
+        Wrapper<OrderDO> wrapper = new EntityWrapper<OrderDO>();
+        wrapper.orderBy("id", false);
+        if (!StringUtils.isEmpty(orderNo)) {
+            wrapper.eq("order_no", orderNo);
+        }
+        if (status != null) {
+            wrapper.eq("status", status);
+        }
+        List<OrderDO> orderDOS = orderMapper.selectPage(new RowBounds((pageNo - 1) * pageSize, pageSize), wrapper);
+        Integer count = orderMapper.selectCount(wrapper);
+        return new Page<OrderDO>(orderDOS, pageNo, pageSize, count);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String refund(String orderNo, Integer type, Long adminId) throws ServiceException {
+        if (lockComponent.tryLock(OrderBizService.ORDER_REFUND_LOCK + orderNo, 30)) {
+            try {
+                //1.校验订单状态是否处于退款中
+                OrderDO orderDO = orderBizService.checkOrderExist(orderNo, null);
+                if (orderDO.getStatus() != OrderStatusType.REFUNDING.getCode()) {
+                    throw new AdminServiceException(ExceptionDefinition.ORDER_STATUS_NOT_SUPPORT_REFUND);
+                }
+                //2.退款处理
+                if (type == 0) {
+                    //2.1 店主拒绝退款
+                    OrderDO updateOrderDO = new OrderDO();
+                    updateOrderDO.setStatus(OrderStatusType.WAIT_CONFIRM.getCode());
+                    updateOrderDO.setGmtUpdate(new Date());
+                    orderBizService.changeOrderStatus(orderNo, OrderStatusType.REFUNDING.getCode(), updateOrderDO);
+                    return "ok";
+                } else if (type == 1) {
+                    //2.2 店主同意退款
+                    //2.2.1 先流转状态
+                    OrderDO updateOrderDO = new OrderDO();
+                    updateOrderDO.setStatus(OrderStatusType.REFUNDED.getCode());
+                    updateOrderDO.setGmtUpdate(new Date());
+                    orderBizService.changeOrderStatus(orderNo, OrderStatusType.REFUNDING.getCode(), updateOrderDO);
+                    Long userId = orderDO.getUserId();
+                    UserDO userDO = userMapper.selectById(userId);
+                    Integer loginType = userDO.getLoginType();
+                    //2.2.2 向微信支付平台发送退款请求
+                    WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
+                    wxPayRefundRequest.setAppid(loginType == UserLoginType.MP_WEIXIN.getCode() ? wxMiNiAppid : wxAppAppid);
+                    wxPayRefundRequest.setOutTradeNo(orderNo);
+                    wxPayRefundRequest.setOutRefundNo("refund_" + orderNo);
+                    wxPayRefundRequest.setTotalFee(orderDO.getPayPrice() - orderDO.getFreightPrice());
+                    wxPayRefundRequest.setRefundFee(orderDO.getPayPrice() - orderDO.getFreightPrice());
+                    WxPayRefundResult wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
+                    if (!wxPayRefundResult.getReturnCode().equals("SUCCESS")) {
+                        logger.warn("[微信退款] 失败 : " + wxPayRefundResult.getReturnMsg());
+                        throw new AdminServiceException(wxPayRefundResult.getReturnMsg(),
+                                ExceptionDefinition.THIRD_PART_SERVICE_EXCEPTION.getCode());
+                    }
+                    if (!wxPayRefundResult.getResultCode().equals("SUCCESS")) {
+                        logger.warn("[微信退款] 失败 : " + wxPayRefundResult.getReturnMsg());
+                        throw new AdminServiceException(wxPayRefundResult.getReturnMsg(),
+                                ExceptionDefinition.THIRD_PART_SERVICE_EXCEPTION.getCode());
+                    }
+                    return "ok";
+                } else {
+                    throw new AdminServiceException(ExceptionDefinition.PARAM_CHECK_FAILED);
+                }
+            } catch (ServiceException e) {
+                throw e;
+            } catch (Exception e) {
+                logger.error("[微信退款] 异常", e);
+                throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
+            } finally {
+                lockComponent.release(OrderBizService.ORDER_REFUND_LOCK + orderNo);
+            }
+        } else {
+            throw new AdminServiceException(ExceptionDefinition.SYSTEM_BUSY);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String ship(String orderNo, String shipCode, String shipNo, Long adminId) throws ServiceException {
+        orderBizService.checkOrderExist(orderNo, null);
+        OrderDO updateOrderDO = new OrderDO();
+        Date now = new Date();
+        updateOrderDO.setGmtUpdate(now);
+        updateOrderDO.setGmtShip(now);
+        updateOrderDO.setStatus(OrderStatusType.WAIT_CONFIRM.getCode());
+        if (!"NONE".equals(shipCode)) {
+            updateOrderDO.setShipCode(shipCode);
+            updateOrderDO.setShipNo(shipNo);
+        }
+        //流转订单状态
+        orderBizService.changeOrderStatus(orderNo, OrderStatusType.WAIT_STOCK.getCode(), updateOrderDO);
+        return "ok";
+    }
+
+    @Override
+    public OrderDTO detail(Long orderId, Long adminId) throws ServiceException {
+        return orderBizService.getOrderDetail(orderId, null);
+    }
+
+    @Override
+    public List<OrderDTO> queryToExcel(Long gmtStart, Long gmtEnd, Integer status, Long adminId) throws ServiceException {
+        EntityWrapper wrapper = new EntityWrapper();
+        if(gmtStart != null && gmtEnd != null){
+            if(gmtStart > gmtStart){
+                throw new AdminServiceException(ExceptionDefinition.ORDER_EXCEL_PARAM_ERROR);
+            }
+            wrapper.between("gmt_create",new Date(gmtStart) ,new Date(gmtEnd));
+        }
+        if(status != null){
+            wrapper.eq("status", status);
+        }
+        List<OrderDO> orderDOS = orderMapper.selectList(wrapper);
+        if(orderDOS == null || orderDOS.size() == 0){
+            return null;
+        }
+        List<OrderDTO> orderDTOList = new ArrayList<>();
+        for (OrderDO temp: orderDOS ) {
+            OrderDTO orderDTO = new OrderDTO();
+            BeanUtils.copyProperties(temp, orderDTO);
+            orderDTOList.add(orderDTO);
+        }
+        for (OrderDTO orderDTO:orderDTOList) {
+                List<OrderSkuDO> orderSkuDOList =  orderSkuMapper.selectList(new EntityWrapper<OrderSkuDO>().eq("order_no",orderDTO.getOrderNo() ));
+                orderDTO.setSkuList(orderSkuDOList);
+        }
+        return orderDTOList;
+    }
+}

+ 54 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/recommend/AdminRecommendService.java

@@ -0,0 +1,54 @@
+package com.iotechn.unimall.admin.api.recommend;
+
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.annotation.param.Range;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.RecommendDO;
+import com.iotechn.unimall.data.dto.RecommendDTO;
+import com.iotechn.unimall.data.model.Page;
+import org.apache.ibatis.annotations.Param;
+
+import java.rmi.ServerException;
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * Description:
+ * User: kbq
+ * Date: 2019-07-08
+ * Time: 下午3:42
+ */
+
+@HttpOpenApi(group = "admin.recommend", description = "推荐商品")
+public interface AdminRecommendService {
+
+    @HttpMethod(description = "创建", permission = "promote:recommend:create", permissionParentName = "推广管理", permissionName = "推荐管理")
+    public Boolean addRecommend(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "spuId", type = HttpParamType.COMMON, description = "商品Id") Long spuId,
+            @NotNull @HttpParam(name = "recommendType", type = HttpParamType.COMMON, description = "推荐类型") Integer recommendType) throws ServiceException;
+
+    @HttpMethod(description = "删除", permission = "promote:recommend:delete", permissionParentName = "推广管理", permissionName = "推荐管理")
+    public Boolean deleteRecommend(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "推荐id") Long id,
+            @NotNull @HttpParam(name = "recommendType", type = HttpParamType.COMMON, description = "推荐类型") Integer recommendType) throws ServiceException;
+
+    @HttpMethod(description = "查询", permission = "promote:recommend:query", permissionParentName = "推广管理", permissionName = "推荐管理")
+    public Page<RecommendDTO> queryRecommendByType(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @HttpParam(name = "recommendType", type = HttpParamType.COMMON, description = "推荐类型") Integer recommendType,
+            @Range(min = 1) @HttpParam(name = "pageNo", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer pageNo,
+            @Range(min = 1) @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页面长度", valueDef = "10") Integer pageSize) throws ServiceException;
+
+    @HttpMethod(description = "查询", permission = "promote:recommend:query", permissionParentName = "推广管理", permissionName = "推荐管理")
+    public Page<RecommendDTO> queryAllRecommend(
+            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
+            @Range(min = 1) @HttpParam(name = "pageNo", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer pageNo,
+            @Range(min = 1) @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页面长度", valueDef = "10") Integer pageSize) throws ServiceException;
+
+}

+ 99 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/recommend/AdminRecommendServiceImpl.java

@@ -0,0 +1,99 @@
+package com.iotechn.unimall.admin.api.recommend;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.iotechn.unimall.biz.service.recommend.RecommendBizService;
+import com.iotechn.unimall.core.exception.AdminServiceException;
+import com.iotechn.unimall.core.exception.ExceptionDefinition;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.component.CacheComponent;
+import com.iotechn.unimall.data.domain.RecommendDO;
+import com.iotechn.unimall.data.domain.SpuDO;
+import com.iotechn.unimall.data.dto.RecommendDTO;
+import com.iotechn.unimall.data.mapper.RecommendMapper;
+import com.iotechn.unimall.data.mapper.SpuMapper;
+import com.iotechn.unimall.data.model.Page;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * Description:
+ * User: kbq
+ * Date: 2019-07-08
+ * Time: 下午5:47
+ */
+@Service
+public class AdminRecommendServiceImpl implements AdminRecommendService {
+
+    @Autowired
+    private CacheComponent cacheComponent;
+    @Autowired
+    private RecommendMapper recommendMapper;
+    @Autowired
+    private SpuMapper spuMapper;
+    @Autowired
+    private RecommendBizService recommendBizService;
+
+    private final static String RECOMMEND_NAME = "RECOMMEND_TYPE_";
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean addRecommend(Long adminId, Long spuId, Integer recommendType) throws ServiceException {
+
+        if (!(spuMapper.selectCount(new EntityWrapper<SpuDO>().eq("id", spuId)) > 0)) {
+            throw new AdminServiceException(ExceptionDefinition.RECOMMEND_SPU_NO_HAS);
+        }
+
+        if (recommendMapper.selectCount(new EntityWrapper<RecommendDO>()
+                .eq("spu_id", spuId)
+                .eq("recommend_type", recommendType)) > 0) {
+            throw new AdminServiceException(ExceptionDefinition.RECOMMEND_ALREADY_HAS);
+        }
+        RecommendDO recommendDO = new RecommendDO(spuId, recommendType);
+        Date now = new Date();
+        recommendDO.setGmtCreate(now);
+        recommendDO.setGmtUpdate(now);
+        if (!(recommendMapper.insert(recommendDO) > 0)) {
+            throw new AdminServiceException(ExceptionDefinition.RECOMMEND_SQL_ADD_FAILED);
+        }
+        cacheComponent.delPrefixKey(RECOMMEND_NAME+recommendType);
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteRecommend(Long adminId, Long id, Integer recommendType) throws ServiceException {
+
+        Integer judgeSQL = recommendMapper.delete(new EntityWrapper<RecommendDO>()
+                .eq("id", id)
+                .eq("recommend_type",recommendType));
+
+        if(judgeSQL > 0){
+            cacheComponent.delPrefixKey(RECOMMEND_NAME + recommendType);
+            return true;
+        }
+
+        throw new AdminServiceException(ExceptionDefinition.RECOMMEND_SQL_DELETE_FAILED);
+    }
+
+    @Override
+    public Page<RecommendDTO> queryRecommendByType(Long adminId, Integer recommendType, Integer pageNo, Integer pageSize) throws ServiceException {
+        if(recommendType == null){
+            return recommendBizService.queryAllRecommend(pageNo, pageSize);
+        }
+
+        Integer count = recommendMapper.selectCount(new EntityWrapper<RecommendDO>().eq("recommend_type",recommendType));
+        List<RecommendDTO> recommendDTOList = recommendMapper.getRecommendByType(recommendType,(pageNo-1)*pageSize,pageSize);
+        Page<RecommendDTO> page = new Page<>(recommendDTOList,pageNo,pageSize,count);
+        return page;
+    }
+
+    @Override
+    public Page<RecommendDTO> queryAllRecommend(Long adminId, Integer pageNo, Integer pageSize) throws ServiceException {
+        return recommendBizService.queryAllRecommend(pageNo, pageSize);
+    }
+}

+ 14 - 18
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/role/RoleService.java

@@ -21,49 +21,45 @@ import java.util.Map;
 public interface RoleService {
 
     @HttpMethod(description = "列表", permission = "admin:role:list", permissionParentName = "系统管理", permissionName = "角色管理")
-    Page<RoleDO> list(
+    public Page<RoleDO> list(
             @HttpParam(name = "name", type = HttpParamType.COMMON, description = "搜索名称") String name,
             @HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
             @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "20") Integer limit,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
+            @HttpParam(name = "adminId", type = HttpParamType.USER_ID, description = "管理员ID") Long adminId) throws ServiceException;
 
 
     @HttpMethod(description = "添加", permission = "admin:role:create", permissionParentName = "系统管理", permissionName = "角色管理")
-    RoleDO create(
+    public RoleDO create(
             @NotNull @HttpParam(name = "role", type = HttpParamType.COMMON, description = "角色对象") RoleDO roleDO,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
+            @HttpParam(name = "adminId", type = HttpParamType.USER_ID, description = "管理员ID") Long adminId) throws ServiceException;
 
 
     @HttpMethod(description = "删除", permission = "admin:role:delete", permissionParentName = "系统管理", permissionName = "角色管理")
-    String delete(
+    public String delete(
             @NotNull @HttpParam(name = "roleId", type = HttpParamType.COMMON, description = "角色Id") Long roleId,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
+            @HttpParam(name = "adminId", type = HttpParamType.USER_ID, description = "管理员ID") Long adminId) throws ServiceException;
 
 
     @HttpMethod(description = "更新", permission = "admin:role:update", permissionParentName = "系统管理", permissionName = "角色管理")
-    RoleDO update(
+    public RoleDO update(
             @NotNull @HttpParam(name = "role", type = HttpParamType.COMMON, description = "角色对象") RoleDO roleDO,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
+            @HttpParam(name = "adminId", type = HttpParamType.USER_ID, description = "管理员ID") Long adminId) throws ServiceException;
 
 
     @HttpMethod(description = "角色授权", permission = "admin:role:permissionList",  permissionParentName = "系统管理", permissionName = "角色管理")
-    String permissionSet(
+    public String permissionSet(
             @NotNull @HttpParam(name = "roleSetPermissionDTO", type = HttpParamType.COMMON, description = "设置DTO") RoleSetPermissionDTO roleSetPermissionDTO,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
+            @HttpParam(name = "adminId", type = HttpParamType.USER_ID, description = "管理员ID") Long adminId) throws ServiceException;
 
 
     @HttpMethod(description = "权限列表", permission = "admin:permission:list", permissionParentName = "系统管理", permissionName = "角色管理")
-    Map<String,Object> permissionList(
+    public Map<String,Object> permissionList(
             @NotNull @HttpParam(name = "roleId", type = HttpParamType.COMMON, description = "角色ID") Long roleId,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
+            @HttpParam(name = "adminId", type = HttpParamType.USER_ID, description = "管理员ID") Long adminId) throws ServiceException;
 
 
     @HttpMethod(description = "角色枚举")
-    List<Map<String,Object>> options(
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
+    public List<Map<String,Object>> options(
+            @HttpParam(name = "adminId", type = HttpParamType.USER_ID, description = "管理员ID") Long adminId) throws ServiceException;
 
 }

+ 5 - 10
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/role/RoleServiceImpl.java

@@ -39,9 +39,8 @@ public class RoleServiceImpl implements RoleService {
     public static Set<String> allPermPoint = new HashSet<>();
 
     @Override
-    public Page<RoleDO> list(String name, Integer page, Integer limit, Long adminId,Long companyId) throws ServiceException {
+    public Page<RoleDO> list(String name, Integer page, Integer limit, Long adminId) throws ServiceException {
         Wrapper<RoleDO> wrapper = new EntityWrapper<RoleDO>();
-        wrapper.eq("company_id",companyId);
         if (!StringUtils.isEmpty(name)) {
             wrapper.like("name", name);
         }
@@ -51,12 +50,11 @@ public class RoleServiceImpl implements RoleService {
     }
 
     @Override
-    public RoleDO create(RoleDO roleDO, Long adminId,Long companyId) throws ServiceException {
+    public RoleDO create(RoleDO roleDO, Long adminId) throws ServiceException {
         Date now = new Date();
         roleDO.setStatus(RoleStatusType.ACTIVE.getCode());
         roleDO.setGmtUpdate(now);
         roleDO.setGmtCreate(now);
-        roleDO.setCompanyId(companyId);
         if (roleMapper.insert(roleDO) > 0) {
             return roleDO;
         }
@@ -72,8 +70,7 @@ public class RoleServiceImpl implements RoleService {
     }
 
     @Override
-    public RoleDO update(RoleDO roleDO, Long adminId,Long companyId) throws ServiceException {
-        roleDO.setCompanyId(companyId);
+    public RoleDO update(RoleDO roleDO, Long adminId) throws ServiceException {
         if (roleMapper.updateById(roleDO) > 0) {
             return roleDO;
         }
@@ -129,10 +126,8 @@ public class RoleServiceImpl implements RoleService {
     }
 
     @Override
-    public List<Map<String, Object>> options(Long adminId,Long companyId) throws ServiceException {
-        Wrapper wrapper = new EntityWrapper<>();
-        wrapper.eq("company_id",companyId);
-        List<RoleDO> roleDOS = roleMapper.selectList(wrapper);
+    public List<Map<String, Object>> options(Long adminId) throws ServiceException {
+        List<RoleDO> roleDOS = roleMapper.selectList(new EntityWrapper<>());
         List<Map<String,Object>> list = new LinkedList<>();
         roleDOS.forEach(item -> {
             Map<String,Object> map = new HashMap<>();

+ 0 - 62
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/sys/DictService.java

@@ -1,62 +0,0 @@
-package com.iotechn.unimall.admin.api.sys;
-
-import com.iotechn.unimall.core.annotation.HttpMethod;
-import com.iotechn.unimall.core.annotation.HttpOpenApi;
-import com.iotechn.unimall.core.annotation.HttpParam;
-import com.iotechn.unimall.core.annotation.HttpParamType;
-import com.iotechn.unimall.core.annotation.param.NotNull;
-import com.iotechn.unimall.core.exception.ServiceException;
-import com.iotechn.unimall.data.model.Page;
-import com.iotechn.unimall.data.domain.SysDictDataDO;
-
-import java.util.Date;
-import java.util.List;
-
-/**
- * Generate Code By Unimall
- */
-@HttpOpenApi(group = "admin.dict", description = "数据字典")
-public interface DictService {
-
-    @HttpMethod(description = "删除", permission = "dict:dict:delete", permissionParentName = "数据字典", permissionName = "删除")
-    public boolean delete(
-            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "id") Long id,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId) throws ServiceException;
-    @HttpMethod(description = "获取数据字典", permission = "dict:dict:get", permissionParentName = "数据字典", permissionName = "获取")
-    public List<SysDictDataDO> getDictDataList(
-            @NotNull @HttpParam(name = "dictType", type = HttpParamType.COMMON, description = "dictType") String dictType,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-
-
-    @HttpMethod(description = "查询", permission = "dict:dict:list", permissionParentName = "数据字典", permissionName = "查询")
-    public Page<SysDictDataDO> list(
-            @HttpParam(name = "dictName", type = HttpParamType.COMMON, description = "字典类型") String dictName,
-            @HttpParam(name = "label", type = HttpParamType.COMMON, description = "字典名称") String label,
-            @HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
-            @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "20") Integer limit,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-
-    @HttpMethod(description = "添加", permission = "dict:dict:create", permissionParentName = "数据字典", permissionName = "添加")
-    public SysDictDataDO create(
-            @NotNull @HttpParam(name = "dictName", type = HttpParamType.COMMON, description = "字典类型") String dictName,
-            @NotNull @HttpParam(name = "dictType", type = HttpParamType.COMMON, description = "字典编号") String dictType,
-            @NotNull @HttpParam(name = "label", type = HttpParamType.COMMON, description = "字典名称") String label,
-            @NotNull @HttpParam(name = "value", type = HttpParamType.COMMON, description = "字典数据") String value,
-            @HttpParam(name = "sort", type = HttpParamType.COMMON, description = "排序") Integer sort,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-
-    @HttpMethod(description = "编辑", permission = "dict:dict:edit", permissionParentName = "数据字典", permissionName = "编辑")
-    public String edit(
-            @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "主键") Long id,
-            @NotNull @HttpParam(name = "dictName", type = HttpParamType.COMMON, description = "字典类型") String dictName,
-            @NotNull @HttpParam(name = "dictType", type = HttpParamType.COMMON, description = "字典编号") String dictType,
-            @NotNull @HttpParam(name = "label", type = HttpParamType.COMMON, description = "字典名称") String label,
-            @NotNull @HttpParam(name = "value", type = HttpParamType.COMMON, description = "字典数据") String value,
-            @HttpParam(name = "sort", type = HttpParamType.COMMON, description = "排序") Integer sort,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-
-}

+ 0 - 106
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/sys/DictServiceImpl.java

@@ -1,106 +0,0 @@
-package com.iotechn.unimall.admin.api.sys;
-
-
-import cn.hutool.json.JSONUtil;
-import com.iotechn.unimall.core.exception.AdminServiceException;
-import com.iotechn.unimall.core.exception.ExceptionDefinition;
-import com.iotechn.unimall.core.exception.ServiceException;
-import com.iotechn.unimall.data.model.Page;
-import com.baomidou.mybatisplus.mapper.EntityWrapper;
-import com.baomidou.mybatisplus.mapper.Wrapper;
-import com.iotechn.unimall.data.domain.SysDictDataDO;
-import com.iotechn.unimall.data.mapper.SysDictDataMapper;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.apache.ibatis.session.RowBounds;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Generate Code By Unimall
- */
-@Service
-public class DictServiceImpl implements DictService {
-
-    @Autowired
-    private SysDictDataMapper sysDictDataMapper;
-    @Override
-    public boolean delete(Long id,  Long adminId) throws ServiceException {
-        return sysDictDataMapper.deleteById(id) > 0;
-    }
-
-    @Override
-    public List<SysDictDataDO> getDictDataList(String dictType,Long adminId,Long companyId) {
-        List<SysDictDataDO> dictDataList = new ArrayList<>();
-        Wrapper<SysDictDataDO> wrapper = new EntityWrapper<SysDictDataDO>();
-        if (dictType != null) {
-            wrapper.eq("dict_type", dictType);
-        }
-        wrapper.eq("company_id", companyId);
-//        wrapper.orderBy("sort",true);
-        wrapper.orderBy("dict_type",true);
-        wrapper.orderBy("value",true);
-        dictDataList = sysDictDataMapper.selectList(wrapper);
-        return dictDataList;
-    }
-    @Override
-    public Page<SysDictDataDO> list(String dictName, String label, Integer page, Integer limit, Long adminId,Long companyId) throws ServiceException {
-        Wrapper<SysDictDataDO> wrapper = new EntityWrapper<SysDictDataDO>();
-        if (dictName != null) {
-            wrapper.like("dict_name", dictName);
-        }
-        if (label != null) {
-            wrapper.like("label", label);
-        }
-        wrapper.orderBy("dict_type",true);
-        wrapper.orderBy("value",true);
-        wrapper.eq("company_id",companyId);
-        List<SysDictDataDO> list = sysDictDataMapper.selectPage(new RowBounds((page - 1) * limit, limit), wrapper);
-        Integer count = sysDictDataMapper.selectCount(wrapper);
-        return new Page<SysDictDataDO>(list, page, limit, count);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public SysDictDataDO create(String dictName,String dictType, String label, String value, Integer sort, Long adminId,Long companyId) throws ServiceException {
-         Date now = new Date();
-         SysDictDataDO insertDO = new SysDictDataDO();
-         insertDO.setDictName(dictName);
-         insertDO.setDictType(dictType);
-         insertDO.setLabel(label);
-         insertDO.setValue(value);
-         insertDO.setSort(sort);
-         insertDO.setCompanyId(companyId);
-         insertDO.setGmtUpdate(now);
-         insertDO.setGmtCreate(now);
-         if (sysDictDataMapper.insert(insertDO) > 0) {
-             return insertDO;
-         }
-         throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public String edit(Long id, String dictName,String dictType, String label, String value, Integer sort, Long adminId,Long companyId) throws ServiceException {
-         Date now = new Date();
-         SysDictDataDO updateDO = new SysDictDataDO();
-         updateDO.setId(id);
-         updateDO.setDictName(dictName);
-         updateDO.setDictType(dictType);
-         updateDO.setLabel(label);
-         updateDO.setValue(value);
-         updateDO.setCompanyId(companyId);
-         updateDO.setSort(sort);
-         updateDO.setGmtUpdate(now);
-         if (sysDictDataMapper.updateById(updateDO) > 0) {
-             return "ok";
-         }
-         throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-    }
-
-}

+ 0 - 39
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/tools/GeneratorService.java

@@ -1,39 +0,0 @@
-package com.iotechn.unimall.admin.api.tools;
-
-import com.iotechn.unimall.core.annotation.HttpMethod;
-import com.iotechn.unimall.core.annotation.HttpOpenApi;
-import com.iotechn.unimall.core.annotation.HttpParam;
-import com.iotechn.unimall.core.annotation.HttpParamType;
-import com.iotechn.unimall.core.annotation.param.NotNull;
-import com.iotechn.unimall.core.exception.ServiceException;
-import com.iotechn.unimall.data.dto.CodeReverseGenerateDTO;
-import com.iotechn.unimall.data.dto.CodeReverseGenerateTableDTO;
-
-import java.util.List;
-
-/**
- * Created with IntelliJ IDEA.
- * Description: 代码生成器、现在主要是逆向生成 Admin 的常用CRUD。
- * Attention: 要使用此功能,请保证unimall的项目结构不要变。否则文件将保存进错误的地址!
- * User: rize
- * Date: 2020/3/11
- * Time: 10:40
- */
-@HttpOpenApi(group = "admin.generator", description = "生成器服务")
-public interface GeneratorService {
-
-    @HttpMethod(description = "列出表")
-    List<CodeReverseGenerateTableDTO> listTable(
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
-
-    @HttpMethod(description = "加载列")
-    List<CodeReverseGenerateDTO.ColumnDefinition> loadColumns(
-            @NotNull @HttpParam(name = "tableName", type = HttpParamType.COMMON, description = "加载DB列") String tableName,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
-
-    @HttpMethod(description = "生成")
-    String generate(
-            @NotNull @HttpParam(name = "generateDTO", type = HttpParamType.COMMON, description = "生成器模型") CodeReverseGenerateDTO generateDTO,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员Id") Long adminId) throws ServiceException;
-
-}

+ 0 - 215
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/tools/GeneratorServiceImpl.java

@@ -1,215 +0,0 @@
-package com.iotechn.unimall.admin.api.tools;
-
-import com.baomidou.mybatisplus.annotations.TableName;
-import com.iotechn.unimall.core.exception.AdminServiceException;
-import com.iotechn.unimall.core.exception.ExceptionDefinition;
-import com.iotechn.unimall.core.exception.ServiceException;
-import com.iotechn.unimall.core.util.ClassScannerUtil;
-import com.iotechn.unimall.data.domain.GeneratorTableColumnDO;
-import com.iotechn.unimall.data.dto.CodeReverseGenerateDTO;
-import com.iotechn.unimall.data.dto.CodeReverseGenerateTableDTO;
-import com.iotechn.unimall.data.mapper.GeneratorMapper;
-import freemarker.cache.FileTemplateLoader;
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-import freemarker.template.TemplateException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-/**
- * Created with IntelliJ IDEA.
- * Description:
- * User: rize
- * Date: 2020/3/11
- * Time: 11:03
- */
-@Service("generatorService")
-public class GeneratorServiceImpl implements GeneratorService {
-
-    @Autowired
-    private GeneratorMapper generatorMapper;
-
-    private static  Logger logger = LoggerFactory.getLogger(GeneratorServiceImpl.class);
-
-    @Override
-    public List<CodeReverseGenerateTableDTO> listTable(Long adminId) throws ServiceException {
-        List<String> strings = generatorMapper.listTables();
-        List<CodeReverseGenerateTableDTO> tableDTOList = strings.stream().map(item -> {
-            CodeReverseGenerateTableDTO tableDTO = new CodeReverseGenerateTableDTO();
-            tableDTO.setExist(checkMapperExist(item));
-            tableDTO.setName(item);
-            return tableDTO;
-        }).collect(Collectors.toList());
-        return tableDTOList;
-    }
-
-    private boolean checkMapperExist(String tableName) {
-        Set<Class<?>> set = ClassScannerUtil.getClasses("com.iotechn.unimall.data.domain");
-        for (Class clazz : set) {
-            TableName annotation = (TableName) clazz.getDeclaredAnnotation(TableName.class);
-            if (annotation != null) {
-                String value = annotation.value();
-                if (value != null) {
-                    if (tableName.equals(value)) {
-                        return true;
-                    }
-                }
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public List<CodeReverseGenerateDTO.ColumnDefinition> loadColumns(String tableName, Long adminId) throws ServiceException {
-        List<GeneratorTableColumnDO> generatorTableColumnDOS = generatorMapper.listColumns(tableName);
-        List<CodeReverseGenerateDTO.ColumnDefinition> columnDefinitions = generatorTableColumnDOS.stream().map(item -> {
-            CodeReverseGenerateDTO.ColumnDefinition definition = new CodeReverseGenerateDTO.ColumnDefinition();
-            definition.setName(item.getField());
-            definition.setClazz(mappingJavaClass(item.getType()));
-            definition.setAlias(lineToHump(item.getField()));
-            definition.setChinese(definition.getAlias());
-            // 若字段NULL = NO。则表示不能为空。则NotNull字段该设为True
-            definition.setNotnull(item.getNull().equals("NO"));
-            definition.setMoney(false);
-            definition.setInsertColumn(false);
-            definition.setQuery(false);
-            definition.setLikeQuery(false);
-            definition.setShowInList(false);
-            definition.setNotnull(false);
-            return definition;
-        }).collect(Collectors.toList());
-        return columnDefinitions;
-    }
-
-    private String mappingJavaClass(String type) {
-        if (type.startsWith("varchar")) {
-            return String.class.getName();
-        } else if (type.startsWith("int")) {
-            return Integer.class.getName();
-        } else if (type.startsWith("bigint")) {
-            return Long.class.getName();
-        } else if (type.startsWith("date")) {
-            return Date.class.getName();
-        } else {
-            // 返回空,要求手动填写
-            return "";
-        }
-    }
-
-    private String lineToHump(String str) {
-        Pattern linePattern = Pattern.compile("_(\\w)");
-        str = str.toLowerCase();
-        Matcher matcher = linePattern.matcher(str);
-        StringBuffer sb = new StringBuffer();
-        while (matcher.find()) {
-            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
-        }
-        matcher.appendTail(sb);
-        return sb.toString();
-    }
-
-    @Override
-    public String generate(CodeReverseGenerateDTO generateDTO, Long adminId) throws ServiceException {
-        String workDirStr = System.getProperty("user.dir");
-        File workDir = new File(workDirStr);
-        if (workDir.exists()) {
-            try {
-                // 若存在,获取模板引擎。模板可以保存在内存中,也可以保存在文件或数据中
-                String templateBaseDir = workDirStr + "/unimall-admin-api/src/main/resources";
-                FileTemplateLoader fileTemplateLoader = new FileTemplateLoader(new File(templateBaseDir));
-                Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
-                configuration.setTemplateLoader(fileTemplateLoader);
-                String title = generateDTO.getTitle();
-                String[] split = title.split("\\.");
-                String packageName = split[0];
-                String serviceName = split[1];
-                String doName = lineToHump(generateDTO.getTableName().replace("unimall_", ""));
-                generateDTO.setDoLowCaseName(doName);
-                doName = doName.replaceFirst(doName.substring(0,1), doName.substring(0,1).toUpperCase());
-                generateDTO.setDoName(doName);
-                generateDTO.setPackageName(packageName);
-                generateDTO.setServiceName(serviceName);
-                generateDTO.setServiceLowCaseName(serviceName.toLowerCase());
-                Set<String> importClassNames = new HashSet<>();
-                for (CodeReverseGenerateDTO.ColumnDefinition columnDefinition : generateDTO.getColumnDefinitionList()) {
-                    if (!columnDefinition.getClazz().startsWith("java.lang")) {
-                        importClassNames.add(columnDefinition.getClazz());
-                    }
-                    String substring = columnDefinition.getClazz().substring(columnDefinition.getClazz().lastIndexOf(".") + 1);
-                    columnDefinition.setClazzName(substring);
-                }
-                generateDTO.setImportClasses(importClassNames);
-                // step1. 生成DO/Dto对象
-                Template doTemplate = configuration.getTemplate("do.ftl", "utf-8");
-                writeFile(workDirStr + "/unimall-data/src/main/java/com/iotechn/unimall/data/domain/" + doName + "DO.java", doTemplate, generateDTO);
-                Template dtoTemplate = configuration.getTemplate("dto.ftl", "utf-8");
-                writeFile(workDirStr + "/unimall-data/src/main/java/com/iotechn/unimall/data/dto/" + doName + "DTO.java", dtoTemplate, generateDTO);
-                // step2. 生成Mapper
-                Template mapperTemplate = configuration.getTemplate("mapper.ftl", "utf-8");
-                writeFile(workDirStr + "/unimall-data/src/main/java/com/iotechn/unimall/data/mapper/" + doName + "Mapper.java", mapperTemplate, generateDTO);
-                // step3. 生成Service接口
-                Template serviceTemplate = configuration.getTemplate("service.ftl", "utf-8");
-                String apiDirStr = workDirStr + "/unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/" + packageName;
-                File apiDir = new File(apiDirStr);
-                if (!apiDir.exists()) {
-                    apiDir.mkdir();
-                }
-                writeFile(workDirStr + "/unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/" + packageName + "/" + serviceName + "Service.java", serviceTemplate, generateDTO);
-                // step4. 生成Service实现
-                Template serviceImplTemplate = configuration.getTemplate("serviceImpl.ftl", "utf-8");
-                writeFile(workDirStr + "/unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/" + packageName + "/" + serviceName + "ServiceImpl.java", serviceImplTemplate, generateDTO);
-                // step5. 生成api/*.js文件
-                Template apijsTemplate = configuration.getTemplate("apijs.ftl", "utf-8");
-                writeFile(workDirStr + "/unimall-admin/src/api/" + generateDTO.getPageName() + ".js", apijsTemplate, generateDTO);
-                // step6. 生成页面
-                Template pageTemplate = configuration.getTemplate("page.ftl", "utf-8");
-                String apiDirUi = workDirStr + "/unimall-admin/src/views/" + generateDTO.getFolder();
-                File apiUi = new File(apiDirUi);
-                if (!apiUi.exists()) {
-                    apiUi.mkdir();
-                }
-                writeFile(workDirStr + "/unimall-admin/src/views/" + generateDTO.getFolder() + "/" + generateDTO.getPageName() + ".vue", pageTemplate, generateDTO);
-                return "ok";
-            } catch (IOException e) {
-                logger.error("[代码生成] IO异常", e);
-                throw new AdminServiceException(ExceptionDefinition.ADMIN_GENERATOR_IO_EXCEPTION);
-            } catch (TemplateException e) {
-                logger.error("[模板生成] 异常", e);
-                throw new AdminServiceException(ExceptionDefinition.ADMIN_GENERATOR_TEMPLATE_EXCEPTION);
-            }
-
-        } else {
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_GENERATOR_WORK_DIR_NOT_EXIST);
-        }
-    }
-
-    /**
-     * @param fileName 文件全路径
-     * @param template
-     * @param model
-     * @throws IOException
-     */
-    private void writeFile(String fileName, Template template, CodeReverseGenerateDTO model) throws IOException, ServiceException, TemplateException {
-        File file = new File(fileName);
-        if (!file.exists()) {
-            file.createNewFile();
-        } else {
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_GENERATOR_FILE_ALREADY_EXIST);
-        }
-        FileWriter fileWriter = new FileWriter(fileName);
-        template.process(model, fileWriter);
-        fileWriter.flush();
-        fileWriter.close();
-    }
-
-}

+ 74 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/tools/gen/GenTableService.java

@@ -0,0 +1,74 @@
+package com.iotechn.unimall.admin.api.tools.gen;
+
+import java.util.List;
+
+import com.alibaba.fastjson.JSONObject;
+import com.iotechn.unimall.core.annotation.HttpMethod;
+import com.iotechn.unimall.core.annotation.HttpOpenApi;
+import com.iotechn.unimall.core.annotation.HttpParam;
+import com.iotechn.unimall.core.annotation.HttpParamType;
+import com.iotechn.unimall.core.annotation.param.NotNull;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.data.domain.tools.gen.GenTable;
+import com.iotechn.unimall.data.domain.tools.gen.GenTableColumn;
+import com.iotechn.unimall.data.model.Page;
+
+/**
+ * 
+ * @author dyl
+ *
+ */
+@HttpOpenApi(group = "admin.tools.gen", description = "代码生成")
+public interface GenTableService {
+	@HttpMethod(description = "代码生成列表", permission = "admin:tools:gen:list", permissionParentName = "系统工具", permissionName = "代码生成")
+	public Page<GenTable> list(
+			@HttpParam(name = "tableName", type = HttpParamType.COMMON, description = "表名称") String tableName,
+			@HttpParam(name = "tableComment", type = HttpParamType.COMMON, description = "表描述") String tableComment,
+			@HttpParam(name = "beginTime", type = HttpParamType.COMMON, description = "开始时间") String beginTime,
+			@HttpParam(name = "endTime", type = HttpParamType.COMMON, description = "结束时间") String endTime,
+			@HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
+			@HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "20") Integer limit)
+			throws ServiceException;
+
+	@HttpMethod(description = "数据表列表", permission = "admin:tools:gen:dbList", permissionParentName = "系统工具", permissionName = "代码生成")
+	public Page<GenTable> getDbList(
+			@HttpParam(name = "tableName", type = HttpParamType.COMMON, description = "表名称") String tableName,
+			@HttpParam(name = "tableComment", type = HttpParamType.COMMON, description = "表描述") String tableComment,
+			@HttpParam(name = "page", type = HttpParamType.COMMON, description = "页码", valueDef = "1") Integer page,
+			@HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度", valueDef = "20") Integer limit)
+			throws ServiceException;
+
+	@HttpMethod(description = "查询数据表详情", permission = "admin:tools:gen:get", permissionParentName = "系统工具", permissionName = "代码生成")
+	public JSONObject get(@NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "表ID") String id)
+			throws ServiceException;
+
+	@HttpMethod(description = "查询数据表字段详情", permission = "admin:tools:genTable:getColumn", permissionParentName = "系统工具", permissionName = "代码生成")
+	public List<GenTableColumn> getColumn(
+			@HttpParam(name = "talbleId", type = HttpParamType.COMMON, description = "表ID") String talbleId)
+			throws ServiceException;
+
+	@HttpMethod(description = "导入表结构", permission = "admin:tools:gen:import", permissionParentName = "系统工具", permissionName = "代码生成")
+	public Boolean importTableSave(
+			@HttpParam(name = "tables", type = HttpParamType.COMMON, description = "表名") String tables)
+			throws ServiceException;
+
+	@HttpMethod(description = "修改表生成信息", permission = "admin:tools:gen:update", permissionParentName = "系统工具", permissionName = "代码生成")
+	public Boolean update(
+			@NotNull @HttpParam(name = "genTable", type = HttpParamType.COMMON, description = "表信息") GenTable genTable)
+			throws ServiceException;
+
+	@HttpMethod(description = "修改表字段生成信息", permission = "admin:tools:gen:updateColumn", permissionParentName = "系统工具", permissionName = "代码生成")
+	public Boolean updateColumn(
+			@NotNull @HttpParam(name = "genTableColumn", type = HttpParamType.COMMON, description = "表字段信息") GenTableColumn genTableColumn)
+			throws ServiceException;
+
+	@HttpMethod(description = "删除", permission = "admin:tools:gen:delete", permissionParentName = "系统工具", permissionName = "代码生成")
+	public Boolean delete(
+			@NotNull @HttpParam(name = "tableIds", type = HttpParamType.COMMON, description = "表Id") String tableIds)
+			throws ServiceException;
+
+	@HttpMethod(description = "代码预览", permission = "admin:tools:gen:preview", permissionParentName = "系统工具", permissionName = "代码生成")
+	public JSONObject preview(
+			@NotNull @HttpParam(name = "tableId", type = HttpParamType.COMMON, description = "表Id") String tableId)
+			throws ServiceException;
+}

+ 179 - 0
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/tools/gen/GenTableServiceImpl.java

@@ -0,0 +1,179 @@
+package com.iotechn.unimall.admin.api.tools.gen;
+
+import java.io.StringWriter;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ibatis.session.RowBounds;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.iotechn.unimall.core.exception.AdminServiceException;
+import com.iotechn.unimall.core.exception.ExceptionDefinition;
+import com.iotechn.unimall.core.exception.ServiceException;
+import com.iotechn.unimall.core.util.StringUtils;
+import com.iotechn.unimall.data.domain.tools.gen.GenTable;
+import com.iotechn.unimall.data.domain.tools.gen.GenTableColumn;
+import com.iotechn.unimall.data.mapper.tools.gen.GenTableColumnMapper;
+import com.iotechn.unimall.data.mapper.tools.gen.GenTableMapper;
+import com.iotechn.unimall.data.model.Page;
+import com.iotechn.unimall.data.util.GenUtils;
+import com.iotechn.unimall.data.util.SessionUtil;
+import com.iotechn.unimall.data.util.VelocityInitializer;
+import com.iotechn.unimall.data.util.VelocityUtils;
+
+/**
+ * 
+ * @author dyl
+ *
+ */
+@Service
+public class GenTableServiceImpl implements GenTableService {
+
+	@Autowired
+	private GenTableMapper tableMapper;
+
+	@Autowired
+	private GenTableColumnMapper tableColumnMapper;
+
+	@Override
+	public Page<GenTable> list(String tableName, String tableComment, String beginTime, String endTime, Integer page,
+			Integer limit) throws ServiceException {
+		Wrapper<GenTable> wrapper = new EntityWrapper<GenTable>();
+		if (!StringUtils.isEmpty(tableName)) {
+			wrapper.eq("table_name", tableName);
+		}
+		if (!StringUtils.isEmpty(tableComment)) {
+			wrapper.like("table_comment", tableComment);
+		}
+		if (!StringUtils.isEmpty(beginTime) && !StringUtils.isEmpty(endTime)) {
+			wrapper.between("create_time", beginTime, endTime);
+		}
+		List<GenTable> GenTableS = tableMapper.selectPage(new RowBounds((page - 1) * limit, limit), wrapper);
+		Integer count = tableMapper.selectCount(wrapper);
+		return new Page<GenTable>(GenTableS, page, limit, count);
+	}
+
+	@Override
+	public Page<GenTable> getDbList(String tableName, String tableComment, Integer page, Integer limit)
+			throws ServiceException {
+		GenTable genTable = new GenTable();
+		genTable.setTableName(tableName);
+		genTable.setTableComment(tableComment);
+		List<GenTable> GenTableS = tableMapper.selectDbTableList(new RowBounds((page - 1) * limit, limit), genTable);
+		Integer count = tableMapper.selectDbTableCount(genTable);
+		return new Page<GenTable>(GenTableS, page, limit, count);
+	}
+
+	@Override
+	public JSONObject get(String id) throws ServiceException {
+		JSONObject result = new JSONObject();
+		Wrapper<GenTableColumn> wrapper = new EntityWrapper<GenTableColumn>();
+		wrapper.eq("table_id", id);
+
+		GenTable table = tableMapper.selectById(id);
+		List<GenTableColumn> list = tableColumnMapper.selectList(wrapper);
+
+		result.put("info", table);
+		result.put("rows", list);
+		return result;
+	}
+
+	@Override
+	public List<GenTableColumn> getColumn(String talbleId) throws ServiceException {
+		Wrapper<GenTableColumn> wrapper = new EntityWrapper<GenTableColumn>();
+		wrapper.eq("table_id", talbleId);
+		List<GenTableColumn> list = tableColumnMapper.selectList(wrapper);
+		return list;
+	}
+
+	@Override
+	public Boolean importTableSave(String tables) throws ServiceException {
+		String[] ids = tables.split(",");
+		List<GenTable> tableList = tableMapper.selectDbTableListByNames(ids);
+		String operName = SessionUtil.getAdmin().getUsername();
+		for (GenTable table : tableList) {
+			try {
+				String tableName = table.getTableName();
+				GenUtils.initTable(table, operName);
+				int row = tableMapper.insert(table);
+				if (row > 0) {
+					// 保存列信息
+					List<GenTableColumn> genTableColumns = tableColumnMapper.selectDbTableColumnsByName(tableName);
+					for (GenTableColumn column : genTableColumns) {
+						GenUtils.initColumnField(column, table);
+						tableColumnMapper.insert(column);
+					}
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+				throw new AdminServiceException(ExceptionDefinition.TABLE_IMPORT_ERROR);
+			}
+		}
+		return true;
+	}
+
+	@Override
+	public Boolean update(GenTable genTable) throws ServiceException {
+		return tableMapper.updateById(genTable) > 0;
+	}
+
+	@Override
+	public Boolean updateColumn(GenTableColumn genTableColumn) throws ServiceException {
+		return tableColumnMapper.updateById(genTableColumn) > 0;
+	}
+
+	@Override
+	public Boolean delete(String tableIds) throws ServiceException {
+		String[] ids = tableIds.split(",");
+		Wrapper<GenTable> wrapper = new EntityWrapper<GenTable>();
+		wrapper.in("table_id", ids);
+		return tableMapper.delete(wrapper) > 0;
+	}
+
+	@Override
+	public JSONObject preview(String tableId) throws ServiceException {
+		Map<String, String> dataMap = new LinkedHashMap<>();
+		// 查询表信息
+		GenTable table = tableMapper.selectById(tableId);
+		Wrapper<GenTableColumn> wrapper = new EntityWrapper<GenTableColumn>();
+		wrapper.eq("table_id", table.getTableId());
+		// 查询列信息
+		List<GenTableColumn> columns =tableColumnMapper.selectList(wrapper);
+		table.setColumns(columns);
+		setPkColumn(table, columns);
+		VelocityInitializer.initVelocity();
+
+		VelocityContext context = VelocityUtils.prepareContext(table);
+
+		// 获取模板列表
+		List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
+		for (String template : templates) {
+			// 渲染模板
+			StringWriter sw = new StringWriter();
+			Template tpl = Velocity.getTemplate(template, "UTF-8");
+			tpl.merge(context, sw);
+			dataMap.put(template, sw.toString());
+		}
+		return JSONObject.parseObject(JSONObject.toJSONString(dataMap));
+	}
+
+	public void setPkColumn(GenTable table, List<GenTableColumn> columns) {
+		for (GenTableColumn column : columns) {
+			if (column.isPk()) {
+				table.setPkColumn(column);
+				break;
+			}
+		}
+		if (StringUtils.isNull(table.getPkColumn())) {
+			table.setPkColumn(columns.get(0));
+		}
+	}
+}

+ 9 - 26
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/user/AdminUserService.java

@@ -8,12 +8,8 @@ import com.iotechn.unimall.core.annotation.param.NotNull;
 import com.iotechn.unimall.core.annotation.param.Range;
 import com.iotechn.unimall.core.exception.ServiceException;
 import com.iotechn.unimall.data.domain.UserDO;
-import com.iotechn.unimall.data.dto.UserDTO;
 import com.iotechn.unimall.data.model.Page;
 
-import java.util.List;
-import java.util.Map;
-
 /**
  * Created with IntelliJ IDEA.
  * Description:
@@ -26,49 +22,36 @@ import java.util.Map;
 public interface AdminUserService {
 
     @HttpMethod(description = "创建", permission = "system:user:create", permissionParentName = "系统管理", permissionName = "用户管理")
-    Boolean addUser(
+    public Boolean addUser(
             @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
             @NotNull @HttpParam(name = "user", type = HttpParamType.COMMON, description = "用户信息") UserDO user) throws ServiceException;
 
     @HttpMethod(description = "删除", permission = "system:user:delete", permissionParentName = "系统管理", permissionName = "用户管理")
-    Boolean deleteUser(
+    public Boolean deleteUser(
             @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
             @NotNull @HttpParam(name = "id", type = HttpParamType.COMMON, description = "用户Id") Long id,
-            @HttpParam(name = "nickname", type = HttpParamType.COMMON, description = "用户Id") String nickname) throws ServiceException;
+            @NotNull @HttpParam(name = "nickname", type = HttpParamType.COMMON, description = "用户Id") String nickname) throws ServiceException;
 
     @HttpMethod(description = "修改", permission = "system:user:update", permissionParentName = "系统管理", permissionName = "用户管理")
-    Boolean updateUser(
+    public Boolean updateUser(
             @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "user", type = HttpParamType.COMMON, description = "用户信息") UserDTO user,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
+            @NotNull @HttpParam(name = "user", type = HttpParamType.COMMON, description = "用户信息") UserDO user) throws ServiceException;
 
     @HttpMethod(description = "激活冻结", permission = "system:user:update", permissionParentName = "系统管理", permissionName = "用户管理")
-    Boolean updateStatus(
+    public Boolean updateStatus(
             @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
             @NotNull @HttpParam(name = "userId", type = HttpParamType.COMMON, description = "用户信息") Long userId,
             @NotNull @HttpParam(name = "status", type = HttpParamType.COMMON, description = "用户信息") Integer status) throws ServiceException;
 
 
     @HttpMethod(description = "查询", permission = "system:user:query", permissionParentName = "系统管理", permissionName = "用户管理")
-    Page<UserDTO> getUser(
+    public Page<UserDO> getUser(
             @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
             @HttpParam(name = "id", type = HttpParamType.COMMON, description = "用户ID") Long id,
             @HttpParam(name = "nickname", type = HttpParamType.COMMON, description = "用户昵称") String nickname,
-            @HttpParam(name = "userName", type = HttpParamType.COMMON, description = "用户等级")  String userName,
+            @HttpParam(name = "level", type = HttpParamType.COMMON, description = "用户等级") Integer level,
             @HttpParam(name = "gender", type = HttpParamType.COMMON, description = "用户性别") Integer gender,
             @HttpParam(name = "status", type = HttpParamType.COMMON, description = "用户状态") Integer status,
-            @HttpParam(name = "phone", type = HttpParamType.COMMON, description = "手机号码") String phone,
             @Range(min = 1) @HttpParam(name = "pageNo", type = HttpParamType.COMMON, description = "当前页码") Integer pageNo,
-            @Range(min = 1) @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度") Integer limit,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-    @HttpMethod(description = "用户枚举")
-    List<UserDO> getUserList(
-            @HttpParam(name = "roleName", type = HttpParamType.COMMON, description = "角色名称") String roleName,
-            @NotNull @HttpParam(name = "adminId", type = HttpParamType.ADMIN_ID, description = "管理员ID") Long adminId,
-            @NotNull @HttpParam(name = "companyId", type = HttpParamType.COMPANY_ID, description = "管理员ID") Long companyId) throws ServiceException;
-
-    @HttpMethod(description = "测试")
-    void test() throws Exception;
-
-
+            @Range(min = 1) @HttpParam(name = "limit", type = HttpParamType.COMMON, description = "页码长度") Integer limit) throws ServiceException;
 }

+ 30 - 148
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/api/user/AdminUserServiceImpl.java

@@ -1,36 +1,20 @@
 package com.iotechn.unimall.admin.api.user;
 
-import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.mapper.EntityWrapper;
-import com.baomidou.mybatisplus.mapper.Wrapper;
-import com.iotechn.unimall.admin.config.WebSocket;
-import com.iotechn.unimall.biz.utils.GeTuiUtils;
-import com.iotechn.unimall.biz.utils.SendUtils;
 import com.iotechn.unimall.core.exception.AdminServiceException;
 import com.iotechn.unimall.core.exception.ExceptionDefinition;
 import com.iotechn.unimall.core.exception.ServiceException;
-import com.iotechn.unimall.core.util.MD5Util;
-import com.iotechn.unimall.data.domain.*;
-import com.iotechn.unimall.data.dto.AdminDTO;
-import com.iotechn.unimall.data.dto.UserDTO;
-import com.iotechn.unimall.data.mapper.*;
+import com.iotechn.unimall.data.domain.UserDO;
+import com.iotechn.unimall.data.mapper.UserMapper;
 import com.iotechn.unimall.data.model.Page;
 import org.apache.commons.codec.digest.Md5Crypt;
-import org.apache.ibatis.session.RowBounds;
-import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.jdbc.datasource.DataSourceTransactionManager;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.TransactionDefinition;
-import org.springframework.transaction.TransactionStatus;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
 
-import java.sql.*;
-import java.util.*;
 import java.util.Date;
+import java.util.List;
 
 /**
  * Created with IntelliJ IDEA.
@@ -42,22 +26,9 @@ import java.util.Date;
 @Service
 public class AdminUserServiceImpl implements AdminUserService {
 
-    @Autowired
-    private RoleMapper roleMapper;
     @Autowired
     private UserMapper userMapper;
-    @Autowired
-    private MessageMapper messageMapper;
-
-    @Autowired
-    DataSourceTransactionManager dataSourceTransactionManager;
-    @Autowired
-    TransactionDefinition transactionDefinition;
-    @Autowired
-    private SendUtils sendUtils;
 
-    WebSocket webSocket = new WebSocket();
-    GeTuiUtils geTuiUtils = new GeTuiUtils();
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean addUser(Long adminId, UserDO user) throws ServiceException {
@@ -81,61 +52,33 @@ public class AdminUserServiceImpl implements AdminUserService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean deleteUser(Long adminId, Long id, String nickname) throws ServiceException {
-        if(StringUtils.isEmpty(nickname)){
-            return userMapper.delete(new EntityWrapper<UserDO>()
-                    .eq("id", id)) > 0;
-        }
         return userMapper.delete(new EntityWrapper<UserDO>()
                 .eq("id", id)
                 .eq("nickname",nickname)) > 0;
     }
 
     @Override
-    public Boolean updateUser(Long adminId, UserDTO user,Long companyId) throws ServiceException {
-        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
-        try{
-            if (user == null || user.getId() == null){
-                throw new AdminServiceException(ExceptionDefinition.USER_INFORMATION_MISSING);
-            }
-            if(user.getPhone() == null){
-                throw new AdminServiceException(ExceptionDefinition.USER_INFORMATION_MISSING);
-            }
-            if(userMapper.selectCount(new EntityWrapper<UserDO>().eq("phone",user.getPhone()).notIn("id",user.getId())) > 0){
-                throw new AdminServiceException(ExceptionDefinition.USER_PHONE_ALREADY_EXIST);
-            }
-            Date now = new Date();
-            user.setGmtUpdate(now);
-
-            if(user.getPassword() != null) {
-                user.setPassword(Md5Crypt.md5Crypt(user.getPassword().getBytes(), "$1$" + user.getPhone().substring(0, 7)));
-            }
-            UserDO userDO = userMapper.selectById(user.getId());
-            BeanUtils.copyProperties(user,userDO);
-            Wrapper wrapper = new EntityWrapper();
-            wrapper.eq("user_id", user.getId());
-            dataSourceTransactionManager.commit(transactionStatus);
-
-            userDO.setGmtUpdate(new Date());
-            UserDO userDOExist = userMapper.selectById(user.getId());
-            if (!StringUtils.isEmpty(userDO.getPassword()) && !StringUtils.isEmpty(userDOExist.getUserName())) {
-                userDO.setPassword(MD5Util.md5(userDO.getPassword(), userDOExist.getUserName()));
-            }
-            userDO.setUserName(user.getUserName());
-            userDO.setCompanyId(companyId);
-            if (userMapper.updateById(userDO) > 0) {
-                return true;
-            }
-            else{
-                dataSourceTransactionManager.rollback(transactionStatus);
-                throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
-            }
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updateUser(Long adminId, UserDO user) throws ServiceException {
+        if (user == null || user.getId() == null){
+            throw new AdminServiceException(ExceptionDefinition.USER_INFORMATION_MISSING);
         }
-        catch (Exception e){
-            //手动回滚事务
-            dataSourceTransactionManager.rollback(transactionStatus);
-            throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
+        if(user.getPhone() == null){
+            throw new AdminServiceException(ExceptionDefinition.USER_INFORMATION_MISSING);
         }
-
+        if(userMapper.selectCount(new EntityWrapper<UserDO>().eq("phone",user.getPhone()).notIn("id",user.getId())) > 0){
+            throw new AdminServiceException(ExceptionDefinition.USER_PHONE_ALREADY_EXIST);
+        }
+        Date now = new Date();
+        user.setGmtUpdate(now);
+        UserDO userDO  = userMapper.selectById(user.getId());
+        if(userDO.getPassword().equals(user.getPassword())){
+            return userMapper.updateById(user) > 0;
+        }
+        if(user.getPassword() != null) {
+            user.setPassword(Md5Crypt.md5Crypt(user.getPassword().getBytes(), "$1$" + user.getPhone().substring(0, 7)));
+        }
+        return userMapper.updateById(user) > 0;
     }
 
     @Override
@@ -147,78 +90,17 @@ public class AdminUserServiceImpl implements AdminUserService {
         userDO.setId(userId);
         userDO.setStatus(status);
         userDO.setGmtUpdate(new Date());
-        return userMapper.updateById(userDO) > 0;
-    }
-
-    @Override
-    public Page<UserDTO> getUser(Long adminId, Long id, String nickname, String userName, Integer gender,Integer status,String phone,Integer pageNo,Integer limit,Long companyId) throws ServiceException {
-        Wrapper wrapper = new EntityWrapper();
-
-        if (userName != null) {
-            wrapper.like("user_name", userName);
-        }
-        if (nickname != null) {
-            wrapper.like("nickname", nickname);
-        }
-        if (phone != null) {
-            wrapper.like("phone", phone);
-        }
-        wrapper.eq("company_id",companyId);
-        wrapper.orNew();
-        wrapper.isNull("company_id");
-        if (userName != null) {
-            wrapper.like("user_name", userName);
-        }
-        if (nickname != null) {
-            wrapper.like("nickname", nickname);
-        }
-        if (phone != null) {
-            wrapper.like("phone", phone);
-        }
-        wrapper.orderBy("user_name",false);
-        Integer count = userMapper.selectCount(wrapper);
-        List<UserDO> userDOList = userMapper.selectPage(new RowBounds((pageNo - 1) * limit, limit), wrapper);
-
-        List<UserDTO> userDTOS = new ArrayList<>();
-        for (UserDO userDO : userDOList) {
-            UserDTO userDTO = new UserDTO();
-            BeanUtils.copyProperties(userDO, userDTO);
-            userDTO.setPassword(null);
-
-            userDTOS.add(userDTO);
-        }
-        return new Page<UserDTO>(userDTOS, pageNo, limit, count);
-    }
-
-    @Override
-    public List<UserDO> getUserList(String role, Long adminId,Long companyId) throws ServiceException {
-        Wrapper wrapper = new EntityWrapper<>();
-        wrapper.like("name",role);
-        wrapper.eq("company_id",companyId);
-        List<RoleDO> list = roleMapper.selectList(wrapper);
-        Long roleId = 0l;
-        if(list.size() >0){
-            roleId = list.get(0).getId();
+        if(userMapper.updateById(userDO) > 0){
+            return true;
         }
-        wrapper = new EntityWrapper<>();
-        wrapper.like("role_ids",roleId+"");
-        wrapper.eq("status", "1");
-        wrapper.isNotNull("user_name");
-        List<UserDO> userDOList = userMapper.selectList(wrapper);
-
-        return userDOList;
+        return false;
     }
 
-
-
     @Override
-    public void test() throws Exception {
-        String title="中秋快乐123";
-        String content="国庆快乐123";
-//        UserDO userDO = userMapper.selectById(21);
-        geTuiUtils.pushByCid(title,content,21l);
-//        geTuiUtils.pushToAll(title,content,"");
+    public Page<UserDO> getUser(Long adminId, Long id, String nickname, Integer level, Integer gender, Integer status,Integer pageNo,Integer limit) throws ServiceException {
+        Integer count = userMapper. countUser(id,nickname,level,gender,status);
+        List<UserDO> userDOList = userMapper.getUserList(id,nickname,level,gender,status,limit*(pageNo-1),limit);
+        Page<UserDO> page = new Page<UserDO>(userDOList,pageNo,limit,count);
+        return page;
     }
-
-
 }

+ 0 - 127
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/config/SendWxMsg.java

@@ -1,127 +0,0 @@
-package com.iotechn.unimall.admin.config;
-
-import com.alibaba.fastjson.JSONObject;
-import com.iotechn.unimall.biz.service.user.UserBizService;
-import com.iotechn.unimall.data.domain.UserDO;
-import com.iotechn.unimall.data.mapper.AdminMapper;
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-public class SendWxMsg {
-    private static Logger logger = LoggerFactory.getLogger(SendWxMsg.class);
-
-    /**
-     * 办公流程审核通知
-     * @param sender
-     * @param userDO
-     * @param accessToken
-     */
-    public static void sendSubscribeMessageSH(String sender, UserDO userDO,String accessToken){
-        try{
-            OkHttpClient okHttpClient = new OkHttpClient();
-            MediaType mediaType = MediaType.parse("application/json");
-            JSONObject param = new JSONObject();
-            JSONObject data = new JSONObject();
-            JSONObject thing1 = new JSONObject();
-            JSONObject name2 = new JSONObject();
-            JSONObject name3 = new JSONObject();
-            JSONObject date5 = new JSONObject();
-            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-
-            thing1.put("value","审核任务");
-            name2.put("value",sender);
-            name3.put("value",userDO.getUserName());
-            date5.put("value",sdf.format(new Date()));
-            data.put("thing1",thing1);
-            data.put("name2",name2);
-            data.put("name3",name3);
-            data.put("date5",date5);
-            param.put("touser", userDO.getOpenId());
-            param.put("template_id", "xL_uZEqJz4QP1FbnlzQWAiO2zVBn3Qeu8JwLVOU3hU0");
-            param.put("data", data);
-            param.put("page","pages/user/task");
-            RequestBody body = RequestBody.create(mediaType, param.toJSONString());
-            Request request = new Request.Builder()
-                    .url("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken)
-                    .post(body)
-                    .addHeader("Content-Type", "application/json")
-                    .build();
-            JSONObject jsonObject = JSONObject.parseObject(okHttpClient.newCall(request).execute().body().string());
-            Integer errcode = jsonObject.getInteger("errcode");
-            if (errcode == null || errcode == 0) {
-                logger.info("[审核任务] 已成功向用户:"+userDO.getPhone()+" 发送订阅消息");
-            }
-            else{
-                logger.info("[审核任务] 订阅消息发送失败 :errcode = "+errcode);
-            }
-        }
-        catch (Exception e){
-            logger.error("sendSubscribeMessageSH exception"+e.getMessage());
-        }
-    }
-
-    /**
-     * 审核结果通知
-     * @param goodsName
-     * @param sender
-     * @param type
-     * @param userDO
-     * @param accessToken
-     */
-    public static void sendSubscribeMessageTZ(String goodsName,String sender,String type, UserDO userDO, String accessToken){
-        try{
-            OkHttpClient okHttpClient = new OkHttpClient();
-            MediaType mediaType = MediaType.parse("application/json");
-            JSONObject param = new JSONObject();
-            JSONObject data = new JSONObject();
-            JSONObject phrase2 = new JSONObject();
-            JSONObject date4 = new JSONObject();
-            JSONObject thing3 = new JSONObject();
-            JSONObject thing9 = new JSONObject();
-            JSONObject thing13 = new JSONObject();
-            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-
-            phrase2.put("value","已通过");
-            date4.put("value",sdf.format(new Date()));
-            thing3.put("value",goodsName);
-            thing9.put("value",type);
-            thing13.put("value",sender);
-            data.put("phrase2",phrase2);
-            data.put("date4",date4);
-            data.put("thing3",thing3);
-            data.put("thing9",thing9);
-            data.put("thing13",thing13);
-            param.put("touser", userDO.getOpenId());
-            param.put("template_id", "8cVkckXi_8zfHeScXRHhjN6cgZFYYCWIMPDTiPWagXY");
-            param.put("data", data);
-            param.put("page","pages/user/task");
-
-            RequestBody body = RequestBody.create(mediaType, param.toJSONString());
-            Request request = new Request.Builder()
-                    .url("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken)
-                    .post(body)
-                    .addHeader("Content-Type", "application/json")
-                    .build();
-            JSONObject jsonObject = JSONObject.parseObject(okHttpClient.newCall(request).execute().body().string());
-            Integer errcode = jsonObject.getInteger("errcode");
-            if (errcode == null || errcode == 0) {
-                logger.info("[审核"+type+"信息] 已成功向用户:"+userDO.getPhone()+" 发送订阅消息");
-            }
-            else{
-                logger.info("[审核"+type+"信息] 订阅消息发送失败 :errcode = "+errcode);
-            }
-        }
-        catch (Exception e){
-            logger.error("sendSubscribeMessageSH exception"+e.getMessage());
-        }
-    }
-
-}

+ 0 - 131
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/config/WebSocket.java

@@ -1,131 +0,0 @@
-package com.iotechn.unimall.admin.config;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-import javax.websocket.OnClose;
-import javax.websocket.OnMessage;
-import javax.websocket.OnOpen;
-import javax.websocket.Session;
-import javax.websocket.server.PathParam;
-import javax.websocket.server.ServerEndpoint;
-
-import com.baomidou.mybatisplus.mapper.EntityWrapper;
-import com.iotechn.unimall.core.Const;
-import com.iotechn.unimall.data.domain.AdminDO;
-import com.iotechn.unimall.data.domain.MessageDO;
-import com.iotechn.unimall.data.domain.RoleDO;
-import com.iotechn.unimall.data.mapper.AdminMapper;
-import com.iotechn.unimall.data.mapper.RoleMapper;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.stereotype.Component;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
-@Component
-@ServerEndpoint("/websocket/{adminId}")
-@Service
-//此注解相当于设置访问URL
-public class WebSocket {
-
-    private Session session;
-    private static CopyOnWriteArraySet<WebSocket> webSockets =new CopyOnWriteArraySet<>();
-    private static Map<String,Session> sessionPool = new HashMap<String,Session>();
-
-    private static RoleMapper  roleMapper;
-    private static AdminMapper  adminMapper;
-
-    @Autowired
-    public void setRoleService(RoleMapper  roleMapper) {
-        WebSocket.roleMapper= roleMapper;
-    }
-
-    @Autowired
-    public void setAdminService(AdminMapper  adminMapper) {
-        WebSocket.adminMapper= adminMapper;
-    }
-
-    @OnOpen
-    public void onOpen(Session session, @PathParam(value="adminId")String adminId) {
-        this.session = session;
-        webSockets.add(this);
-        sessionPool.put(adminId, session);
-        System.out.println("adminId = "+adminId+"【websocket消息】有新的连接,总数为:"+webSockets.size());
-    }
-
-    @OnClose
-    public void onClose() {
-        webSockets.remove(this);
-        System.out.println("【websocket消息】连接断开,总数为:"+webSockets.size());
-    }
-
-    @OnMessage
-    public void onMessage(String message) {
-        System.out.println("【websocket消息】收到客户端消息:"+message);
-    }
-
-    // 此为广播消息
-    public void sendAllMessage(MessageDO messageDO) {
-        for(WebSocket webSocket : webSockets) {
-            System.out.println("【websocket消息】广播消息:"+messageDO.getCustomer()+messageDO.getOperation()+messageDO.getResult()+"$"+messageDO.getPath());
-            try {
-                webSocket.session.getAsyncRemote().sendText(messageDO.getCustomer()+messageDO.getOperation()+messageDO.getResult()+"$"+messageDO.getPath());
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    // 此为单点消息
-    public void sendOneMessage(MessageDO messageDO) {
-//        sendAllMessage(messageDO);
-        System.out.println("【websocket消息 : "+messageDO.getAdminId()+"】单点消息:"+messageDO.getCustomer()+messageDO.getOperation()+messageDO.getResult()+"$"+messageDO.getPath());
-        Session session = sessionPool.get(messageDO.getAdminId()+"");
-        if (session != null) {
-            try {
-//                session.getAsyncRemote().sendObject(messageDO);
-//                session.getBasicRemote().sendObject(messageDO);
-                session.getAsyncRemote().sendText(messageDO.getCustomer()+messageDO.getOperation()+messageDO.getResult()+"$"+messageDO.getPath());
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-        else{
-            System.out.println("【websocket消息 session is null ");
-        }
-    }
-
-    // 根据角色发送消息
-    public  void sendMessageByRole(MessageDO messageDO ,String role ,Long companyId){
-        // 根据role 获取roleId
-        List<RoleDO> roleDOs = roleMapper.selectList(new EntityWrapper<RoleDO>().like("name","%"+role+"%").eq("company_id",companyId));
-        if(!CollectionUtils.isEmpty(roleDOs)){
-            RoleDO roleDO = roleDOs.get(0);
-            // 根据roleID  查询adminid
-            List<AdminDO> adminDOList = adminMapper.selectList(new EntityWrapper<AdminDO>().eq("company_id",companyId).like("role_ids","%"+roleDO.getId()+"%"));
-            if(!CollectionUtils.isEmpty(adminDOList)){
-                adminDOList.forEach(adminDO -> {
-                    System.out.println("【websocket消息 : "+adminDO.getId()+"】单点消息:"+messageDO.getCustomer()+messageDO.getOperation()+messageDO.getResult()+"$"+messageDO.getPath());
-                    Session session = sessionPool.get(adminDO.getId()+"");
-                    if (session != null) {
-                        try {
-                            session.getAsyncRemote().sendText(messageDO.getCustomer()+messageDO.getOperation()+messageDO.getResult()+"$"+messageDO.getPath());
-                        } catch (Exception e) {
-                            e.printStackTrace();
-                        }
-                    }
-                    else{
-                        System.out.println("【websocket消息 session is null ");
-                    }
-                });
-
-
-            }
-        }
-    }
-
-}

+ 0 - 18
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/config/WebSocketConfig.java

@@ -1,18 +0,0 @@
-package com.iotechn.unimall.admin.config;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.socket.server.standard.ServerEndpointExporter;
-
-@Configuration
-public class WebSocketConfig {
-    /**
-     * 注入ServerEndpointExporter,
-     * 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
-     */
-    @Bean
-    public ServerEndpointExporter serverEndpointExporter() {
-        return new ServerEndpointExporter();
-    }
-
-}

+ 0 - 548
unimall-admin-api/src/main/java/com/iotechn/unimall/admin/utils/DateUtils.java

@@ -1,548 +0,0 @@
-package com.iotechn.unimall.admin.utils;
-
-import org.apache.commons.lang3.StringUtils;
-import freemarker.core.ParseException;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Locale;
-
-public class DateUtils {
-
-
-    /**
-     * 格式化日期对象
-     */
-    private static SimpleDateFormat format;
-
-    /**
-     * 日期格式【yyyyMMddHHmmssSSS】
-     */
-    public static final String PATTERN_YYYY_MM_DD_HH_MM_SS_SSS = "yyyyMMddHHmmssSSS";
-    /**
-     * 日期格式【yyyyMMddHHmmss】
-     */
-    public static final String PATTERN_YYYY_MM_DD_HH_MM_SS = "yyyyMMddHHmmss";
-    /**
-     * 日期格式【yyMMdd】
-     */
-    public static final String PATTERN_YY_MM_DD = "yyMMdd";
-
-    /**
-     * 日期格式: yyyy
-     */
-    public static final String DATE_FMT_YYYY = "yyyy";
-
-    /**
-     * 日期格式: MM
-     */
-    public static final String DATE_FMT_MM = "MM";
-
-    /**
-     * 日期格式: yyyyMM
-     */
-    public static final String DATE_FMT_YYYYMM_NS = "yyyyMM";
-
-    /**
-     * 日期格式: yyyy/MM/dd
-     */
-    public static final String DATE_FMT_YYYYMMDD = "yyyy/MM/dd";
-    /**
-     * 日期格式: dd/MM/yyyy
-     */
-    public static final String DATE_FMT_DDMMYYYY = "dd/MM/yyyy";
-
-    /**
-     * 日期格式: yyyyMMdd
-     */
-    public static final String DATE_FMT_YYYYMMDD_NS = "yyyyMMdd";
-
-    /**
-     * 日期格式: yyyy/MM/dd HH:mm:ss
-     */
-    public static final String DATE_FMT_YYYYMMDDHHMMSS = "yyyy/MM/dd HH:mm:ss";
-
-    /**
-     * 日期格式:yyyy-MM-dd
-     */
-    public static final String DATE_FMT_YYYY_MM_DD = "yyyy-MM-dd";
-    /**
-     * 日期格式:yyyy.MM.dd
-     */
-    public static final String DATE_FMT_YYYY_MM_DD_DD = "yyyy.MM.dd";
-
-    /**
-     * 日期格式:yyyy-MM
-     */
-    public static final String DATE_FMT_YYYY_MM = "yyyy-MM";
-
-    /**
-     * 日期格式:yyyy年MM月dd日
-     */
-    public static final String DATE_FMT_YYYY_MM_DD2 = "yyyy年MM月dd日";
-
-    /**
-     * 日期格式:yyyy年MM月dd日hh时
-     */
-    public static final String DATE_FMT_YYYY_MM_DD_HH = "yyyy年MM月dd日HH时";
-
-    /**
-     * 时间格式:HH:mm
-     */
-    public static final String TIME_HH_MM = "HH:mm";
-    /**
-     * 时间格式:HHmm
-     */
-    public static final String TIME_HHMM = "HHmm";
-    /**
-     * 日期时间格式:yyyy-MM-dd HH:mm
-     */
-    public static final String DATE_FMT_YYYYMMDDHH_MM = "yyyy-MM-dd HH:mm";
-    /**
-     * 日期时间格式:yyyy-MM-dd HH:mm:ss
-     */
-    public static final String DATE_FMT_YYYYMMDDHH_MM_SS = "yyyy-MM-dd HH:mm:ss";
-    /**
-     * 日期时间格式:yyyy-MM-dd HH:mm
-     */
-    public static final String DATE_FMT_YYYYMMDDHHMM = "yyyy/MM/dd HHmm";
-    /**
-     * 日期时间格式:yyyyMMddHHmm
-     */
-    public static final String DATE_FMT_DATETIME = "yyyyMMddHHmm";
-    /**
-     * 日期时间格式: HH:mm:ss
-     */
-    public static final String DATE_FMT_HH_MM_SS = "HH:mm:ss";
-    /**
-     * 日期时间格式:dd-MM-yy
-     */
-    public static final String DATE_FMT_DDMMYY1 = "dd-MM-yy";
-
-    /**
-     * 取得日期字符串
-     *
-     * @param date    日期
-     * @param pattern 日期格式
-     * @return String 日期字符串
-     */
-    public static String formatDate(Date date, String pattern) {
-        if (date == null) {
-            return "";
-        }
-        format = new SimpleDateFormat();
-        format.applyPattern(pattern);
-        return format.format(date);
-    }
-
-    /**
-     * 向前或是向后滚动年
-     *
-     * @return Date 日期
-     */
-    public static Date rollYear(Date date, int rollCount) {
-        Calendar ca = Calendar.getInstance();
-        ca.setTime(date);
-        ca.roll(Calendar.YEAR, rollCount);
-        return ca.getTime();
-    }
-
-
-    /**
-     * 向前或者向后滚动月份 正数像前滚 负数向后滚
-     *
-     * @param date      准备滚动的日期
-     * @param rollCount 滚动参数
-     * @return Date 滚动之后的日期
-     * @author gdc
-     */
-    public static Date rollMonth(Date date, int rollCount) {
-        Calendar ca = Calendar.getInstance();
-        ca.setTime(date);
-        ca.add(Calendar.MONTH, rollCount);
-        return ca.getTime();
-    }
-
-    /**
-     * 向前或者向后滚动天 正数像前滚 负数向后滚
-     *
-     * @param date      准备滚动的日期
-     * @param rollCount 滚动参数
-     * @return Date 滚动之后的日期
-     * @author gdc
-     */
-    public static Date rollDay(Date date, int rollCount) {
-        Calendar ca = Calendar.getInstance();
-        ca.setTime(date);
-        ca.add(Calendar.DATE, rollCount);
-        return ca.getTime();
-    }
-
-    /**
-     * 时间滚动 正数像前滚 负数向后滚
-     *
-     * @param date      准备滚动的日期
-     * @param calendar  滚动系数 年 Calendar.YEAR; 月 Calendar.MONTH; 日 Calendar.DATE; 时
-     *                  Calendar.HOUR; 钟Calendar.MINUTE;
-     * @param rollCount 滚动参数
-     * @return Date 滚动之后的日期
-     * @author gdc
-     */
-    public static Date rollDate(Date date, int calendar, int rollCount) {
-
-        Calendar ca = Calendar.getInstance();
-        ca.setTime(date);
-        ca.add(calendar, rollCount);
-        return ca.getTime();
-    }
-
-    /**
-     * 取得去年的今天
-     *
-     * @return String 去年的今天
-     */
-    public static Date getLastYearOfToday() {
-        return rollYear(new Date(), -1);
-    }
-
-
-    /**
-     * 取得当前年
-     *
-     * @return String 年的字符型值
-     */
-    public static String getYear() {
-        return formatDate(new Date(), DATE_FMT_YYYY);
-    }
-
-    /**
-     * 取得去年
-     *
-     * @return String 去年的字符型值
-     */
-    public static String getLastYear() {
-        return formatDate(getLastYearOfToday(), DATE_FMT_YYYY);
-    }
-
-    /**
-     * 取得当前年月日
-     *
-     * @return String 年月日的字符型值
-     */
-    public static String getYearMonthDay() {
-        return formatDate(new Date(), DATE_FMT_YYYY_MM_DD);
-    }
-
-    /**
-     * 取得去年月日
-     *
-     * @return String 去年月日的字符型值
-     */
-    public static String getLastYearMonthDay() {
-        return formatDate(getLastYearOfToday(), DATE_FMT_YYYY_MM_DD);
-    }
-
-    /**
-     * 判断是否是指定日期格式字符串
-     *
-     * @param strDate
-     * @param dateFormat
-     * @return
-     * @author gdc
-     */
-    public static boolean isDate(String strDate, String dateFormat) {
-        SimpleDateFormat df = new SimpleDateFormat(dateFormat);
-        try {
-            Date tmpDate = df.parse(strDate);
-            String strTempDate = df.format(tmpDate);
-            if (!strTempDate.equals(strDate)) {
-                return false;
-            }
-        } catch (Exception e) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * 判断两日期年份月份..是否相同
-     *
-     * @param d1
-     * @param d2
-     * @param dateFmt
-     * @return
-     */
-    public static boolean sameDate(Date d1, Date d2, String dateFmt) {
-        SimpleDateFormat fmt = new SimpleDateFormat(dateFmt);
-        //fmt.setTimeZone(new TimeZone()); // 如果需要设置时间区域,可以在这里设置
-        return fmt.format(d1).equals(fmt.format(d2));
-    }
-
-    /**
-     * 取得月份的第一天
-     *
-     * @param yearMonth 年月yyyy-MM
-     * @return Date
-     */
-    public static Date getMonthFirstDay(String yearMonth) {
-        String[] arr = yearMonth.split("-");
-
-        Calendar cal = Calendar.getInstance();
-        cal.set(Calendar.YEAR, Integer.parseInt(arr[0]));
-        cal.set(Calendar.MONTH, Integer.parseInt(arr[1]));
-        cal.set(Calendar.DAY_OF_MONTH, 1);
-        cal.add(Calendar.DAY_OF_MONTH, -1);
-
-        cal.set(Calendar.DAY_OF_MONTH, 1);
-
-        cal.set(Calendar.HOUR_OF_DAY, 0);
-        cal.set(Calendar.MINUTE, 0);
-        cal.set(Calendar.SECOND, 0);
-        cal.set(Calendar.MILLISECOND, 0);
-        return cal.getTime();
-    }
-
-    /**
-     * 取得月份的最后一天
-     *
-     * @param yearMonth 年月yyyy-MM
-     * @return Date
-     */
-    public static Date getMonthLastDay(String yearMonth) {
-        String[] arr = yearMonth.split("-");
-
-        Calendar cal = Calendar.getInstance();
-        cal.set(Calendar.YEAR, Integer.parseInt(arr[0]));
-        cal.set(Calendar.MONTH, Integer.parseInt(arr[1]));
-        cal.set(Calendar.DAY_OF_MONTH, 1);
-        cal.add(Calendar.DAY_OF_MONTH, -1);
-
-        cal.set(Calendar.HOUR_OF_DAY, 0);
-        cal.set(Calendar.MINUTE, 0);
-        cal.set(Calendar.SECOND, 0);
-        cal.set(Calendar.MILLISECOND, 0);
-
-        return cal.getTime();
-    }
-
-    /**
-     * 取得昨天
-     *
-     * @param nowDate
-     * @return
-     * @author gdc
-     */
-    public static String getYesToday(Date nowDate) {
-        Calendar calendar = new GregorianCalendar();
-        calendar.setTime(nowDate);
-        calendar.add(Calendar.DATE, -1);
-        return new SimpleDateFormat(DATE_FMT_YYYY_MM_DD).format(calendar.getTime());
-
-    }
-
-    /**
-     * 通过出生时间计算年龄
-     *
-     * @param birthday
-     * @return
-     */
-    public static int getAgeByBirth(Date birthday) {
-        int age = 0;
-        try {
-            Calendar now = Calendar.getInstance();
-            now.setTime(new Date());// 当前时间
-
-            Calendar birth = Calendar.getInstance();
-            birth.setTime(birthday);
-
-            if (birth.after(now)) {//如果传入的时间,在当前时间的后面,返回0岁
-                age = 0;
-            } else {
-                age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR);
-                if (now.get(Calendar.DAY_OF_YEAR) > birth.get(Calendar.DAY_OF_YEAR)) {
-                    age += 1;
-                }
-            }
-            return age;
-        } catch (Exception e) {//兼容性更强,异常后返回数据
-            return 0;
-        }
-    }
-
-    /**
-     * 日期时间格式:dd-MMM-yyyy
-     */
-    public static final String DATE_FMT_DDMMMYYYY = "dd-MMM-yyyy";
-    /**
-     * 日期时间格式:dd-MMM-yyyy
-     */
-    public static final String DATE_FMT_MMMYYYY = "MMM-yyyy";
-
-    /**
-     * 日期时间格式:dd-MM-yyyy
-     */
-    public static final String DATE_FMT_DDMMYYYY2 = "dd-MM-yyyy";
-    /**
-     * 日期时间格式:dd-MMM-yy
-     */
-    public static final String DATE_FMT_DDMMMYY2 = "dd-MMM-yy";
-
-    // 一天的毫秒数 60*60*1000*24
-    private final static long DAY_MILLIS = 86400000;
-
-    // 一小时的毫秒数 60*60*1000
-    private final static long HOUR_MILLIS = 3600000;
-
-    // 一分钟的毫秒数 60*1000
-    private final static long MINUTE_MILLIS = 60000;
-
-    /**
-     * 取得日期字符串(英文格式)
-     *
-     * @param date    日期
-     * @param pattern 日期格式
-     * @return String 日期字符串
-     */
-    public static String formatDateEn(Date date, String pattern) {
-        if (date == null) {
-            return "";
-        }
-        // 日期字符串格式化
-        SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.ENGLISH);
-        return sdf.format(date);
-    }
-
-    /**
-     * 取得日期字符串
-     *
-     * @param date    日期
-     * @param pattern 日期格式
-     * @return String 日期字符串
-     */
-    public static String formatStringDate(String date, String pattern) {
-
-        if (date == null) {
-            return "";
-        }
-        DateFormat format1 = new SimpleDateFormat(pattern);
-        Date dateFormat = null;
-        try {
-            dateFormat = format1.parse(date);
-            format = new SimpleDateFormat();
-            format.applyPattern(pattern);
-        } catch (Exception e) {
-            return "";
-        }
-        return format.format(dateFormat);
-    }
-
-    /**
-     * 取得当前日期上个月下个月
-     * 上一个月 -1
-     * 下一个月 1
-     *
-     * @param nowDate
-     * @return
-     */
-    public static Date getOtherMonth(Date nowDate, int number) {
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTime(nowDate); // 设置为当前时间
-        calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) + number);
-        return calendar.getTime();
-    }
-
-    /**
-     * 计算两个日期之间相差的天数
-     *
-     * @param smdate 较小的时间
-     * @param bdate  较大的时间
-     * @return 相差小时数
-     * @throws ParseException
-     */
-    public static long timesBetween(Date smdate, Date bdate, String timeType) {
-
-        long startL = smdate.getTime();
-        long endL = bdate.getTime();
-
-        if (timeType.equals("DAY")) {
-            return (endL - startL) / DAY_MILLIS;
-        } else if (timeType.equals("HOUR")) {
-            return (endL - startL) / HOUR_MILLIS;
-        } else if (timeType.equals("MINUTE")) {
-            return (endL - startL) / MINUTE_MILLIS;
-        } else {
-            return (endL - startL);
-        }
-
-    }
-
-
-    /**
-     * 判断时间是上午还是下午
-     * true 下午
-     * false 上午
-     *
-     * @param date
-     * @return
-     */
-    public static boolean greGorian(Date date) {
-        boolean greGorianFlag = true;
-        SimpleDateFormat df = new SimpleDateFormat("HH");
-        String str = df.format(date);
-        int a = Integer.parseInt(str);
-
-        if (a < 12) {
-            greGorianFlag = true;
-        }
-        if (a >= 12) {
-            greGorianFlag = false;
-        }
-        return greGorianFlag;
-    }
-
-    /**
-     * 获取当前月第一天
-     *
-     * @return
-     */
-    public static Date getMonthFirstDay() {
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTime(new Date());
-        calendar.set(Calendar.DAY_OF_MONTH, 1);
-        calendar.add(Calendar.MONTH, 0);
-        return calendar.getTime();
-    }
-
-    /**
-     * 获取当前月最后一天
-     *
-     * @return
-     */
-    public static Date getMonthLastDay() {
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTime(new Date());
-        calendar.set(Calendar.DAY_OF_MONTH, 0);
-        calendar.add(Calendar.MONTH, 1);
-        return calendar.getTime();
-    }
-
-    /**
-     * 判断字符串是否为日期格式
-     *
-     * @return
-     */
-    public static boolean isValidDate(String date, String pattern) {
-        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
-        dateFormat.setLenient(false);
-        try {
-            dateFormat.parse(date);
-            return true;
-        } catch (Exception e) {
-            return false;
-        }
-    }
-
-}

+ 0 - 48
unimall-admin-api/src/main/resources/apijs.ftl

@@ -1,48 +0,0 @@
-import request from '@/utils/request'
-import Qs from 'qs'
-
-export function list${doName}(query) {
-  return request({
-    method: 'post',
-    params: {
-      _gp: 'admin.${serviceLowCaseName}',
-      _mt: 'list',
-      page: query.page,
-      limit: query.limit,
-      ...query
-    }
-  })
-}
-
-export function create${doName}(data) {
-  return request({
-    method: 'post',
-    data: Qs.stringify({
-      _gp: 'admin.${serviceLowCaseName}',
-      _mt: 'create',
-      ${doName}DTO: JSON.stringify(data)
-    })
-  })
-}
-
-export function update${doName}(data) {
-  return request({
-    method: 'post',
-    data: Qs.stringify({
-      _gp: 'admin.${serviceLowCaseName}',
-      _mt: 'edit',
-      ${doName}DTO: JSON.stringify(data)
-    })
-  })
-}
-
-export function delete${doName}(id) {
-  return request({
-    method: 'post',
-    params: {
-      _gp: 'admin.${serviceLowCaseName}',
-      _mt: 'delete',
-      id: id
-    }
-  })
-}

BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/bg.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/breadcrumbs.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/checker-bg.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/blue/message_catch.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/business_rule.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/error_catch.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/error_throw.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/manual.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/message_catch.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/message_throw.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/receive.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/script.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/send.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/service.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/signal_catch.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/signal_throw.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/timer.png


BIN
unimall-admin-api/src/main/resources/diagram-viewer/images/deployer/user.png


+ 0 - 130
unimall-admin-api/src/main/resources/diagram-viewer/index.html

@@ -1,130 +0,0 @@
-<html>
-<head>
-  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-  
-  <link rel="stylesheet" href="style.css" type="text/css" media="screen">
-  <script src="js/jstools.js" type="text/javascript" charset="utf-8"></script>
-  <script src="js/raphael.js" type="text/javascript" charset="utf-8"></script>
-  
-  <script src="js/jquery/jquery.js" type="text/javascript" charset="utf-8"></script>
-  <script src="js/jquery/jquery.progressbar.js" type="text/javascript" charset="utf-8"></script>
-  <script src="js/jquery/jquery.asyncqueue.js" type="text/javascript" charset="utf-8"></script>
-  
-  <script src="js/Color.js" type="text/javascript" charset="utf-8"></script>
-  <script src="js/Polyline.js" type="text/javascript" charset="utf-8"></script>
-  <script src="js/ActivityImpl.js" type="text/javascript" charset="utf-8"></script>
-  <script src="js/ActivitiRest.js" type="text/javascript" charset="utf-8"></script>
-  <script src="js/LineBreakMeasurer.js" type="text/javascript" charset="utf-8"></script>
-  <script src="js/ProcessDiagramGenerator.js" type="text/javascript" charset="utf-8"></script>
-  <script src="js/ProcessDiagramCanvas.js" type="text/javascript" charset="utf-8"></script>
-  
-  <style type="text/css" media="screen">
-    
-  </style>
-</head>
-<body>
-<div class="wrapper">
-  <div id="pb1"></div>
-  <div id="overlayBox" >
-    <div id="diagramBreadCrumbs" class="diagramBreadCrumbs" onmousedown="return false" onselectstart="return false"></div>
-    <div id="diagramHolder" class="diagramHolder"></div>
-    <div class="diagram-info" id="diagramInfo"></div>
-  </div>
-</div>
-<script language='javascript'>
-var DiagramGenerator = {};
-var pb1;
-$(document).ready(function(){
-  var query_string = {};
-  var query = window.location.search.substring(1);
-  var vars = query.split("&");
-  for (var i=0;i<vars.length;i++) {
-    var pair = vars[i].split("=");
-    query_string[pair[0]] = pair[1];
-  } 
-  
-  var processDefinitionId = query_string["processDefinitionId"];
-  var processInstanceId = query_string["processInstanceId"];
-  
-  console.log("Initialize progress bar");
-  
-  pb1 = new $.ProgressBar({
-    boundingBox: '#pb1',
-    label: 'Progressbar!',
-    on: {
-      complete: function() {
-        console.log("Progress Bar COMPLETE");
-        this.set('label', 'complete!');
-        if (processInstanceId) {
-          ProcessDiagramGenerator.drawHighLights(processInstanceId);
-        }
-      },
-      valueChange: function(e) {
-        this.set('label', e.newVal + '%');
-      }
-    },
-    value: 0
-  });
-  console.log("Progress bar inited");
-  
-  ProcessDiagramGenerator.options = {
-    diagramBreadCrumbsId: "diagramBreadCrumbs",
-    diagramHolderId: "diagramHolder",
-    diagramInfoId: "diagramInfo",
-    on: {
-      click: function(canvas, element, contextObject){
-        var mouseEvent = this;
-        console.log("[CLICK] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
-
-        if (contextObject.getProperty("type") == "callActivity") {
-          var processDefinitonKey = contextObject.getProperty("processDefinitonKey");
-          var processDefinitons = contextObject.getProperty("processDefinitons");
-          var processDefiniton = processDefinitons[0];
-          console.log("Load callActivity '" + processDefiniton.processDefinitionKey + "', contextObject: ", contextObject);
-
-          // Load processDefinition
-        ProcessDiagramGenerator.drawDiagram(processDefiniton.processDefinitionId);
-        }
-      },
-      rightClick: function(canvas, element, contextObject){
-        var mouseEvent = this;
-        console.log("[RIGHTCLICK] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
-      },
-      over: function(canvas, element, contextObject){
-        var mouseEvent = this;
-        //console.log("[OVER] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
-
-        // TODO: show tooltip-window with contextObject info
-        ProcessDiagramGenerator.showActivityInfo(contextObject);
-      },
-      out: function(canvas, element, contextObject){
-        var mouseEvent = this;
-        //console.log("[OUT] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
-
-        ProcessDiagramGenerator.hideInfo();
-      }
-    }
-  };
-  
-  var baseUrl = window.document.location.protocol + "//" + window.document.location.host + "/";
-  var shortenedUrl = window.document.location.href.replace(baseUrl, "");
-  baseUrl = baseUrl + shortenedUrl.substring(0, shortenedUrl.indexOf("/"));
-  
-  ActivitiRest.options = {
-    processInstanceHighLightsUrl: baseUrl + "/service/process-instance/{processInstanceId}/highlights?callback=?",
-    processDefinitionUrl: baseUrl + "/service/process-definition/{processDefinitionId}/diagram-layout?callback=?",
-    processDefinitionByKeyUrl: baseUrl + "/service/process-definition/{processDefinitionKey}/diagram-layout?callback=?"
-  };
-  
-  if (processDefinitionId) {
-    ProcessDiagramGenerator.drawDiagram(processDefinitionId);
-    
-  } else {
-    alert("processDefinitionId parameter is required");
-  }
-});
-
-
-</script>
-</body>
-</html>

+ 0 - 74
unimall-admin-api/src/main/resources/diagram-viewer/js/ActivitiRest.js

@@ -1,74 +0,0 @@
-var ActivitiRest = {
-	options: {},
-	getProcessDefinitionByKey: function(processDefinitionKey, callback) {
-		var url = Lang.sub(this.options.processDefinitionByKeyUrl, {processDefinitionKey: processDefinitionKey});
-		
-		$.ajax({
-			url: url,
-			dataType: 'jsonp',
-			cache: false,
-			async: true,
-			success: function(data, textStatus) {
-				var processDefinition = data;
-				if (!processDefinition) {
-					console.error("Process definition '" + processDefinitionKey + "' not found");
-				} else {
-				  callback.apply({processDefinitionId: processDefinition.id});
-				}
-			}
-		}).done(function(data, textStatus) {
-			console.log("ajax done");
-		}).fail(function(jqXHR, textStatus, error){
-			console.error('Get diagram layout['+processDefinitionKey+'] failure: ', textStatus, 'error: ', error, jqXHR);
-		});
-	},
-	
-	getProcessDefinition: function(processDefinitionId, callback) {
-		var url = Lang.sub(this.options.processDefinitionUrl, {processDefinitionId: processDefinitionId});
-		
-		$.ajax({
-			url: url,
-			dataType: 'jsonp',
-			cache: false,
-			async: true,
-			success: function(data, textStatus) {
-				var processDefinitionDiagramLayout = data;
-				if (!processDefinitionDiagramLayout) {
-					console.error("Process definition diagram layout '" + processDefinitionId + "' not found");
-					return;
-				} else {
-					callback.apply({processDefinitionDiagramLayout: processDefinitionDiagramLayout});
-				}
-			}
-		}).done(function(data, textStatus) {
-			console.log("ajax done");
-		}).fail(function(jqXHR, textStatus, error){
-			console.log('Get diagram layout['+processDefinitionId+'] failure: ', textStatus, jqXHR);
-		});
-	},
-	
-	getHighLights: function(processInstanceId, callback) {
-		var url = Lang.sub(this.options.processInstanceHighLightsUrl, {processInstanceId: processInstanceId});
-		
-		$.ajax({
-			url: url,
-			dataType: 'jsonp',
-			cache: false,
-			async: true,
-			success: function(data, textStatus) {
-				console.log("ajax returned data");
-				var highLights = data;
-				if (!highLights) {
-					console.log("highLights not found");
-					return;
-				} else {
-					callback.apply({highLights: highLights});
-				}
-			}
-		}).done(function(data, textStatus) {
-			console.log("ajax done");
-		}).fail(function(jqXHR, textStatus, error){
-		  console.log('Get HighLights['+processInstanceId+'] failure: ', textStatus, jqXHR);
-		});
-	}
-};

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
unimall-admin-api/src/main/resources/diagram-viewer/js/ActivityImpl.js


+ 0 - 603
unimall-admin-api/src/main/resources/diagram-viewer/js/Color.js

@@ -1,603 +0,0 @@
-/**
- * Web color table
- * 
- * @author Dmitry Farafonov
- */
-
-var Color = {
-   /**
-   * The color white.  In the default sRGB space.
-   */
-  white     : Raphael.getRGB("rgb(255,255,255)"),
-  
-  /**
-   * The color white.  In the default sRGB space.
-   */
-  WHITE : this.white,
-  
-  /**
-   * The color light gray.  In the default sRGB space.
-   */
-  lightGray : Raphael.getRGB("rgb(192, 192, 192)"),
-  
-  /**
-   * The color light gray.  In the default sRGB space.
-   */
-  LIGHT_GRAY : this.lightGray,
-  
-  /**
-   * The color gray.  In the default sRGB space.
-   */
-  gray : Raphael.getRGB("rgb(128, 128, 128)"),
-  
-  /**
-   * The color gray.  In the default sRGB space.
-   */
-  GRAY : this.gray,
-  
-  /**
-   * The color dark gray.  In the default sRGB space.
-   */
-  darkGray : Raphael.getRGB("rgb(64, 64, 64)"),
-  
-  /**
-   * The color dark gray.  In the default sRGB space.
-   */
-  DARK_GRAY : this.darkGray,
-  
-  /**
-   * The color black.  In the default sRGB space.
-   */
-  black : Raphael.getRGB("rgb(0, 0, 0)"),
-  
-  /**
-   * The color black.  In the default sRGB space.
-   */
-  BLACK : this.black,
-  
-  /**
-   * The color red.  In the default sRGB space.
-   */
-  red : Raphael.getRGB("rgb(255, 0, 0)"),
-  
-  /**
-   * The color red.  In the default sRGB space.
-   */
-  RED : this.red,
-  
-  /**
-   * The color pink.  In the default sRGB space.
-   */
-  pink : Raphael.getRGB("rgb(255, 175, 175)"),
-  
-  /**
-   * The color pink.  In the default sRGB space.
-   */
-  PINK : this.pink,
-  
-  /**
-   * The color orange.  In the default sRGB space.
-   */
-  orange : Raphael.getRGB("rgb(255, 200, 0)"),
-  
-  /**
-   * The color orange.  In the default sRGB space.
-   */
-  ORANGE : this.orange,
-  
-  /**
-   * The color yellow.  In the default sRGB space.
-   */
-  yellow : Raphael.getRGB("rgb(255, 255, 0)"),
-  
-  /**
-   * The color yellow.  In the default sRGB space.
-   */
-  YELLOW : this.yellow,
-  
-  /**
-   * The color green.  In the default sRGB space.
-   */
-  green : Raphael.getRGB("rgb(0, 255, 0)"),
-  
-  /**
-   * The color green.  In the default sRGB space.
-   */
-  GREEN : this.green,
-  
-  /**
-   * The color magenta.  In the default sRGB space.
-   */
-  magenta : Raphael.getRGB("rgb(255, 0, 255)"),
-  
-  /**
-   * The color magenta.  In the default sRGB space.
-   */
-  MAGENTA : this.magenta,
-  
-  /**
-   * The color cyan.  In the default sRGB space.
-   */
-  cyan : Raphael.getRGB("rgb(0, 255, 255)"),
-  
-  /**
-   * The color cyan.  In the default sRGB space.
-   */
-  CYAN : this.cyan,
-  
-  /**
-   * The color blue.  In the default sRGB space.
-   */
-  blue : Raphael.getRGB("rgb(0, 0, 255)"),
-  
-  /**
-   * The color blue.  In the default sRGB space.
-   */
-  BLUE : this.blue,
-  
-  /************************************************************************/
-
-  // http://www.stm.dp.ua/web-design/color-html.php
-  
-	Snow			:   Raphael.getRGB("#FFFAFA	"),  // 	255 250 250
-	GhostWhite		:   Raphael.getRGB("#F8F8FF	"),  // 	248 248 255
-	WhiteSmoke		:   Raphael.getRGB("#F5F5F5	"),  // 	245 245 245
-	Gainsboro		:   Raphael.getRGB("#DCDCDC	"),  // 	220 220 220
-	FloralWhite		:   Raphael.getRGB("#FFFAF0	"),  // 	255 250 240
-	OldLace			:   Raphael.getRGB("#FDF5E6	"),  // 	253 245 230
-	Linen			:   Raphael.getRGB("#FAF0E6	"),  // 	250 240 230
-	AntiqueWhite	:   Raphael.getRGB("#FAEBD7	"),  // 	250 235 215
-	PapayaWhip		:   Raphael.getRGB("#FFEFD5	"),  // 	255 239 213
-	BlanchedAlmond	:   Raphael.getRGB("#FFEBCD	"),  // 	255 235 205
-	Bisque			:   Raphael.getRGB("#FFE4C4	"),  // 	255 228 196
-	PeachPuff		:   Raphael.getRGB("#FFDAB9	"),  // 	255 218 185
-	NavajoWhite		:   Raphael.getRGB("#FFDEAD	"),  // 	255 222 173
-	Moccasin		:   Raphael.getRGB("#FFE4B5	"),  // 	255 228 181
-	Cornsilk		:   Raphael.getRGB("#FFF8DC	"),  // 	255 248 220
-	Ivory			:   Raphael.getRGB("#FFFFF0	"),  // 	255 255 240
-	LemonChiffon	:   Raphael.getRGB("#FFFACD	"),  // 	255 250 205
-	Seashell		:   Raphael.getRGB("#FFF5EE	"),  // 	255 245 238
-	Honeydew		:   Raphael.getRGB("#F0FFF0	"),  // 	240 255 240
-	MintCream		:   Raphael.getRGB("#F5FFFA	"),  // 	245 255 250
-	Azure			:   Raphael.getRGB("#F0FFFF	"),  // 	240 255 255
-	AliceBlue		:   Raphael.getRGB("#F0F8FF	"),  // 	240 248 255
-	lavender		:   Raphael.getRGB("#E6E6FA	"),  // 	230 230 250
-	LavenderBlush	:   Raphael.getRGB("#FFF0F5	"),  // 	255 240 245
-	MistyRose		:   Raphael.getRGB("#FFE4E1	"),  // 	255 228 225
-	White			:   Raphael.getRGB("#FFFFFF	"),  // 	255 255 255
-	Black			:   Raphael.getRGB("#000000	"),  // 	0 0 0
-	DarkSlateGray	:   Raphael.getRGB("#2F4F4F	"),  // 	47 79 79
-	DimGrey			:   Raphael.getRGB("#696969	"),  // 	105 105 105
-	SlateGrey		:   Raphael.getRGB("#708090	"),  // 	112 128 144
-	LightSlateGray	:   Raphael.getRGB("#778899	"),  // 	119 136 153
-	Grey			:   Raphael.getRGB("#BEBEBE	"),  // 	190 190 190
-	LightGray		:   Raphael.getRGB("#D3D3D3	"),  // 	211 211 211
-	MidnightBlue	:   Raphael.getRGB("#191970	"),  // 	25 25 112
-	NavyBlue		:   Raphael.getRGB("#000080	"),  // 	0 0 128
-	CornflowerBlue	:   Raphael.getRGB("#6495ED	"),  // 	100 149 237
-	DarkSlateBlue	:   Raphael.getRGB("#483D8B	"),  // 	72 61 139
-	SlateBlue		:   Raphael.getRGB("#6A5ACD	"),  // 	106 90 205
-	MediumSlateBlue	:   Raphael.getRGB("#7B68EE	"),  // 	123 104 238
-	LightSlateBlue	:   Raphael.getRGB("#8470FF	"),  // 	132 112 255
-	MediumBlue		:   Raphael.getRGB("#0000CD	"),  // 	0 0 205
-	RoyalBlue		:   Raphael.getRGB("#4169E1	"),  // 	65 105 225
-	Blue			:   Raphael.getRGB("#0000FF	"),  // 	0 0 255
-	DodgerBlue		:   Raphael.getRGB("#1E90FF	"),  // 	30 144 255
-	DeepSkyBlue		:   Raphael.getRGB("#00BFFF	"),  // 	0 191 255
-	SkyBlue			:   Raphael.getRGB("#87CEEB	"),  // 	135 206 235
-	LightSkyBlue	:   Raphael.getRGB("#87CEFA	"),  // 	135 206 250
-	SteelBlue		:   Raphael.getRGB("#4682B4	"),  // 	70 130 180
-	LightSteelBlue	:   Raphael.getRGB("#B0C4DE	"),  // 	176 196 222
-	LightBlue		:   Raphael.getRGB("#ADD8E6	"),  // 	173 216 230
-	PowderBlue		:   Raphael.getRGB("#B0E0E6	"),  // 	176 224 230
-	PaleTurquoise	:   Raphael.getRGB("#AFEEEE	"),  // 	175 238 238
-	DarkTurquoise	:   Raphael.getRGB("#00CED1	"),  // 	0 206 209
-	MediumTurquoise	:   Raphael.getRGB("#48D1CC	"),  // 	72 209 204
-	Turquoise		:   Raphael.getRGB("#40E0D0	"),  // 	64 224 208
-	Cyan			:   Raphael.getRGB("#00FFFF	"),  // 	0 255 255
-	LightCyan		:   Raphael.getRGB("#E0FFFF	"),  // 	224 255 255
-	CadetBlue		:   Raphael.getRGB("#5F9EA0	"),  // 	95 158 160
-	MediumAquamarine:   Raphael.getRGB("#66CDAA	"),  // 	102 205 170
-	Aquamarine		:   Raphael.getRGB("#7FFFD4	"),  // 	127 255 212
-	DarkGreen		:   Raphael.getRGB("#006400	"),  // 	0 100 0
-	DarkOliveGreen	:   Raphael.getRGB("#556B2F	"),  // 	85 107 47
-	DarkSeaGreen	:   Raphael.getRGB("#8FBC8F	"),  // 	143 188 143
-	SeaGreen		:   Raphael.getRGB("#2E8B57	"),  // 	46 139 87
-	MediumSeaGreen	:   Raphael.getRGB("#3CB371	"),  // 	60 179 113
-	LightSeaGreen	:   Raphael.getRGB("#20B2AA	"),  // 	32 178 170
-	PaleGreen		:   Raphael.getRGB("#98FB98	"),  // 	152 251 152
-	SpringGreen		:   Raphael.getRGB("#00FF7F	"),  // 	0 255 127
-	LawnGreen		:   Raphael.getRGB("#7CFC00	"),  // 	124 252 0
-	Green			:   Raphael.getRGB("#00FF00	"),  // 	0 255 0
-	Chartreuse		:   Raphael.getRGB("#7FFF00	"),  // 	127 255 0
-	MedSpringGreen	:   Raphael.getRGB("#00FA9A	"),  // 	0 250 154
-	GreenYellow		:   Raphael.getRGB("#ADFF2F	"),  // 	173 255 47
-	LimeGreen		:   Raphael.getRGB("#32CD32	"),  // 	50 205 50
-	YellowGreen		:   Raphael.getRGB("#9ACD32	"),  // 	154 205 50
-	ForestGreen		:   Raphael.getRGB("#228B22	"),  // 	34 139 34
-	OliveDrab		:   Raphael.getRGB("#6B8E23	"),  // 	107 142 35
-	DarkKhaki		:   Raphael.getRGB("#BDB76B	"),  // 	189 183 107
-	PaleGoldenrod	:   Raphael.getRGB("#EEE8AA	"),  // 	238 232 170
-	LtGoldenrodYello:   Raphael.getRGB("#FAFAD2	"),  // 	250 250 210
-	LightYellow		:   Raphael.getRGB("#FFFFE0	"),  // 	255 255 224
-	Yellow			:   Raphael.getRGB("#FFFF00	"),  // 	255 255 0
-	Gold			:   Raphael.getRGB("#FFD700	"),  // 	255 215 0
-	LightGoldenrod	:   Raphael.getRGB("#EEDD82	"),  // 	238 221 130
-	goldenrod		:   Raphael.getRGB("#DAA520	"),  // 	218 165 32
-	DarkGoldenrod	:   Raphael.getRGB("#B8860B	"),  // 	184 134 11
-	RosyBrown		:   Raphael.getRGB("#BC8F8F	"),  // 	188 143 143
-	IndianRed		:   Raphael.getRGB("#CD5C5C	"),  // 	205 92 92
-	SaddleBrown		:   Raphael.getRGB("#8B4513	"),  // 	139 69 19
-	Sienna			:   Raphael.getRGB("#A0522D	"),  // 	160 82 45
-	Peru			:   Raphael.getRGB("#CD853F	"),  // 	205 133 63
-	Burlywood		:   Raphael.getRGB("#DEB887	"),  // 	222 184 135
-	Beige			:   Raphael.getRGB("#F5F5DC	"),  // 	245 245 220
-	Wheat			:   Raphael.getRGB("#F5DEB3	"),  // 	245 222 179
-	SandyBrown		:   Raphael.getRGB("#F4A460	"),  // 	244 164 96
-	Tan				:   Raphael.getRGB("#D2B48C	"),  // 	210 180 140
-	Chocolate		:   Raphael.getRGB("#D2691E	"),  // 	210 105 30
-	Firebrick		:   Raphael.getRGB("#B22222	"),  // 	178 34 34
-	Brown			:   Raphael.getRGB("#A52A2A	"),  // 	165 42 42
-	DarkSalmon		:   Raphael.getRGB("#E9967A	"),  // 	233 150 122
-	Salmon			:   Raphael.getRGB("#FA8072	"),  // 	250 128 114
-	LightSalmon		:   Raphael.getRGB("#FFA07A	"),  // 	255 160 122
-	Orange			:   Raphael.getRGB("#FFA500	"),  // 	255 165 0
-	DarkOrange		:   Raphael.getRGB("#FF8C00	"),  // 	255 140 0
-	Coral			:   Raphael.getRGB("#FF7F50	"),  // 	255 127 80
-	LightCoral		:   Raphael.getRGB("#F08080	"),  // 	240 128 128
-	Tomato			:   Raphael.getRGB("#FF6347	"),  // 	255 99 71
-	OrangeRed		:   Raphael.getRGB("#FF4500	"),  // 	255 69 0
-	Red				:   Raphael.getRGB("#FF0000	"),  // 	255 0 0
-	HotPink			:   Raphael.getRGB("#FF69B4	"),  // 	255 105 180
-	DeepPink		:   Raphael.getRGB("#FF1493	"),  // 	255 20 147
-	Pink			:   Raphael.getRGB("#FFC0CB	"),  // 	255 192 203
-	LightPink		:   Raphael.getRGB("#FFB6C1	"),  // 	255 182 193
-	PaleVioletRed	:   Raphael.getRGB("#DB7093	"),  // 	219 112 147
-	Maroon			:   Raphael.getRGB("#B03060	"),  // 	176 48 96
-	MediumVioletRed	:   Raphael.getRGB("#C71585	"),  // 	199 21 133
-	VioletRed		:   Raphael.getRGB("#D02090	"),  // 	208 32 144
-	Magenta			:   Raphael.getRGB("#FF00FF	"),  // 	255 0 255
-	Violet			:   Raphael.getRGB("#EE82EE	"),  // 	238 130 238
-	Plum			:   Raphael.getRGB("#DDA0DD	"),  // 	221 160 221
-	Orchid			:   Raphael.getRGB("#DA70D6	"),  // 	218 112 214
-	MediumOrchid	:   Raphael.getRGB("#BA55D3	"),  // 	186 85 211
-	DarkOrchid		:   Raphael.getRGB("#9932CC	"),  // 	153 50 204
-	DarkViolet		:   Raphael.getRGB("#9400D3	"),  // 	148 0 211
-	BlueViolet		:   Raphael.getRGB("#8A2BE2	"),  // 	138 43 226
-	Purple			:   Raphael.getRGB("#A020F0	"),  // 	160 32 240
-	MediumPurple	:   Raphael.getRGB("#9370DB	"),  // 	147 112 219
-	Thistle			:   Raphael.getRGB("#D8BFD8	"),  // 	216 191 216
-	Snow1			:   Raphael.getRGB("#FFFAFA	"),  // 	255 250 250
-	Snow2			:   Raphael.getRGB("#EEE9E9	"),  // 	238 233 233
-	Snow3			:   Raphael.getRGB("#CDC9C9	"),  // 	205 201 201
-	Snow4			:   Raphael.getRGB("#8B8989	"),  // 	139 137 137
-	Seashell1		:   Raphael.getRGB("#FFF5EE	"),  // 	255 245 238
-	Seashell2		:   Raphael.getRGB("#EEE5DE	"),  // 	238 229 222
-	Seashell3		:   Raphael.getRGB("#CDC5BF	"),  // 	205 197 191
-	Seashell4		:   Raphael.getRGB("#8B8682	"),  // 	139 134 130
-	AntiqueWhite1	:   Raphael.getRGB("#FFEFDB	"),  // 	255 239 219
-	AntiqueWhite2	:   Raphael.getRGB("#EEDFCC	"),  // 	238 223 204
-	AntiqueWhite3	:   Raphael.getRGB("#CDC0B0	"),  // 	205 192 176
-	AntiqueWhite4	:   Raphael.getRGB("#8B8378	"),  // 	139 131 120
-	Bisque1			:   Raphael.getRGB("#FFE4C4	"),  // 	255 228 196
-	Bisque2			:   Raphael.getRGB("#EED5B7	"),  // 	238 213 183
-	Bisque3			:   Raphael.getRGB("#CDB79E	"),  // 	205 183 158
-	Bisque4			:   Raphael.getRGB("#8B7D6B	"),  // 	139 125 107
-	PeachPuff1		:   Raphael.getRGB("#FFDAB9	"),  // 	255 218 185
-	PeachPuff2		:   Raphael.getRGB("#EECBAD	"),  // 	238 203 173
-	PeachPuff3		:   Raphael.getRGB("#CDAF95	"),  // 	205 175 149
-	PeachPuff4		:   Raphael.getRGB("#8B7765	"),  // 	139 119 101
-	NavajoWhite1	:   Raphael.getRGB("#FFDEAD	"),  // 	255 222 173
-	NavajoWhite2	:   Raphael.getRGB("#EECFA1	"),  // 	238 207 161
-	NavajoWhite3	:   Raphael.getRGB("#CDB38B	"),  // 	205 179 139
-	NavajoWhite4	:   Raphael.getRGB("#8B795E	"),  // 	139 121 94
-	LemonChiffon1	:   Raphael.getRGB("#FFFACD	"),  // 	255 250 205
-	LemonChiffon2	:   Raphael.getRGB("#EEE9BF	"),  // 	238 233 191
-	LemonChiffon3	:   Raphael.getRGB("#CDC9A5	"),  // 	205 201 165
-	LemonChiffon4	:   Raphael.getRGB("#8B8970	"),  // 	139 137 112
-	Cornsilk1		:   Raphael.getRGB("#FFF8DC	"),  // 	255 248 220
-	Cornsilk2		:   Raphael.getRGB("#EEE8CD	"),  // 	238 232 205
-	Cornsilk3		:   Raphael.getRGB("#CDC8B1	"),  // 	205 200 177
-	Cornsilk4		:   Raphael.getRGB("#8B8878	"),  // 	139 136 120
-	Ivory1			:   Raphael.getRGB("#FFFFF0	"),  // 	255 255 240
-	Ivory2			:   Raphael.getRGB("#EEEEE0	"),  // 	238 238 224
-	Ivory3			:   Raphael.getRGB("#CDCDC1	"),  // 	205 205 193
-	Ivory4			:   Raphael.getRGB("#8B8B83	"),  // 	139 139 131
-	Honeydew1		:   Raphael.getRGB("#F0FFF0	"),  // 	240 255 240
-	Honeydew2		:   Raphael.getRGB("#E0EEE0	"),  // 	224 238 224
-	Honeydew3		:   Raphael.getRGB("#C1CDC1	"),  // 	193 205 193
-	Honeydew4		:   Raphael.getRGB("#838B83	"),  // 	131 139 131
-	LavenderBlush1	:   Raphael.getRGB("#FFF0F5	"),  // 	255 240 245
-	LavenderBlush2	:   Raphael.getRGB("#EEE0E5	"),  // 	238 224 229
-	LavenderBlush3	:   Raphael.getRGB("#CDC1C5	"),  // 	205 193 197
-	LavenderBlush4	:   Raphael.getRGB("#8B8386	"),  // 	139 131 134
-	MistyRose1		:   Raphael.getRGB("#FFE4E1	"),  // 	255 228 225
-	MistyRose2		:   Raphael.getRGB("#EED5D2	"),  // 	238 213 210
-	MistyRose3		:   Raphael.getRGB("#CDB7B5	"),  // 	205 183 181
-	MistyRose4		:   Raphael.getRGB("#8B7D7B	"),  // 	139 125 123
-	Azure1			:   Raphael.getRGB("#F0FFFF	"),  // 	240 255 255
-	Azure2			:   Raphael.getRGB("#E0EEEE	"),  // 	224 238 238
-	Azure3			:   Raphael.getRGB("#C1CDCD	"),  // 	193 205 205
-	Azure4			:   Raphael.getRGB("#838B8B	"),  // 	131 139 139
-	SlateBlue1		:   Raphael.getRGB("#836FFF	"),  // 	131 111 255
-	SlateBlue2		:   Raphael.getRGB("#7A67EE	"),  // 	122 103 238
-	SlateBlue3		:   Raphael.getRGB("#6959CD	"),  // 	105 89 205
-	SlateBlue4		:   Raphael.getRGB("#473C8B	"),  // 	71 60 139
-	RoyalBlue1		:   Raphael.getRGB("#4876FF	"),  // 	72 118 255
-	RoyalBlue2		:   Raphael.getRGB("#436EEE	"),  // 	67 110 238
-	RoyalBlue3		:   Raphael.getRGB("#3A5FCD	"),  // 	58 95 205
-	RoyalBlue4		:   Raphael.getRGB("#27408B	"),  // 	39 64 139
-	Blue1			:   Raphael.getRGB("#0000FF	"),  // 	0 0 255
-	Blue2			:   Raphael.getRGB("#0000EE	"),  // 	0 0 238
-	Blue3			:   Raphael.getRGB("#0000CD	"),  // 	0 0 205
-	Blue4			:   Raphael.getRGB("#00008B	"),  // 	0 0 139
-	DodgerBlue1		:   Raphael.getRGB("#1E90FF	"),  // 	30 144 255
-	DodgerBlue2		:   Raphael.getRGB("#1C86EE	"),  // 	28 134 238
-	DodgerBlue3		:   Raphael.getRGB("#1874CD	"),  // 	24 116 205
-	DodgerBlue4		:   Raphael.getRGB("#104E8B	"),  // 	16 78 139
-	SteelBlue1		:   Raphael.getRGB("#63B8FF	"),  // 	99 184 255
-	SteelBlue2		:   Raphael.getRGB("#5CACEE	"),  // 	92 172 238
-	SteelBlue3		:   Raphael.getRGB("#4F94CD	"),  // 	79 148 205
-	SteelBlue4		:   Raphael.getRGB("#36648B	"),  // 	54 100 139
-	DeepSkyBlue1	:   Raphael.getRGB("#00BFFF	"),  // 	0 191 255
-	DeepSkyBlue2	:   Raphael.getRGB("#00B2EE	"),  // 	0 178 238
-	DeepSkyBlue3	:   Raphael.getRGB("#009ACD	"),  // 	0 154 205
-	DeepSkyBlue4	:   Raphael.getRGB("#00688B	"),  // 	0 104 139
-	SkyBlue1		:   Raphael.getRGB("#87CEFF	"),  // 	135 206 255
-	SkyBlue2		:   Raphael.getRGB("#7EC0EE	"),  // 	126 192 238
-	SkyBlue3		:   Raphael.getRGB("#6CA6CD	"),  // 	108 166 205
-	SkyBlue4		:   Raphael.getRGB("#4A708B	"),  // 	74 112 139
-	LightSkyBlue1	:   Raphael.getRGB("#B0E2FF	"),  // 	176 226 255
-	LightSkyBlue2	:   Raphael.getRGB("#A4D3EE	"),  // 	164 211 238
-	LightSkyBlue3	:   Raphael.getRGB("#8DB6CD	"),  // 	141 182 205
-	LightSkyBlue4	:   Raphael.getRGB("#607B8B	"),  // 	96 123 139
-	SlateGray1		:   Raphael.getRGB("#C6E2FF	"),  // 	198 226 255
-	SlateGray2		:   Raphael.getRGB("#B9D3EE	"),  // 	185 211 238
-	SlateGray3		:   Raphael.getRGB("#9FB6CD	"),  // 	159 182 205
-	SlateGray4		:   Raphael.getRGB("#6C7B8B	"),  // 	108 123 139
-	LightSteelBlue1	:   Raphael.getRGB("#CAE1FF	"),  // 	202 225 255
-	LightSteelBlue2	:   Raphael.getRGB("#BCD2EE	"),  // 	188 210 238
-	LightSteelBlue3	:   Raphael.getRGB("#A2B5CD	"),  // 	162 181 205
-	LightSteelBlue4	:   Raphael.getRGB("#6E7B8B	"),  // 	110 123 139
-	LightBlue1		:   Raphael.getRGB("#BFEFFF	"),  // 	191 239 255
-	LightBlue2		:   Raphael.getRGB("#B2DFEE	"),  // 	178 223 238
-	LightBlue3		:   Raphael.getRGB("#9AC0CD	"),  // 	154 192 205
-	LightBlue4		:   Raphael.getRGB("#68838B	"),  // 	104 131 139
-	LightCyan1		:   Raphael.getRGB("#E0FFFF	"),  // 	224 255 255
-	LightCyan2		:   Raphael.getRGB("#D1EEEE	"),  // 	209 238 238
-	LightCyan3		:   Raphael.getRGB("#B4CDCD	"),  // 	180 205 205
-	LightCyan4		:   Raphael.getRGB("#7A8B8B	"),  // 	122 139 139
-	PaleTurquoise1	:   Raphael.getRGB("#BBFFFF	"),  // 	187 255 255
-	PaleTurquoise2	:   Raphael.getRGB("#AEEEEE	"),  // 	174 238 238
-	PaleTurquoise3	:   Raphael.getRGB("#96CDCD	"),  // 	150 205 205
-	PaleTurquoise4	:   Raphael.getRGB("#668B8B	"),  // 	102 139 139
-	CadetBlue1		:   Raphael.getRGB("#98F5FF	"),  // 	152 245 255
-	CadetBlue2		:   Raphael.getRGB("#8EE5EE	"),  // 	142 229 238
-	CadetBlue3		:   Raphael.getRGB("#7AC5CD	"),  // 	122 197 205
-	CadetBlue4		:   Raphael.getRGB("#53868B	"),  // 	83 134 139
-	Turquoise1		:   Raphael.getRGB("#00F5FF	"),  // 	0 245 255
-	Turquoise2		:   Raphael.getRGB("#00E5EE	"),  // 	0 229 238
-	Turquoise3		:   Raphael.getRGB("#00C5CD	"),  // 	0 197 205
-	Turquoise4		:   Raphael.getRGB("#00868B	"),  // 	0 134 139
-	Cyan1			:   Raphael.getRGB("#00FFFF	"),  // 	0 255 255
-	Cyan2			:   Raphael.getRGB("#00EEEE	"),  // 	0 238 238
-	Cyan3			:   Raphael.getRGB("#00CDCD	"),  // 	0 205 205
-	Cyan4			:   Raphael.getRGB("#008B8B	"),  // 	0 139 139
-	DarkSlateGray1	:   Raphael.getRGB("#97FFFF	"),  // 	151 255 255
-	DarkSlateGray2	:   Raphael.getRGB("#8DEEEE	"),  // 	141 238 238
-	DarkSlateGray3	:   Raphael.getRGB("#79CDCD	"),  // 	121 205 205
-	DarkSlateGray4	:   Raphael.getRGB("#528B8B	"),  // 	82 139 139
-	Aquamarine1		:   Raphael.getRGB("#7FFFD4	"),  // 	127 255 212
-	Aquamarine2		:   Raphael.getRGB("#76EEC6	"),  // 	118 238 198
-	Aquamarine3		:   Raphael.getRGB("#66CDAA	"),  // 	102 205 170
-	Aquamarine4		:   Raphael.getRGB("#458B74	"),  // 	69 139 116
-	DarkSeaGreen1	:   Raphael.getRGB("#C1FFC1	"),  // 	193 255 193
-	DarkSeaGreen2	:   Raphael.getRGB("#B4EEB4	"),  // 	180 238 180
-	DarkSeaGreen3	:   Raphael.getRGB("#9BCD9B	"),  // 	155 205 155
-	DarkSeaGreen4	:   Raphael.getRGB("#698B69	"),  // 	105 139 105
-	SeaGreen1		:   Raphael.getRGB("#54FF9F	"),  // 	84 255 159
-	SeaGreen2		:   Raphael.getRGB("#4EEE94	"),  // 	78 238 148
-	SeaGreen3		:   Raphael.getRGB("#43CD80	"),  // 	67 205 128
-	SeaGreen4		:   Raphael.getRGB("#2E8B57	"),  // 	46 139 87
-	PaleGreen1		:   Raphael.getRGB("#9AFF9A	"),  // 	154 255 154
-	PaleGreen2		:   Raphael.getRGB("#90EE90	"),  // 	144 238 144
-	PaleGreen3		:   Raphael.getRGB("#7CCD7C	"),  // 	124 205 124
-	PaleGreen4		:   Raphael.getRGB("#548B54	"),  // 	84 139 84
-	SpringGreen1	:   Raphael.getRGB("#00FF7F	"),  // 	0 255 127
-	SpringGreen2	:   Raphael.getRGB("#00EE76	"),  // 	0 238 118
-	SpringGreen3	:   Raphael.getRGB("#00CD66	"),  // 	0 205 102
-	SpringGreen4	:   Raphael.getRGB("#008B45	"),  // 	0 139 69
-	Green1			:   Raphael.getRGB("#00FF00	"),  // 	0 255 0
-	Green2			:   Raphael.getRGB("#00EE00	"),  // 	0 238 0
-	Green3			:   Raphael.getRGB("#00CD00	"),  // 	0 205 0
-	Green4			:   Raphael.getRGB("#008B00	"),  // 	0 139 0
-	Chartreuse1		:   Raphael.getRGB("#7FFF00	"),  // 	127 255 0
-	Chartreuse2		:   Raphael.getRGB("#76EE00	"),  // 	118 238 0
-	Chartreuse3		:   Raphael.getRGB("#66CD00	"),  // 	102 205 0
-	Chartreuse4		:   Raphael.getRGB("#458B00	"),  // 	69 139 0
-	OliveDrab1		:   Raphael.getRGB("#C0FF3E	"),  // 	192 255 62
-	OliveDrab2		:   Raphael.getRGB("#B3EE3A	"),  // 	179 238 58
-	OliveDrab3		:   Raphael.getRGB("#9ACD32	"),  // 	154 205 50
-	OliveDrab4		:   Raphael.getRGB("#698B22	"),  // 	105 139 34
-	DarkOliveGreen1	:   Raphael.getRGB("#CAFF70	"),  // 	202 255 112
-	DarkOliveGreen2	:   Raphael.getRGB("#BCEE68	"),  // 	188 238 104
-	DarkOliveGreen3	:   Raphael.getRGB("#A2CD5A	"),  // 	162 205 90
-	DarkOliveGreen4	:   Raphael.getRGB("#6E8B3D	"),  // 	110 139 61
-	Khaki1			:   Raphael.getRGB("#FFF68F	"),  // 	255 246 143
-	Khaki2			:   Raphael.getRGB("#EEE685	"),  // 	238 230 133
-	Khaki3			:   Raphael.getRGB("#CDC673	"),  // 	205 198 115
-	Khaki4			:   Raphael.getRGB("#8B864E	"),  // 	139 134 78
-	LightGoldenrod1	:   Raphael.getRGB("#FFEC8B	"),  // 	255 236 139
-	LightGoldenrod2	:   Raphael.getRGB("#EEDC82	"),  // 	238 220 130
-	LightGoldenrod3	:   Raphael.getRGB("#CDBE70	"),  // 	205 190 112
-	LightGoldenrod4	:   Raphael.getRGB("#8B814C	"),  // 	139 129 76
-	LightYellow1	:   Raphael.getRGB("#FFFFE0	"),  // 	255 255 224
-	LightYellow2	:   Raphael.getRGB("#EEEED1	"),  // 	238 238 209
-	LightYellow3	:   Raphael.getRGB("#CDCDB4	"),  // 	205 205 180
-	LightYellow4	:   Raphael.getRGB("#8B8B7A	"),  // 	139 139 122
-	Yellow1			:   Raphael.getRGB("#FFFF00	"),  // 	255 255 0
-	Yellow2			:   Raphael.getRGB("#EEEE00	"),  // 	238 238 0
-	Yellow3			:   Raphael.getRGB("#CDCD00	"),  // 	205 205 0
-	Yellow4			:   Raphael.getRGB("#8B8B00	"),  // 	139 139 0
-	Gold1			:   Raphael.getRGB("#FFD700	"),  // 	255 215 0
-	Gold2			:   Raphael.getRGB("#EEC900	"),  // 	238 201 0
-	Gold3			:   Raphael.getRGB("#CDAD00	"),  // 	205 173 0
-	Gold4			:   Raphael.getRGB("#8B7500	"),  // 	139 117 0
-	Goldenrod1		:   Raphael.getRGB("#FFC125	"),  // 	255 193 37
-	Goldenrod2		:   Raphael.getRGB("#EEB422	"),  // 	238 180 34
-	Goldenrod3		:   Raphael.getRGB("#CD9B1D	"),  // 	205 155 29
-	Goldenrod4		:   Raphael.getRGB("#8B6914	"),  // 	139 105 20
-	DarkGoldenrod1	:   Raphael.getRGB("#FFB90F	"),  // 	255 185 15
-	DarkGoldenrod2	:   Raphael.getRGB("#EEAD0E	"),  // 	238 173 14
-	DarkGoldenrod3	:   Raphael.getRGB("#CD950C	"),  // 	205 149 12
-	DarkGoldenrod4	:   Raphael.getRGB("#8B658B	"),  // 	139 101 8
-	RosyBrown1		:   Raphael.getRGB("#FFC1C1	"),  // 	255 193 193
-	RosyBrown2		:   Raphael.getRGB("#EEB4B4	"),  // 	238 180 180
-	RosyBrown3		:   Raphael.getRGB("#CD9B9B	"),  // 	205 155 155
-	RosyBrown4		:   Raphael.getRGB("#8B6969	"),  // 	139 105 105
-	IndianRed1		:   Raphael.getRGB("#FF6A6A	"),  // 	255 106 106
-	IndianRed2		:   Raphael.getRGB("#EE6363	"),  // 	238 99 99
-	IndianRed3		:   Raphael.getRGB("#CD5555	"),  // 	205 85 85
-	IndianRed4		:   Raphael.getRGB("#8B3A3A	"),  // 	139 58 58
-	Sienna1			:   Raphael.getRGB("#FF8247	"),  // 	255 130 71
-	Sienna2			:   Raphael.getRGB("#EE7942	"),  // 	238 121 66
-	Sienna3			:   Raphael.getRGB("#CD6839	"),  // 	205 104 57
-	Sienna4			:   Raphael.getRGB("#8B4726	"),  // 	139 71 38
-	Burlywood1		:   Raphael.getRGB("#FFD39B	"),  // 	255 211 155
-	Burlywood2		:   Raphael.getRGB("#EEC591	"),  // 	238 197 145
-	Burlywood3		:   Raphael.getRGB("#CDAA7D	"),  // 	205 170 125
-	Burlywood4		:   Raphael.getRGB("#8B7355	"),  // 	139 115 85
-	Wheat1			:   Raphael.getRGB("#FFE7BA	"),  // 	255 231 186
-	Wheat2			:   Raphael.getRGB("#EED8AE	"),  // 	238 216 174
-	Wheat3			:   Raphael.getRGB("#CDBA96	"),  // 	205 186 150
-	Wheat4			:   Raphael.getRGB("#8B7E66	"),  // 	139 126 102
-	Tan1			:   Raphael.getRGB("#FFA54F	"),  // 	255 165 79
-	Tan2			:   Raphael.getRGB("#EE9A49	"),  // 	238 154 73
-	Tan3			:   Raphael.getRGB("#CD853F	"),  // 	205 133 63
-	Tan4			:   Raphael.getRGB("#8B5A2B	"),  // 	139 90 43
-	Chocolate1		:   Raphael.getRGB("#FF7F24	"),  // 	255 127 36
-	Chocolate2		:   Raphael.getRGB("#EE7621	"),  // 	238 118 33
-	Chocolate3		:   Raphael.getRGB("#CD661D	"),  // 	205 102 29
-	Chocolate4		:   Raphael.getRGB("#8B4513	"),  // 	139 69 19
-	Firebrick1		:   Raphael.getRGB("#FF3030	"),  // 	255 48 48
-	Firebrick2		:   Raphael.getRGB("#EE2C2C	"),  // 	238 44 44
-	Firebrick3		:   Raphael.getRGB("#CD2626	"),  // 	205 38 38
-	Firebrick4		:   Raphael.getRGB("#8B1A1A	"),  // 	139 26 26
-	Brown1			:   Raphael.getRGB("#FF4040	"),  // 	255 64 64
-	Brown2			:   Raphael.getRGB("#EE3B3B	"),  // 	238 59 59
-	Brown3			:   Raphael.getRGB("#CD3333	"),  // 	205 51 51
-	Brown4			:   Raphael.getRGB("#8B2323	"),  // 	139 35 35
-	Salmon1			:   Raphael.getRGB("#FF8C69	"),  // 	255 140 105
-	Salmon2			:   Raphael.getRGB("#EE8262	"),  // 	238 130 98
-	Salmon3			:   Raphael.getRGB("#CD7054	"),  // 	205 112 84
-	Salmon4			:   Raphael.getRGB("#8B4C39	"),  // 	139 76 57
-	LightSalmon1	:   Raphael.getRGB("#FFA07A	"),  // 	255 160 122
-	LightSalmon2	:   Raphael.getRGB("#EE9572	"),  // 	238 149 114
-	LightSalmon3	:   Raphael.getRGB("#CD8162	"),  // 	205 129 98
-	LightSalmon4	:   Raphael.getRGB("#8B5742	"),  // 	139 87 66
-	Orange1			:   Raphael.getRGB("#FFA500	"),  // 	255 165 0
-	Orange2			:   Raphael.getRGB("#EE9A00	"),  // 	238 154 0
-	Orange3			:   Raphael.getRGB("#CD8500	"),  // 	205 133 0
-	Orange4			:   Raphael.getRGB("#8B5A00	"),  // 	139 90 0
-	DarkOrange1		:   Raphael.getRGB("#FF7F00	"),  // 	255 127 0
-	DarkOrange2		:   Raphael.getRGB("#EE7600	"),  // 	238 118 0
-	DarkOrange3		:   Raphael.getRGB("#CD6600	"),  // 	205 102 0
-	DarkOrange4		:   Raphael.getRGB("#8B4500	"),  // 	139 69 0
-	Coral1			:   Raphael.getRGB("#FF7256	"),  // 	255 114 86
-	Coral2			:   Raphael.getRGB("#EE6A50	"),  // 	238 106 80
-	Coral3			:   Raphael.getRGB("#CD5B45	"),  // 	205 91 69
-	Coral4			:   Raphael.getRGB("#8B3E2F	"),  // 	139 62 47
-	Tomato1			:   Raphael.getRGB("#FF6347	"),  // 	255 99 71
-	Tomato2			:   Raphael.getRGB("#EE5C42	"),  // 	238 92 66
-	Tomato3			:   Raphael.getRGB("#CD4F39	"),  // 	205 79 57
-	Tomato4			:   Raphael.getRGB("#8B3626	"),  // 	139 54 38
-	OrangeRed1		:   Raphael.getRGB("#FF4500	"),  // 	255 69 0
-	OrangeRed2		:   Raphael.getRGB("#EE4000	"),  // 	238 64 0
-	OrangeRed3		:   Raphael.getRGB("#CD3700	"),  // 	205 55 0
-	OrangeRed4		:   Raphael.getRGB("#8B2500	"),  // 	139 37 0
-	Red1			:   Raphael.getRGB("#FF0000	"),  // 	255 0 0
-	Red2			:   Raphael.getRGB("#EE0000	"),  // 	238 0 0
-	Red3			:   Raphael.getRGB("#CD0000	"),  // 	205 0 0
-	Red4			:   Raphael.getRGB("#8B0000	"),  // 	139 0 0
-	DeepPink1		:   Raphael.getRGB("#FF1493	"),  // 	255 20 147
-	DeepPink2		:   Raphael.getRGB("#EE1289	"),  // 	238 18 137
-	DeepPink3		:   Raphael.getRGB("#CD1076	"),  // 	205 16 118
-	DeepPink4		:   Raphael.getRGB("#8B0A50	"),  // 	139 10 80
-	HotPink1		:   Raphael.getRGB("#FF6EB4	"),  // 	255 110 180
-	HotPink2		:   Raphael.getRGB("#EE6AA7	"),  // 	238 106 167
-	HotPink3		:   Raphael.getRGB("#CD6090	"),  // 	205 96 144
-	HotPink4		:   Raphael.getRGB("#8B3A62	"),  // 	139 58 98
-	Pink1			:   Raphael.getRGB("#FFB5C5	"),  // 	255 181 197
-	Pink2			:   Raphael.getRGB("#EEA9B8	"),  // 	238 169 184
-	Pink3			:   Raphael.getRGB("#CD919E	"),  // 	205 145 158
-	Pink4			:   Raphael.getRGB("#8B636C	"),  // 	139 99 108
-	LightPink1		:   Raphael.getRGB("#FFAEB9	"),  // 	255 174 185
-	LightPink2		:   Raphael.getRGB("#EEA2AD	"),  // 	238 162 173
-	LightPink3		:   Raphael.getRGB("#CD8C95	"),  // 	205 140 149
-	LightPink4		:   Raphael.getRGB("#8B5F65	"),  // 	139 95 101
-	PaleVioletRed1	:   Raphael.getRGB("#FF82AB	"),  // 	255 130 171
-	PaleVioletRed2	:   Raphael.getRGB("#EE799F	"),  // 	238 121 159
-	PaleVioletRed3	:   Raphael.getRGB("#CD6889	"),  // 	205 104 137
-	PaleVioletRed4	:   Raphael.getRGB("#8B475D	"),  // 	139 71 93
-	Maroon1			:   Raphael.getRGB("#FF34B3	"),  // 	255 52 179
-	Maroon2			:   Raphael.getRGB("#EE30A7	"),  // 	238 48 167
-	Maroon3			:   Raphael.getRGB("#CD2990	"),  // 	205 41 144
-	Maroon4			:   Raphael.getRGB("#8B1C62	"),  // 	139 28 98
-	VioletRed1		:   Raphael.getRGB("#FF3E96	"),  // 	255 62 150
-	VioletRed2		:   Raphael.getRGB("#EE3A8C	"),  // 	238 58 140
-	VioletRed3		:   Raphael.getRGB("#CD3278	"),  // 	205 50 120
-	VioletRed4		:   Raphael.getRGB("#8B2252	"),  // 	139 34 82
-	Magenta1		:   Raphael.getRGB("#FF00FF	"),  // 	255 0 255
-	Magenta2		:   Raphael.getRGB("#EE00EE	"),  // 	238 0 238
-	Magenta3		:   Raphael.getRGB("#CD00CD	"),  // 	205 0 205
-	Magenta4		:   Raphael.getRGB("#8B008B	"),  // 	139 0 139
-	Orchid1			:   Raphael.getRGB("#FF83FA	"),  // 	255 131 250
-	Orchid2			:   Raphael.getRGB("#EE7AE9	"),  // 	238 122 233
-	Orchid3			:   Raphael.getRGB("#CD69C9	"),  // 	205 105 201
-	Orchid4			:   Raphael.getRGB("#8B4789	"),  // 	139 71 137
-	Plum1			:   Raphael.getRGB("#FFBBFF	"),  // 	255 187 255
-	Plum2			:   Raphael.getRGB("#EEAEEE	"),  // 	238 174 238
-	Plum3			:   Raphael.getRGB("#CD96CD	"),  // 	205 150 205
-	Plum4			:   Raphael.getRGB("#8B668B	"),  // 	139 102 139
-	MediumOrchid1	:   Raphael.getRGB("#E066FF	"),  // 	224 102 255
-	MediumOrchid2	:   Raphael.getRGB("#D15FEE	"),  // 	209 95 238
-	MediumOrchid3	:   Raphael.getRGB("#B452CD	"),  // 	180 82 205
-	MediumOrchid4	:   Raphael.getRGB("#7A378B	"),  // 	122 55 139
-	DarkOrchid1		:   Raphael.getRGB("#BF3EFF	"),  // 	191 62 255
-	DarkOrchid2		:   Raphael.getRGB("#B23AEE	"),  // 	178 58 238
-	DarkOrchid3		:   Raphael.getRGB("#9A32CD	"),  // 	154 50 205
-	DarkOrchid4		:   Raphael.getRGB("#68228B	"),  // 	104 34 139
-	Purple1			:   Raphael.getRGB("#9B30FF	"),  // 	155 48 255
-	Purple2			:   Raphael.getRGB("#912CEE	"),  // 	145 44 238
-	Purple3			:   Raphael.getRGB("#7D26CD	"),  // 	125 38 205
-	Purple4			:   Raphael.getRGB("#551A8B	"),  // 	85 26 139
-	MediumPurple1	:   Raphael.getRGB("#AB82FF	"),  // 	171 130 255
-	MediumPurple2	:   Raphael.getRGB("#9F79EE	"),  // 	159 121 238
-	MediumPurple3	:   Raphael.getRGB("#8968CD	"),  // 	137 104 205
-	MediumPurple4	:   Raphael.getRGB("#5D478B	"),  // 	93 71 139
-	Thistle1		:   Raphael.getRGB("#FFE1FF	"),  // 	255 225 255
-	Thistle2		:   Raphael.getRGB("#EED2EE	"),  // 	238 210 238
-	Thistle3		:   Raphael.getRGB("#CDB5CD	"),  // 	205 181 205
-	Thistle4		:   Raphael.getRGB("#8B7B8B	"),  // 	139 123 139
-	grey11			:   Raphael.getRGB("#1C1C1C	"),  // 	28 28 28
-	grey21			:   Raphael.getRGB("#363636	"),  // 	54 54 54
-	grey31			:   Raphael.getRGB("#4F4F4F	"),  // 	79 79 79
-	grey41			:   Raphael.getRGB("#696969	"),  // 	105 105 105
-	grey51			:   Raphael.getRGB("#828282	"),  // 	130 130 130
-	grey61			:   Raphael.getRGB("#9C9C9C	"),  // 	156 156 156
-	grey71			:   Raphael.getRGB("#B5B5B5	"),  // 	181 181 181
-	gray81			:   Raphael.getRGB("#CFCFCF	"),  // 	207 207 207
-	gray91			:   Raphael.getRGB("#E8E8E8	"),  // 	232 232 232
-	DarkGrey		:   Raphael.getRGB("#A9A9A9	"),  // 	169 169 169
-	DarkBlue		:   Raphael.getRGB("#00008B	"),  // 	0 0 139
-	DarkCyan		:   Raphael.getRGB("#008B8B	"),  // 	0 139 139
-	DarkMagenta		:   Raphael.getRGB("#8B008B	"),  // 	139 0 139
-	DarkRed			:   Raphael.getRGB("#8B0000	"),  // 	139 0 0
-	LightGreen		:   Raphael.getRGB("#90EE90	"),  // 	144 238 144
-
-  
-  
-  get: function(R, G, B){
-	return Raphael.getRGB("rgb(" + R + ", " + G + ", " + B + ")");
-  }
-};

+ 0 - 270
unimall-admin-api/src/main/resources/diagram-viewer/js/LineBreakMeasurer.js

@@ -1,270 +0,0 @@
-/**
- * Word wrapping
- * 
- * @author (Javascript) Dmitry Farafonov
- */
-
-		var AttributedStringIterator = function(text){
-				//this.text = this.rtrim(this.ltrim(text));
-				text = text.replace(/(\s)+/, " ");
-				this.text = this.rtrim(text);
-				/*
-				if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
-					throw new IllegalArgumentException("Invalid substring range");
-				}
-				*/
-				this.beginIndex = 0;
-				this.endIndex = this.text.length;
-				this.currentIndex = this.beginIndex;
-				
-				//console.group("[AttributedStringIterator]");
-				var i = 0;
-				var string = this.text;
-				var fullPos = 0;
-				
-				//console.log("string: \"" + string + "\", length: " + string.length);
-				this.startWordOffsets = [];
-				this.startWordOffsets.push(fullPos);
-				
-				// TODO: remove i 1000
-				while (i<1000) {
-					var pos = string.search(/[ \t\n\f-\.\,]/);
-					if (pos == -1)
-						break;
-					
-					// whitespace start
-					fullPos += pos;
-					string = string.substr(pos);
-					////console.log("fullPos: " + fullPos + ", pos: " + pos +  ", string: ", string);
-					
-					// remove whitespaces
-					var pos = string.search(/[^ \t\n\f-\.\,]/);
-					if (pos == -1)
-						break;
-						
-					// whitespace end
-					fullPos += pos;
-					string = string.substr(pos);
-					
-					////console.log("fullPos: " + fullPos);
-					this.startWordOffsets.push(fullPos);
-					
-					i++;
-				}
-				//console.log("startWordOffsets: ", this.startWordOffsets);
-				//console.groupEnd();
-			};
-			AttributedStringIterator.prototype = {
-				getEndIndex: function(pos){
-					if (typeof(pos) == "undefined")
-						return this.endIndex;
-						
-					var string = this.text.substr(pos, this.endIndex - pos);
-					
-					var posEndOfLine = string.search(/[\n]/);
-					if (posEndOfLine == -1)
-						return this.endIndex;
-					else
-						return pos + posEndOfLine;
-				},
-				getBeginIndex: function(){
-					return this.beginIndex;
-				},
-				isWhitespace: function(pos){
-					var str = this.text[pos];
-					var whitespaceChars = " \t\n\f";
-					
-					return (whitespaceChars.indexOf(str) != -1);
-				},
-				isNewLine: function(pos){
-					var str = this.text[pos];
-					var whitespaceChars = "\n";
-					
-					return (whitespaceChars.indexOf(str) != -1);
-				},
-				preceding: function(pos){
-					//console.group("[AttributedStringIterator.preceding]");
-					for(var i in this.startWordOffsets) {
-						var startWordOffset = this.startWordOffsets[i];
-						if (pos < startWordOffset && i>0) {
-							//console.log("startWordOffset: " + this.startWordOffsets[i-1]);
-							//console.groupEnd();
-							return this.startWordOffsets[i-1];
-						}
-					}
-					//console.log("pos: " + pos);
-					//console.groupEnd();
-					return this.startWordOffsets[i];
-				},
-				following: function(pos){
-					//console.group("[AttributedStringIterator.following]");
-					for(var i in this.startWordOffsets) {
-						var startWordOffset = this.startWordOffsets[i];
-						if (pos < startWordOffset && i>0) {
-							//console.log("startWordOffset: " + this.startWordOffsets[i]);
-							//console.groupEnd();
-							return this.startWordOffsets[i];
-						}
-					}
-					//console.log("pos: " + pos);
-					//console.groupEnd();
-					return this.startWordOffsets[i];
-				},
-				ltrim: function(str){
-					var patt2=/^\s+/g;
-					return str.replace(patt2, "");
-				}, 
-				rtrim: function(str){
-					var patt2=/\s+$/g;
-					return str.replace(patt2, "");
-				},
-				getLayout: function(start, limit){
-					return this.text.substr(start, limit - start);
-				},
-				getCharAtPos: function(pos) {
-					return this.text[pos];
-				}
-			};
-
-		var LineBreakMeasurer = function(paper, x, y, text, fontAttrs){
-				this.paper = paper;
-				this.text = new AttributedStringIterator(text);
-				this.fontAttrs = fontAttrs;
-				
-				if (this.text.getEndIndex() - this.text.getBeginIndex() < 1) {
-					throw {message: "Text must contain at least one character.", code: "IllegalArgumentException"};
-				}
-				
-				//this.measurer = new TextMeasurer(paper, this.text, this.fontAttrs);
-				this.limit = this.text.getEndIndex();
-				this.pos = this.start = this.text.getBeginIndex();
-				
-				this.rafaelTextObject = this.paper.text(x, y, this.text.text).attr(fontAttrs).attr("text-anchor", "start");
-				this.svgTextObject = this.rafaelTextObject[0];
-			};
-			LineBreakMeasurer.prototype = {
-				nextOffset: function(wrappingWidth, offsetLimit, requireNextWord) {
-					//console.group("[nextOffset]");
-					var nextOffset = this.pos;
-					if (this.pos < this.limit) {
-						if (offsetLimit <= this.pos) {
-							throw {message: "offsetLimit must be after current position", code: "IllegalArgumentException"};
-						}
-						
-						var charAtMaxAdvance = this.getLineBreakIndex(this.pos, wrappingWidth);
-						//charAtMaxAdvance --;
-						//console.log("charAtMaxAdvance:", charAtMaxAdvance, ", [" + this.text.getCharAtPos(charAtMaxAdvance) + "]");
-						
-						if (charAtMaxAdvance == this.limit) {
-							nextOffset = this.limit;
-							//console.log("charAtMaxAdvance == this.limit");
-						} else if (this.text.isNewLine(charAtMaxAdvance)) {
-							//console.log("isNewLine");
-							nextOffset = charAtMaxAdvance+1;
-						} else if (this.text.isWhitespace(charAtMaxAdvance)) {
-							// TODO: find next noSpaceChar
-							//return nextOffset;
-							nextOffset = this.text.following(charAtMaxAdvance);
-						} else {
-							// Break is in a word;  back up to previous break.
-							/*
-							var testPos = charAtMaxAdvance + 1;
-							if (testPos == this.limit) {
-								console.error("hbz...");
-							} else {
-								nextOffset = this.text.preceding(charAtMaxAdvance);
-							}
-							*/
-							nextOffset = this.text.preceding(charAtMaxAdvance);
-							
-							if (nextOffset <= this.pos) {
-								nextOffset = Math.max(this.pos+1, charAtMaxAdvance);
-							}
-						}
-					}
-					if (nextOffset > offsetLimit) {
-						nextOffset = offsetLimit;
-					}
-					//console.log("nextOffset: " + nextOffset);
-					//console.groupEnd();
-					return nextOffset;
-				},
-				nextLayout: function(wrappingWidth) {
-					//console.groupCollapsed("[nextLayout]");
-					if (this.pos < this.limit) {
-						var requireNextWord = false;
-						var layoutLimit = this.nextOffset(wrappingWidth, this.limit, requireNextWord);
-						//console.log("layoutLimit:", layoutLimit);
-						if (layoutLimit == this.pos) {
-							//console.groupEnd();
-							return null;
-						}
-						var result = this.text.getLayout(this.pos, layoutLimit);
-						//console.log("layout: \"" + result + "\"");
-						
-						// remove end of line
-						
-						//var posEndOfLine = this.text.getEndIndex(this.pos);
-						//if (posEndOfLine < result.length)
-						//	result = result.substr(0, posEndOfLine);
-						
-						this.pos = layoutLimit;
-						
-						//console.groupEnd();
-						return result;
-					} else {
-						//console.groupEnd();
-						return null;
-					}
-				},
-				getLineBreakIndex: function(pos, wrappingWidth) {
-					//console.group("[getLineBreakIndex]");
-					//console.log("pos:"+pos + ", text: \""+ this.text.text.replace(/\n/g, "_").substr(pos, 1) + "\"");
-					
-					var bb = this.rafaelTextObject.getBBox();
-					
-					var charNum = -1;
-					try {
-						var svgPoint = this.svgTextObject.getStartPositionOfChar(pos);
-						//var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.blue});
-						svgPoint.x = svgPoint.x + wrappingWidth;
-						//svgPoint.y = bb.y;
-						//console.log("svgPoint:", svgPoint);
-					
-						//var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.red});
-					
-						charNum = this.svgTextObject.getCharNumAtPosition(svgPoint);
-					} catch (e){
-						console.warn("getStartPositionOfChar error, pos:" + pos);
-						/*
-						var testPos = pos + 1;
-						if (testPos < this.limit) {
-							return testPos
-						}
-						*/
-					}
-					//console.log("charNum:", charNum);
-					if (charNum == -1) {
-						//console.groupEnd();
-						return this.text.getEndIndex(pos);
-					} else {
-						// When case there is new line between pos and charnum then use this new line
-						var newLineIndex = this.text.getEndIndex(pos);
-						if (newLineIndex < charNum ) {
-							console.log("newLineIndex <= charNum, newLineIndex:"+newLineIndex+", charNum:"+charNum, "\"" + this.text.text.substr(newLineIndex+1).replace(/\n/g, "?") + "\"");
-							//console.groupEnd();
-							
-							return newLineIndex;
-						}
-							
-						//var charAtMaxAdvance  = this.text.text.substring(charNum, charNum + 1);
-						var charAtMaxAdvance  = this.text.getCharAtPos(charNum);
-						//console.log("!!charAtMaxAdvance: " + charAtMaxAdvance);
-						//console.groupEnd();
-						return charNum;
-					}
-				}, 
-				getPosition: function() {
-					return this.pos;
-				}
-			};

+ 0 - 387
unimall-admin-api/src/main/resources/diagram-viewer/js/Polyline.js

@@ -1,387 +0,0 @@
-/**
- * Class to generate polyline
- *
- * @author Dmitry Farafonov
- */
- 
-var ANCHOR_TYPE= {
-	main: "main",
-	middle: "middle",
-	first: "first",
-	last: "last"
-};
-
-function Anchor(uuid, type, x, y) {
-	this.uuid = uuid; 
-	this.x = x
-	this.y = y
-	this.type = (type == ANCHOR_TYPE.middle) ? ANCHOR_TYPE.middle : ANCHOR_TYPE.main;
-};
-Anchor.prototype = {
-	uuid: null,
-	x: 0,
-	y: 0,
-	type: ANCHOR_TYPE.main,
-	isFirst: false,
-	isLast: false,
-	ndex: 0,
-	typeIndex: 0
-};
-
-function Polyline(uuid, points, strokeWidth) {
-	/* Array on coordinates:
-	 * points: [{x: 410, y: 110}, 1
-	 *			{x: 570, y: 110}, 1 2
-	 *			{x: 620, y: 240},   2 3
-	 *			{x: 750, y: 270},     3 4
-	 *			{x: 650, y: 370}];      4
-	 */
-	this.points = points;
-	
-	/*
-	 * path for graph
-	 * [["M", x1, y1], ["L", x2, y2], ["C", ax, ay, bx, by, x3, y3], ["L", x3, y3]]
-	 */
-	this.path = [];
-	
-	this.anchors = [];
-	
-	if (strokeWidth) this.strokeWidth = strokeWidth;
-	
-	this.closePath = false;
-	
-	this.init();
-};
-
-Polyline.prototype = {
-	id: null,
-	points: [],
-	path: [],
-	anchors: [],
-	strokeWidth: 1,
-	radius: 15,
-	showDetails: false,
-	element: null,
-	isDefaultConditionAvailable: false,
-	closePath: false,
-	
-	init: function(points){
-		var linesCount = this.getLinesCount();
-		if (linesCount < 1)
-			return;
-			
-		this.normalizeCoordinates();
-		
-		// create anchors
-		
-		this.pushAnchor(ANCHOR_TYPE.first, this.getLine(0).x1, this.getLine(0).y1);
-		
-		for(var i = 1; i < linesCount; i++){
-			var line1 = this.getLine(i-1),
-				line2 = this.getLine(i);
-			
-			//this.pushAnchor(ANCHOR_TYPE.middle, line1.x1 + line1.x2-line1.x1, line1.y1 + line1.y2-line1.y1);
-			this.pushAnchor(ANCHOR_TYPE.main,  line1.x2, line1.y2);
-			//this.pushAnchor(ANCHOR_TYPE.middle,  line2.x1 + line2.x2-line2.x1, line2.y1 + line2.y2-line2.y1);
-		}
-		
-		this.pushAnchor(ANCHOR_TYPE.last, this.getLine(linesCount-1).x2, this.getLine(linesCount-1).y2);
-		
-		this.rebuildPath();
-	},
-	
-	normalizeCoordinates: function(){
-		for(var i=0; i < this.points.length; i++){
-			this.points[i].x = parseFloat(this.points[i].x);
-			this.points[i].y = parseFloat(this.points[i].y);
-		}
-	},
-	
-	getLinesCount: function(){
-		return this.points.length-1;
-	},
-	_getLine: function(i){
-		return {x1: this.points[i].x, y1: this.points[i].y, x2: this.points[i+1].x, y2: this.points[i+1].y};
-	},
-	getLine: function(i){
-		var line = this._getLine(i);
-		line.angle = this.getLineAngle(i) ;
-		return line;
-	},
-	getLineAngle: function(i){
-		var line = this._getLine(i);
-		return Math.atan2(line.y2 - line.y1, line.x2 - line.x1);
-	},
-	getLineLengthX: function(i){
-		var line = this.getLine(i);
-		return (line.x2 - line.x1);
-	},
-	getLineLengthY: function(i){
-		var line = this.getLine(i);
-		return (line.y2 - line.y1);
-	},
-	getLineLength: function(i){
-		var line = this.getLine(i);
-		return Math.sqrt(Math.pow(this.getLineLengthX(i), 2) + Math.pow(this.getLineLengthY(i), 2));
-	},
-	
-	getAnchors: function(){
-		// âåðíóòü îòñîðòèðîâàííûé ìàññèâ
-		// ????
-		return this.anchors;
-	},
-	getAnchorsCount: function(type){
-		if (!type)
-			return this.anchors.length;
-		else {
-			var count = 0;
-			for(var i=0; i < this.getAnchorsCount(); i++){
-				var anchor = this.anchors[i];
-				if (anchor.getType() == type) {
-					count++;
-				}
-			}
-			return count;
-		}
-	},
-	
-	pushAnchor: function(type, x, y, index){
-		if (type == ANCHOR_TYPE.first) {
-			index = 0;
-			typeIndex = 0;
-		} else if (type == ANCHOR_TYPE.last) {
-			index = this.getAnchorsCount();
-			typeIndex = 0;
-		} else if (!index) {
-			index = this.anchors.length;
-		} else {
-			// ïåðåáðàòü anchors, ñäâèíóòü ïîçèöèþ äëÿ êàæäîãî, íà÷èíàÿ ñ index
-			//var anchor = this.getAnchor()
-			for(var i=0; i < this.getAnchorsCount(); i++){
-				var anchor = this.anchors[i];
-				if (anchor.index > index) {
-					anchor.index++;
-					anchor.typeIndex++;
-				}
-			}
-		}
-		
-		var anchor = new Anchor(this.id, ANCHOR_TYPE.main, x, y, index, typeIndex);
-		
-		this.anchors.push(anchor);
-	},
-	
-	getAnchor: function(position){
-		return this.anchors[position];
-	},
-	
-	getAnchorByType: function(type, position){
-		if (type == ANCHOR_TYPE.first)
-			return this.anchors[0];
-		if (type == ANCHOR_TYPE.last)
-			return this.anchors[this.getAnchorsCount()-1];
-		
-		for(var i=0; i < this.getAnchorsCount(); i++){
-			var anchor = this.anchors[i];
-			if (anchor.type == type) {
-				if( position == anchor.position)
-					return anchor;
-			}
-		}
-		return null;
-	},
-	
-	addNewPoint: function(position, x, y){
-		// 
-		for(var i = 0; i < this.getLinesCount(); i++){
-			var line = this.getLine(i);
-			if (x > line.x1 && x < line.x2 && y > line.y1 && y < line.y2) {
-				this.points.splice(i+1,0,{x: x, y: y});
-				break;
-			}
-		}
-		
-		this.rebuildPath();
-	},
-	
-	rebuildPath: function(){
-		var path = [];
-		
-		for(var i = 0; i < this.getAnchorsCount(); i++){
-			var anchor = this.getAnchor(i);
-			
-			var pathType = ""
-			if (i==0)
-				pathType = "M";
-			else 
-				pathType = "L";
-			
-// TODO: save previous points and calculate new path just if points are updated, and then save currents values as previous
-			
-			var targetX = anchor.x, targetY = anchor.y;
-			if (i>0 && i < this.getAnchorsCount()-1) {
-				// get new x,y
-				var cx = anchor.x, cy = anchor.y;
-				
-				// pivot point of prev line
-				var AO = this.getLineLength(i-1);
-				if (AO < this.radius) {
-					AO = this.radius;
-				}
-				
-				this.isDefaultConditionAvailable = (this.isDefaultConditionAvailable || (i == 1 && AO > 10));
-				//console.log("isDefaultConditionAvailable", this.isDefaultConditionAvailable);
-				
-				var ED = this.getLineLengthY(i-1) * this.radius / AO;
-				var OD = this.getLineLengthX(i-1) * this.radius / AO;
-					targetX = anchor.x - OD;
-					targetY = anchor.y - ED;
-				
-				if (AO < 2*this.radius && i>1) {
-					targetX = anchor.x - this.getLineLengthX(i-1)/2;
-					targetY = anchor.y - this.getLineLengthY(i-1)/2;;
-				}
-					
-				// pivot point of next line
-				var AO = this.getLineLength(i);
-				if (AO < this.radius) {
-					AO = this.radius;
-				}
-				var ED = this.getLineLengthY(i) * this.radius / AO;
-				var OD = this.getLineLengthX(i) * this.radius / AO;
-					var nextSrcX = anchor.x + OD;
-					var nextSrcY = anchor.y + ED;
-					
-				if (AO < 2*this.radius && i<this.getAnchorsCount()-2) {
-					nextSrcX = anchor.x + this.getLineLengthX(i)/2;
-					nextSrcY = anchor.y + this.getLineLengthY(i)/2;;
-				}
-					
-				
-				var dx0 = (cx - targetX) / 3,
-					dy0 = (cy - targetY) / 3,
-					ax = cx - dx0,
-					ay = cy - dy0,
-					
-					dx1 = (cx - nextSrcX) / 3,
-					dy1 = (cy - nextSrcY) / 3,
-					bx = cx - dx1,
-					by = cy - dy1,
-					
-					zx=nextSrcX, zy=nextSrcY;
-					
-				if (this.showDetails) {
-					var c = ProcessDiagramCanvas.g.path("M"+targetX+","+targetY+"L"+ax+","+ay).attr({stroke: Color.get(255, 153, 51), "stroke-dasharray": "- "});
-					var c = ProcessDiagramCanvas.g.path("M"+nextSrcX+","+nextSrcY+"L"+bx+","+by).attr({stroke: Color.get(255, 153, 51), "stroke-dasharray": "- "});
-					var c = ProcessDiagramCanvas.g.ellipse(ax, ay, 2, 2).attr({stroke: Color.SlateGrey});
-					var c = ProcessDiagramCanvas.g.ellipse(bx, by, 2, 2).attr({stroke: Color.SlateGrey});
-					var c = ProcessDiagramCanvas.g.ellipse(cx, cy, this.radius, this.radius).attr({stroke: Color.Gainsboro});
-					var c = ProcessDiagramCanvas.g.ellipse(targetX, targetY, 2, 2).attr({fill: Color.red});
-					var c = ProcessDiagramCanvas.g.ellipse(nextSrcX, nextSrcY, 2, 2).attr({fill: Color.red});
-				}
-			} else if (i==1 && this.getAnchorsCount() == 2){
-				var AO = this.getLineLength(i-1);
-				if (AO < this.radius) {
-					AO = this.radius;
-				}
-				this.isDefaultConditionAvailable = (this.isDefaultConditionAvailable || (i == 1 && AO > 10));
-				//console.log("-- isDefaultConditionAvailable", this.isDefaultConditionAvailable);
-			}
-
-			// anti smoothing
-			if (this.strokeWidth%2 == 1) {
-				targetX += 0.5;
-				targetY += 0.5;
-			}
-			
-			path.push([pathType, targetX, targetY]);
-			
-			if (i>0 && i < this.getAnchorsCount()-1) {
-				path.push(["C", ax, ay, bx, by, zx, zy]);
-			}
-		}
-		
-		if (this.closePath) {
-			console.log("closePath:", this.closePath);
-			path.push(["Z"]);
-		}
-		
-		this.path = path;
-	},
-	
-	transform: function(transformation){
-		this.element.transform(transformation);
-	},
-	attr: function(attrs){
-		//console.log("attrs: " +attrs, "", this.element);
-		// TODO: foreach and set each
-		this.element.attr(attrs);
-	}
-};
-
-function Polygone(points, strokeWidth) {
-	/* Array on coordinates:
-	 * points: [{x: 410, y: 110}, 1
-	 *			{x: 570, y: 110}, 1 2
-	 *			{x: 620, y: 240},   2 3
-	 *			{x: 750, y: 270},     3 4
-	 *			{x: 650, y: 370}];      4
-	 */
-	this.points = points;
-	
-	/*
-	 * path for graph
-	 * [["M", x1, y1], ["L", x2, y2], ["C", ax, ay, bx, by, x3, y3], ["L", x3, y3]]
-	 */
-	this.path = [];
-	
-	this.anchors = [];
-	
-	if (strokeWidth) this.strokeWidth = strokeWidth;
-	
-	this.closePath = true;
-	this.init();
-};
-
-
-/*
- * Poligone is inherited from Poliline: draws closedPath of polyline
- */
-
-var Foo = function () { };
-Foo.prototype = Polyline.prototype;
-
-Polygone.prototype = new Foo();
-
-Polygone.prototype.rebuildPath = function(){
-	var path = [];
-	//console.log("Polygone rebuildPath");
-	for(var i = 0; i < this.getAnchorsCount(); i++){
-		var anchor = this.getAnchor(i);
-		
-		var pathType = ""
-		if (i==0)
-			pathType = "M";
-		else 
-			pathType = "L";
-		
-		var targetX = anchor.x, targetY = anchor.y;
-		
-		// anti smoothing
-		if (this.strokeWidth%2 == 1) {
-			targetX += 0.5;
-			targetY += 0.5;
-		}
-		
-		path.push([pathType, targetX, targetY]);	
-	}
-	if (this.closePath)
-		path.push(["Z"]);
-	
-	this.path = path;
-};
-/*
-Polygone.prototype.transform = function(transformation){
-	this.element.transform(transformation);
-};
-*/

+ 0 - 2172
unimall-admin-api/src/main/resources/diagram-viewer/js/ProcessDiagramCanvas.js

@@ -1,2172 +0,0 @@
-/**
- * Represents a canvas on which BPMN 2.0 constructs can be drawn.
- * 
- * Some of the icons used are licenced under a Creative Commons Attribution 2.5
- * License, see http://www.famfamfam.com/lab/icons/silk/
- * 
- * @see ProcessDiagramGenerator
- * @author (Java) Joram Barrez
- * @author (Javascript) Dmitry Farafonov
- */
- 
-//Color.Cornsilk
-
-var ARROW_HEAD_SIMPLE = "simple";
-var ARROW_HEAD_EMPTY = "empty";
-var ARROW_HEAD_FILL = "FILL";
-var MULTILINE_VERTICAL_ALIGN_TOP = "top";
-var MULTILINE_VERTICAL_ALIGN_MIDDLE = "middle";
-var MULTILINE_VERTICAL_ALIGN_BOTTOM = "bottom";
-var MULTILINE_HORIZONTAL_ALIGN_LEFT = "start";
-var MULTILINE_HORIZONTAL_ALIGN_MIDDLE = "middle";
-var MULTILINE_HORIZONTAL_ALIGN_RIGHT = "end";
-
-// Predefined sized
-var TEXT_PADDING = 3;
-var ARROW_WIDTH = 4;
-var CONDITIONAL_INDICATOR_WIDTH = 16;
-var MARKER_WIDTH = 12;
-var ANNOTATION_TEXT_PADDING = 7;
-
-// Colors
-var TASK_COLOR = Color.OldLace; // original: Color.get(255, 255, 204);
-var TASK_STROKE_COLOR = Color.black; /*Color.SlateGrey; */
-//var EXPANDED_SUBPROCESS_ATTRS = Color.black; /*Color.SlateGrey; */
-var BOUNDARY_EVENT_COLOR = Color.white;
-var CONDITIONAL_INDICATOR_COLOR = Color.get(255, 255, 255);
-var HIGHLIGHT_COLOR = Color.Firebrick1;
-//var SEQUENCEFLOW_COLOR = Color.DimGrey;
-var SEQUENCEFLOW_COLOR = Color.black;
-
-var CATCHING_EVENT_COLOR = Color.black; /* Color.SlateGrey; */
-var START_EVENT_COLOR = Color.get(251,251,251);
-var START_EVENT_STROKE_COLOR = Color.black; /* Color.SlateGrey; */
-var END_EVENT_COLOR = Color.get(251,251,251);
-//var END_EVENT_STROKE_COLOR = Color.black;
-var NONE_END_EVENT_COLOR = Color.Firebrick4;
-var NONE_END_EVENT_STROKE_COLOR = Color.Firebrick4;
-var ERROR_END_EVENT_COLOR = Color.Firebrick;
-var ERROR_END_EVENT_STROKE_COLOR = Color.Firebrick;
-//var LABEL_COLOR = Color.get(112, 146, 190);
-var LABEL_COLOR = Color.get(72, 106, 150);
-
-// Fonts
-var NORMAL_FONT = {font: "10px Arial", opacity: 1, fill: Color.black};
-var LABEL_FONT = {font: "11px Arial", "font-style":"italic", opacity: 1, "fill": LABEL_COLOR};
-var LABEL_FONT_SMOOTH = {font: "10px Arial", "font-style":"italic", opacity: 1, "fill": LABEL_COLOR, stroke: LABEL_COLOR, "stroke-width":.4};
-var TASK_FONT = {font: "11px Arial", opacity: 1, fill: Color.black};
-var TASK_FONT_SMOOTH = {font: "11px Arial", opacity: 1, fill: Color.black, stroke: LABEL_COLOR, "stroke-width":.4};
-var POOL_LANE_FONT = {font: "11px Arial", opacity: 1, fill: Color.black};
-var EXPANDED_SUBPROCESS_FONT = {font: "11px Arial", opacity: 1, fill: Color.black};
-
-// Strokes
-var NORMAL_STROKE = 1;
-var SEQUENCEFLOW_STROKE = 1.5;
-var SEQUENCEFLOW_HIGHLIGHT_STROKE = 2;
-var THICK_TASK_BORDER_STROKE = 2.5;
-var GATEWAY_TYPE_STROKE = 3.2;
-var END_EVENT_STROKE = NORMAL_STROKE+2;
-var MULTI_INSTANCE_STROKE = 1.3;
-var EVENT_SUBPROCESS_ATTRS = 	{"stroke": Color.black, "stroke-width": NORMAL_STROKE, "stroke-dasharray": ". "};
-//var EXPANDED_SUBPROCESS_ATTRS = {"stroke": Color.black, "stroke-width": NORMAL_STROKE, "fill": Color.FloralWhite};
-var EXPANDED_SUBPROCESS_ATTRS = {"stroke": Color.black, "stroke-width": NORMAL_STROKE, "fill": Color.WhiteSmoke};
-var NON_INTERRUPTING_EVENT_STROKE = "- ";
-
-var TASK_CORNER_ROUND = 10;
-var EXPANDED_SUBPROCESS_CORNER_ROUND = 10;
-
-// icons
-var ICON_SIZE = 16;
-var ICON_PADDING = 4;
-var USERTASK_IMAGE = 		"images/deployer/user.png";
-var SCRIPTTASK_IMAGE = 		"images/deployer/script.png";
-var SERVICETASK_IMAGE = 	"images/deployer/service.png";
-var RECEIVETASK_IMAGE = 	"images/deployer/receive.png";
-var SENDTASK_IMAGE = 		"images/deployer/send.png";
-var MANUALTASK_IMAGE = 		"images/deployer/manual.png";
-var BUSINESS_RULE_TASK_IMAGE = "images/deployer/business_rule.png";
-var TIMER_IMAGE = 			"images/deployer/timer.png";
-var MESSAGE_CATCH_IMAGE = 	"images/deployer/message_catch.png";
-var MESSAGE_THROW_IMAGE = 	"images/deployer/message_throw.png";
-var ERROR_THROW_IMAGE = 	"images/deployer/error_throw.png";
-var ERROR_CATCH_IMAGE = 	"images/deployer/error_catch.png";
-var SIGNAL_CATCH_IMAGE = 	"images/deployer/signal_catch.png";
-var SIGNAL_THROW_IMAGE = 	"images/deployer/signal_throw.png";
-var MULTIPLE_CATCH_IMAGE = 	"images/deployer/multiple_catch.png";
-
-
-var ObjectType = {
-	ELLIPSE: "ellipse",
-	FLOW: "flow",
-	RECT: "rect",
-	RHOMBUS: "rhombus"
-};
-
-function OBJ(type){
-	this.c = null;
-	this.type = type;
-	this.nestedElements = [];
-};
-OBJ.prototype = {
-	
-};
-
-var CONNECTION_TYPE = {
-	SEQUENCE_FLOW: "sequence_flow",
-	MESSAGE_FLOW: "message_flow",
-	ASSOCIATION: "association"
-};
-
-var ProcessDiagramCanvas = function(){
-};
-ProcessDiagramCanvas.prototype = {
-// var DefaultProcessDiagramCanvas = {
-	canvasHolder: "holder",
-	canvasWidth: 0, 
-	canvasHeight: 0,
-	paint: Color.black,
-	strokeWidth: 0,
-	font: null,
-	fontSmoothing: null,
-	
-	g: null,
-	ninjaPaper: null,
-	
-	objects: [],
-	
-	processDefinitionId: null,
-	activity: null,
-	
-	frame: null,
-	
-	
-	debug: false,
-	
-	/**
-	* Creates an empty canvas with given width and height.
-	*/
-	init: function(width, height, processDefinitionId){
-		this.canvasWidth = width;
-		this.canvasHeight = height;
-		
-		// TODO: name it as 'canvasName'
-		if (!processDefinitionId)
-			processDefinitionId = "holder";
-		
-		this.processDefinitionId = processDefinitionId;
-		this.canvasHolder = this.processDefinitionId;
-
-		var h = document.getElementById(this.canvasHolder);
-		if (!h) return;
-		
-		h.style.width = this.canvasWidth;
-		h.style.height = this.canvasHeight;
-		
-		this.g = Raphael(this.canvasHolder);
-		this.g.clear();
-	
-		//this.setPaint(Color.DimGrey);
-		this.setPaint(Color.black);
-		//this.setPaint(Color.white);
-		this.setStroke(NORMAL_STROKE);
-		
-		//this.setFont("Arial", 11);
-		this.setFont(NORMAL_FONT);
-		//this.font = this.g.getFont("Arial");
-		
-		this.fontSmoothing = true;
-		
-		// ninja!
-		var RaphaelOriginal = Raphael;
-		this.ninjaPaper =(function (local_raphael) {
-			var paper = local_raphael(1, 1, 1, 1, processDefinitionId);
-			return paper;
-		})(Raphael.ninja());
-		Raphael = RaphaelOriginal;
-	},
-	setPaint: function(color){
-		this.paint = color;
-	},
-	getPaint: function(){
-		return this.paint;
-	},
-	setStroke: function(strokeWidth){
-		this.strokeWidth = strokeWidth;
-	},
-	getStroke: function(){
-		return this.strokeWidth;
-	},
-	/*
-	setFont: function(family, weight, style, stretch){
-		this.font = this.g.getFont(family, weight);
-	},
-	*/
-	setFont: function(font){
-		this.font = font;
-	},
-	getFont: function(){
-		return this.font;
-	},
-	drawShaddow: function(object){
-		var border = object.clone();
-		border.attr({"stroke-width": this.strokeWidth + 6, 
-					"stroke": Color.white,
-					"fill": Color.white,
-					"opacity": 1,
-					"stroke-dasharray":null});
-		//border.toBack();
-		object.toFront();
-		
-		return border;
-	},
-	
-	setConextObject: function(obj){
-		this.contextObject = obj;
-	},
-	getConextObject: function(){
-		return this.contextObject;
-	},
-	setContextToElement: function(object){
-		var contextObject = this.getConextObject();
-		object.id = contextObject.id;
-		object.data("contextObject", contextObject);
-	},
-	onClick: function(event, instance, element){
-	  var overlay = element;
-	  var set = overlay.data("set");
-	  var contextObject = overlay.data("contextObject");
-	  //console.log("["+contextObject.getProperty("type")+"], activityId: " + contextObject.getId());
-	  if (ProcessDiagramGenerator.options && ProcessDiagramGenerator.options.on && ProcessDiagramGenerator.options.on.click) {
-	    var args = [instance, element, contextObject];
-	    ProcessDiagramGenerator.options.on.click.apply(event, args);
-	  }
-	},
-	onRightClick: function(event, instance, element){
-	  var overlay = element;
-	  var set = overlay.data("set");
-	  var contextObject = overlay.data("contextObject");
-	  //console.log("[%s], activityId: %s (RIGHTCLICK)", contextObject.getProperty("type"), contextObject.getId());
-
-	  if (ProcessDiagramGenerator.options && ProcessDiagramGenerator.options.on && ProcessDiagramGenerator.options.on.rightClick) {
-	    var args = [instance, element, contextObject];
-	    ProcessDiagramGenerator.options.on.rightClick.apply(event, args);
-	  }
-	},
-	onHoverIn: function(event, instance, element){
-	  var overlay = element;
-	  var set = overlay.data("set");
-	  var contextObject = overlay.data("contextObject");
-
-	  var border = instance.g.getById(contextObject.id + "_border");
-	  border.attr("opacity", 0.3);
-
-	  // provide callback
-	  if (ProcessDiagramGenerator.options && ProcessDiagramGenerator.options.on && ProcessDiagramGenerator.options.on.over) {
-	    var args = [instance, element, contextObject];
-	    ProcessDiagramGenerator.options.on.over.apply(event, args);
-	  }
-	 },
-	 onHoverOut: function(event, instance, element){
-	   var overlay = element;
-	   var set = overlay.data("set");
-	   var contextObject = overlay.data("contextObject");
-
-	   var border = instance.g.getById(contextObject.id + "_border");
-	   border.attr("opacity", 0.0);
-	   // provide callback
-	   if (ProcessDiagramGenerator.options && ProcessDiagramGenerator.options.on && ProcessDiagramGenerator.options.on.out) {
-	     var args = [instance, element, contextObject];
-	     ProcessDiagramGenerator.options.on.out.apply(event, args);
-	   }
-	 },
-	 addHandlers: function(set, x, y, width, height, type){
-	   var contextObject = this.getConextObject();
-
-	   var cx = x+width/2, cy = y+height/2;
-	   if (type == "event") {
-	     var border = this.g.ellipse(cx, cy, width/2+4, height/2+4);
-	     var overlay = this.g.ellipse(cx, cy, width/2, height/2);
-	   } else if (type == "gateway") {
-	     // rhombus
-	     var border = this.g.path( "M" + (x - 4) + " " + (y + (height / 2)) +
-	         "L" + (x + (width / 2)) + " " + (y + height + 4) +
-	         "L" + (x + width + 4) + " " + (y + (height / 2)) +
-	         "L" + (x + (width / 2)) + " " + (y - 4) +
-	         "z" );
-	     var overlay = this.g.path(  "M" + x + " " + (y + (height / 2)) +
-	         "L" + (x + (width / 2)) + " " + (y + height) +
-	         "L" + (x + width) + " " + (y + (height / 2)) +
-	         "L" + (x + (width / 2)) + " " + y +
-	         "z" );
-	   } else if (type == "task") {
-	     var border = this.g.rect(x - 4, y - 4, width+9, height+9, TASK_CORNER_ROUND+4);
-	     var overlay = this.g.rect(x, y, width, height, TASK_CORNER_ROUND);
-	   }
-
-	   border.attr({stroke: Color.get(132,112,255)/*Color.Tan1*/,"stroke-width": 4, opacity: 0.0});
-	   border.id = contextObject.id + "_border";
-
-	   set.push(border);
-
-	   overlay.attr({stroke: Color.Orange,"stroke-width": 3, fill: Color.get(0,0,0), opacity: 0.0, cursor: "hand"});
-	   overlay.data("set",set);
-	   overlay.id = contextObject.id;
-	   overlay.data("contextObject",contextObject);
-
-	   var instance = this;
-	   overlay.mousedown(function(event){if (event.button == 2) instance.onRightClick(event, instance, this);});
-	   overlay.click(function(event){instance.onClick(event, instance, this);});
-	   overlay.hover(function(event){instance.onHoverIn(event, instance, this);}, function(event){instance.onHoverOut(event, instance, this);});
-	 },
-	
-	/*
-	 * Start Events:
-	 * 
-	 *	drawNoneStartEvent
-	 *	drawTimerStartEvent
-	 *	drawMessageStartEvent
-	 *	drawErrorStartEvent
-	 *	drawSignalStartEvent
-	 *	_drawStartEventImage
-	 *	_drawStartEvent
-	 */
-	 
-	drawNoneStartEvent: function(x, y, width, height) {
-	  this.g.setStart();
-	  
-		var isInterrupting = undefined;
-		this._drawStartEvent(x, y, width, height, isInterrupting, null);
-		
-		var set = this.g.setFinish();
-		this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawTimerStartEvent: function(x, y, width, height, isInterrupting, name) {
-	  this.g.setStart();
-	  
-		this._drawStartEvent(x, y, width, height, isInterrupting, null);
-		
-		var cx = x + width/2 - this.getStroke()/4;
-		var cy = y + height/2 - this.getStroke()/4;
-		
-		var w = width*.9;// - this.getStroke()*2;
-		var h = height*.9;// - this.getStroke()*2;
-		
-		this._drawClock(cx, cy, w, h);
-		
-		if (this.gebug)
-			var center = this.g.ellipse(cx, cy, 3, 3).attr({stroke:"none", fill: Color.green});
-		
-		var set = this.g.setFinish();
-		this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawMessageStartEvent: function(x, y, width, height, isInterrupting, name) {
-	  this.g.setStart();
-	  
-		this._drawStartEvent(x, y, width, height, isInterrupting, null);
-		
-		this._drawStartEventImage(x, y, width, height, MESSAGE_CATCH_IMAGE);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawErrorStartEvent: function(x, y, width, height, name) {
-	  this.g.setStart();
-		var isInterrupting = undefined;
-		this._drawStartEvent(x, y, width, height, isInterrupting);
-
-		this._drawStartEventImage(x, y, width, height, ERROR_CATCH_IMAGE);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawSignalStartEvent: function(x, y, width, height, isInterrupting, name) {
-	  this.g.setStart();
-		this._drawStartEvent(x, y, width, height, isInterrupting, null);
-		
-		this._drawStartEventImage(x, y, width, height, SIGNAL_CATCH_IMAGE);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawMultipleStartEvent: function(x, y, width, height, isInterrupting, name) {
-	  this.g.setStart();
-		
-	  this._drawStartEvent(x, y, width, height, isInterrupting, null);
-		
-		var cx = x + width/2 - this.getStroke()/4;
-		var cy = y + height/2 - this.getStroke()/4;
-		
-		var w = width*1;
-		var h = height*1;
-		
-		this._drawPentagon(cx, cy, w, h);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	_drawStartEventImage: function(x, y, width, height, image){
-		var cx = x + width/2 - this.getStroke()/2;
-		var cy = y + height/2 - this.getStroke()/2;
-		
-		var w = width*.65;// - this.getStroke()*2;
-		var h = height*.65;// - this.getStroke()*2;
-		
-		var img = this.g.image(image, cx-w/2, cy-h/2, w, h);
-	},
-	_drawStartEvent: function(x, y, width, height, isInterrupting){
-		var originalPaint = this.getPaint();
-		if (typeof(START_EVENT_STROKE_COLOR) != "undefined")
-			this.setPaint(START_EVENT_STROKE_COLOR);
-		
-		
-		width -= this.strokeWidth / 2;
-		height -= this.strokeWidth / 2;
-		
-		x = x + width/2;
-		y = y + height/2;
-		
-		var circle = this.g.ellipse(x, y, width/2, height/2);
-		
-		circle.attr({"stroke-width": this.strokeWidth, 
-				"stroke": this.paint, 
-				//"stroke": START_EVENT_STROKE_COLOR,
-				"fill": START_EVENT_COLOR});
-				
-		// white shaddow
-		this.drawShaddow(circle);
-		
-		if (isInterrupting!=null && isInterrupting!=undefined && !isInterrupting) 
-			circle.attr({"stroke-dasharray": NON_INTERRUPTING_EVENT_STROKE});
-
-		this.setContextToElement(circle);
-		
-		
-		this.setPaint(originalPaint);
-	},
-	
-	/*
-	 * End Events:
-	 * 
-	 *	drawNoneEndEvent
-	 *	drawErrorEndEvent
-	 *	drawMessageEndEvent
-	 *	drawSignalEndEvent
-	 *	drawMultipleEndEvent
-	 *  _drawEndEventImage
-	 *	_drawNoneEndEvent
-	 */
-	 
-	drawNoneEndEvent: function(x, y, width, height) {
-	  this.g.setStart();
-	  
-		this._drawNoneEndEvent(x, y, width, height, null, "noneEndEvent");
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawErrorEndEvent: function(x, y, width, height) {
-	  this.g.setStart();
-		var type = "errorEndEvent";
-		this._drawNoneEndEvent(x, y, width, height, null, type);
-		
-		this._drawEndEventImage(x, y, width, height, ERROR_THROW_IMAGE);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawMessageEndEvent: function(x, y, width, height, name) {
-	  this.g.setStart();
-		var type = "errorEndEvent";
-		this._drawNoneEndEvent(x, y, width, height, null, type);
-		
-		this._drawEndEventImage(x, y, width, height, MESSAGE_THROW_IMAGE);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawSignalEndEvent: function(x, y, width, height, name) {
-	  this.g.setStart();
-		var type = "errorEndEvent";
-		this._drawNoneEndEvent(x, y, width, height, null, type);
-		
-		this._drawEndEventImage(x, y, width, height, SIGNAL_THROW_IMAGE);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawMultipleEndEvent: function(x, y, width, height, name) {
-	  this.g.setStart();
-		var type = "errorEndEvent";
-		this._drawNoneEndEvent(x, y, width, height, null, type);
-		
-		var cx = x + width/2;// - this.getStroke();
-		var cy = y + height/2;// - this.getStroke();
-		
-		var w = width*1;
-		var h = height*1;
-		
-		var filled = true;
-		this._drawPentagon(cx, cy, w, h, filled);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawTerminateEndEvent: function(x, y, width, height) {
-	  this.g.setStart();
-		var type = "errorEndEvent";
-		this._drawNoneEndEvent(x, y, width, height, null, type);
-		
-		var cx = x + width/2;// - this.getStroke()/2;
-		var cy = y + height/2;// - this.getStroke()/2;
-		
-		var w = width/2*.6;
-		var h = height/2*.6;
-		
-		var circle = this.g.ellipse(cx, cy, w, h).attr({fill: Color.black});
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	_drawEndEventImage: function(x, y, width, height, image){
-		var cx = x + width/2 - this.getStroke()/2;
-		var cy = y + height/2 - this.getStroke()/2;
-		
-		var w = width*.65;
-		var h = height*.65;
-		
-		var img = this.g.image(image, cx-w/2, cy-h/2, w, h);
-	},
-	
-	_drawNoneEndEvent: function(x, y, width, height, image, type) {
-		var originalPaint = this.getPaint();
-		if (typeof(CATCHING_EVENT_COLOR) != "undefined")
-			this.setPaint(CATCHING_EVENT_COLOR);
-			
-		var strokeColor = this.getPaint();
-		var fillColor = this.getPaint();
-		
-		if (type == "errorEndEvent") {
-			strokeColor = ERROR_END_EVENT_STROKE_COLOR;
-			fillColor = ERROR_END_EVENT_COLOR;
-		} else if (type == "noneEndEvent") {
-			strokeColor = NONE_END_EVENT_STROKE_COLOR;
-			fillColor = NONE_END_EVENT_COLOR;
-		} else 
-			
-		// event circles
-		width -= this.strokeWidth / 2;
-		height -= this.strokeWidth / 2;
-		
-		x = x + width/2;// + this.strokeWidth/2;
-		y = y + width/2;// + this.strokeWidth/2;
-		
-		// outerCircle
-		var outerCircle = this.g.ellipse(x, y, width/2, height/2);
-		
-		// white shaddow
-		var shaddow = this.drawShaddow(outerCircle);
-		
-		outerCircle.attr({"stroke-width": this.strokeWidth,
-						"stroke": strokeColor,
-						"fill": fillColor});
-		
-		var innerCircleX = x;
-		var innerCircleY = y;
-		var innerCircleWidth = width/2 - 2;
-		var innerCircleHeight = height/2 - 2;
-		var innerCircle = this.g.ellipse(innerCircleX, innerCircleY, innerCircleWidth, innerCircleHeight);
-		innerCircle.attr({"stroke-width": this.strokeWidth,
-				"stroke": strokeColor,
-				"fill": Color.white});
-
-		// TODO: implement it
-		//var originalPaint = this.getPaint();
-		//this.g.setPaint(BOUNDARY_EVENT_COLOR);
-		
-		this.setPaint(originalPaint);
-	},
-	
-	/*
-	 * Catching Events:
-	 * 
-	 *	drawCatchingTimerEvent
-	 *	drawCatchingErrorEvent
-	 *	drawCatchingSignalEvent
-	 *  drawCatchingMessageEvent
-	 *	drawCatchingMultipleEvent
-	 *	_drawCatchingEventImage
-	 *	_drawCatchingEvent
-	 */
-	 
-	
-	drawCatchingTimerEvent: function(x, y, width, height, isInterrupting, name) {
-	  this.g.setStart();
-		this._drawCatchingEvent(x, y, width, height, isInterrupting, null);
-		
-		var innerCircleWidth = width - 4;
-		var innerCircleHeight = height - 4;
-		
-		var cx = x + width/2 - this.getStroke()/4;
-		var cy = y + height/2 - this.getStroke()/4;
-		
-		var w = innerCircleWidth*.9;// - this.getStroke()*2;
-		var h = innerCircleHeight*.9;// - this.getStroke()*2;
-		
-		this._drawClock(cx, cy, w, h);
-		
-		var set = this.g.setFinish();
-		this.addHandlers(set, x, y, width, height, "event");
-	},
-
-	drawCatchingErrorEvent: function(x, y, width, height, isInterrupting, name) {
-	  this.g.setStart();
-		this._drawCatchingEvent(x, y, width, height, isInterrupting, null);
-		
-		this._drawCatchingEventImage(x, y, width, height, ERROR_CATCH_IMAGE);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawCatchingSignalEvent: function(x, y, width, height, isInterrupting, name) {
-	  this.g.setStart();
-		this._drawCatchingEvent(x, y, width, height, isInterrupting, null);
-		
-		this._drawCatchingEventImage(x, y, width, height, SIGNAL_CATCH_IMAGE);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawCatchingMessageEvent: function(x, y, width, height, isInterrupting, name) {
-	  this.g.setStart();
-		this._drawCatchingEvent(x, y, width, height, isInterrupting, null);
-		
-		this._drawCatchingEventImage(x, y, width, height, MESSAGE_CATCH_IMAGE);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawCatchingMultipleEvent: function(x, y, width, height, isInterrupting, name) {
-	  this.g.setStart();
-		this._drawCatchingEvent(x, y, width, height, isInterrupting, null);
-		
-		var cx = x + width/2 - this.getStroke();
-		var cy = y + height/2 - this.getStroke();
-		
-		var w = width*.9;
-		var h = height*.9;
-		
-		this._drawPentagon(cx, cy, w, h);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	_drawCatchingEventImage: function(x, y, width, height, image){
-		var innerCircleWidth = width - 4;
-		var innerCircleHeight = height - 4;
-		
-		var cx = x + width/2 - this.getStroke()/2;
-		var cy = y + height/2 - this.getStroke()/2;
-		
-		var w = innerCircleWidth*.6;// - this.getStroke()*2;
-		var h = innerCircleHeight*.6;// - this.getStroke()*2;
-		
-		var img = this.g.image(image, cx-w/2, cy-h/2, w, h);
-	},
-	
-	_drawCatchingEvent: function(x, y, width, height, isInterrupting, image) {
-		var originalPaint = this.getPaint();
-		if (typeof(CATCHING_EVENT_COLOR) != "undefined")
-			this.setPaint(CATCHING_EVENT_COLOR);
-			
-		// event circles
-		width -= this.strokeWidth / 2;
-		height -= this.strokeWidth / 2;
-		
-		x = x + width/2;// + this.strokeWidth/2;
-		y = y + width/2;// + this.strokeWidth/2;
-		
-		// outerCircle
-		var outerCircle = this.g.ellipse(x, y, width/2, height/2);
-		
-		// white shaddow
-		var shaddow = this.drawShaddow(outerCircle);
-		
-		//console.log("isInterrupting: " + isInterrupting, "x:" , x, "y:",y);
-		if (isInterrupting!=null && isInterrupting!=undefined && !isInterrupting) 
-			outerCircle.attr({"stroke-dasharray": NON_INTERRUPTING_EVENT_STROKE});
-		
-		outerCircle.attr({"stroke-width": this.strokeWidth,
-						"stroke": this.getPaint(),
-						"fill": BOUNDARY_EVENT_COLOR});
-		
-		var innerCircleX = x;
-		var innerCircleY = y;
-		var innerCircleRadiusX = width/2 - 4;
-		var innerCircleRadiusY = height/2 - 4;
-		var innerCircle = this.g.ellipse(innerCircleX, innerCircleY, innerCircleRadiusX, innerCircleRadiusY);
-		innerCircle.attr({"stroke-width": this.strokeWidth,
-				"stroke": this.getPaint()});
-
-		if (image) {
-			var imageWidth = imageHeight = innerCircleRadiusX*1.2 + this.getStroke()*2;
-			var imageX = innerCircleX-imageWidth/2 - this.strokeWidth/2;
-			var imageY = innerCircleY-imageWidth/2 - this.strokeWidth/2;
-			var img = this.g.image(image, imageX, imageY, imageWidth, imageHeight);
-		}
-		
-		this.setPaint(originalPaint);
-		
-		var set = this.g.set();
-		set.push(outerCircle, innerCircle, shaddow);
-		this.setContextToElement(outerCircle);
-		
-		// TODO: add shapes to set
-		
-		/*
-		var st = this.g.set();
-		st.push(
-			this.g.ellipse(innerCircleX, innerCircleY, 2, 2),
-			this.g.ellipse(imageX, imageY, 2, 2)
-		);
-		st.attr({fill: "red", "stroke-width":0});
-		*/
-	},
-	
-	/*
-	 * Catching Events:
-	 * 
-	 *	drawThrowingNoneEvent
-	 *	drawThrowingSignalEvent
-	 *	drawThrowingMessageEvent
-	 *	drawThrowingMultipleEvent
-	 */
-	
-	drawThrowingNoneEvent: function(x, y, width, height, name) {
-	  this.g.setStart();
-		this._drawCatchingEvent(x, y, width, height, null, null);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawThrowingSignalEvent: function(x, y, width, height, name) {
-	  this.g.setStart();
-		this._drawCatchingEvent(x, y, width, height, null, null);
-		
-		this._drawCatchingEventImage(x, y, width, height, SIGNAL_THROW_IMAGE);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawThrowingMessageEvent: function(x, y, width, height, name) {
-	  this.g.setStart();
-		this._drawCatchingEvent(x, y, width, height, null, null);
-		
-		this._drawCatchingEventImage(x, y, width, height, MESSAGE_THROW_IMAGE);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	drawThrowingMultipleEvent: function(x, y, width, height, name) {
-	  this.g.setStart();
-		this._drawCatchingEvent(x, y, width, height, null, null);
-		
-		var cx = x + width/2 - this.getStroke();
-		var cy = y + height/2 - this.getStroke();
-		
-		var w = width*.9;
-		var h = height*.9;
-		
-		var filled = true;
-		this._drawPentagon(cx, cy, w, h, filled);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "event");
-	},
-	
-	/*
-	 * Draw flows:
-	 * 
-	 *  _connectFlowToActivity
-	 *	_drawFlow
-	 *	_drawDefaultSequenceFlowIndicator
-	 *	drawSequenceflow
-	 *	drawMessageflow
-	 *	drawAssociation
-	 *	_drawCircleTail
-	 *	_drawArrowHead
-	 *	_drawConditionalSequenceFlowIndicator
-	 *	drawSequenceflowWithoutArrow
-	 */
-	 
-	_connectFlowToActivity: function(sourceActivityId, destinationActivityId, waypoints){
-		var sourceActivity = this.g.getById(sourceActivityId);
-		var destinationActivity = this.g.getById(destinationActivityId);
-		if (sourceActivity == null || destinationActivity == null) {
-			if (sourceActivity == null)
-				console.error("source activity["+sourceActivityId+"] not found");
-			else
-				console.error("destination activity["+destinationActivityId+"] not found");
-			return null;
-		}
-			var bbSourceActivity = sourceActivity.getBBox()
-			var bbDestinationActivity = destinationActivity.getBBox()
-			
-			var path = [];
-			var newWaypoints = [];
-			for(var i = 0; i < waypoints.length; i++){
-				var pathType = ""
-				if (i==0)
-					pathType = "M";
-				else 
-					pathType = "L";
-					
-				path.push([pathType, waypoints[i].x, waypoints[i].y]);
-				newWaypoints.push({x:waypoints[i].x, y:waypoints[i].y});
-			}
-
-			var ninjaPathSourceActivity = this.ninjaPaper.path(sourceActivity.realPath);
-			var ninjaPathDestinationActivity = this.ninjaPaper.path(destinationActivity.realPath);
-			var ninjaBBSourceActivity = ninjaPathSourceActivity.getBBox();
-			var ninjaBBDestinationActivity = ninjaPathDestinationActivity.getBBox();
-			
-			// set target of the flow to the center of the taskObject
-			var newPath = path;
-			var originalSource = {x: newPath[0][1], y: newPath[0][2]};
-			var originalTarget = {x: newPath[newPath.length-1][1], y: newPath[newPath.length-1][2]};
-			newPath[0][1] = ninjaBBSourceActivity.x + (ninjaBBSourceActivity.x2 - ninjaBBSourceActivity.x ) / 2;
-			newPath[0][2] = ninjaBBSourceActivity.y + (ninjaBBSourceActivity.y2 - ninjaBBSourceActivity.y ) / 2;
-			newPath[newPath.length-1][1] = ninjaBBDestinationActivity.x + (ninjaBBDestinationActivity.x2 - ninjaBBDestinationActivity.x ) / 2;
-			newPath[newPath.length-1][2] = ninjaBBDestinationActivity.y + (ninjaBBDestinationActivity.y2 - ninjaBBDestinationActivity.y ) / 2;
-			
-			var ninjaPathFlowObject = this.ninjaPaper.path(newPath);
-			var ninjaBBFlowObject = ninjaPathFlowObject.getBBox();
-			
-			var intersectionsSource = Raphael.pathIntersection(ninjaPathSourceActivity.realPath, ninjaPathFlowObject.realPath);
-			var intersectionsDestination = Raphael.pathIntersection(ninjaPathDestinationActivity.realPath, ninjaPathFlowObject.realPath);
-			var intersectionSource = intersectionsSource.pop();
-			var intersectionDestination = intersectionsDestination.pop();
-			
-			if (intersectionSource != undefined) {
-				if (this.gebug) {
-					var diameter = 5;
-					var dotOriginal = this.g.ellipse(originalSource.x, originalSource.y, diameter, diameter).attr({"fill": Color.white, "stroke": Color.Pink});
-					var dot = this.g.ellipse(intersectionSource.x, intersectionSource.y, diameter, diameter).attr({"fill": Color.white, "stroke": Color.Green});
-				}
-				
-				newWaypoints[0].x = intersectionSource.x;
-				newWaypoints[0].y = intersectionSource.y;
-			}
-			if (intersectionDestination != undefined) {
-				if (this.gebug) {
-					var diameter = 5;
-					var dotOriginal = this.g.ellipse(originalTarget.x, originalTarget.y, diameter, diameter).attr({"fill": Color.white, "stroke": Color.Red});
-					var dot = this.g.ellipse(intersectionDestination.x, intersectionDestination.y, diameter, diameter).attr({"fill": Color.white, "stroke": Color.Blue});
-				}
-				
-				newWaypoints[newWaypoints.length-1].x = intersectionDestination.x;
-				newWaypoints[newWaypoints.length-1].y = intersectionDestination.y;
-			}
-			
-			this.ninjaPaper.clear();
-		return newWaypoints;
-	},
-	 
-	_drawFlow: function(waypoints, conditional, isDefault, highLighted, withArrowHead, connectionType){
-		var originalPaint = this.getPaint();
-		var originalStroke = this.getStroke();
-		
-		this.setPaint(SEQUENCEFLOW_COLOR);
-		this.setStroke(SEQUENCEFLOW_STROKE);
-		
-		if (highLighted) {
-			this.setPaint(HIGHLIGHT_COLOR);
-			this.setStroke(SEQUENCEFLOW_HIGHLIGHT_STROKE);
-		}
-
-// TODO: generate polylineId or do something!!
-		var uuid = Raphael.createUUID();
-		
-		var contextObject = this.getConextObject();
-		var newWaypoints = waypoints;
-		if (contextObject) {
-			var newWaypoints = this._connectFlowToActivity(contextObject.sourceActivityId, contextObject.destinationActivityId, waypoints);
-			
-			if (!newWaypoints) {
-				console.error("Error draw flow from '"+contextObject.sourceActivityId+"' to '"+contextObject.destinationActivityId+"' ");
-				return;
-			}
-		}
-		var polyline = new Polyline(uuid, newWaypoints, this.getStroke());
-		//var polyline = new Polyline(waypoints, 3);
-		
-		polyline.element = this.g.path(polyline.path);
-		polyline.element.attr("stroke-width", this.getStroke());
-		polyline.element.attr("stroke", this.getPaint());
-			
-		if (contextObject) {
-			polyline.element.id = contextObject.id;
-			polyline.element.data("contextObject", contextObject);
-		} else {
-			polyline.element.id = uuid;
-		}
-		
-		
-		/*
-		polyline.element.mouseover(function(){
-			this.attr({"stroke-width": NORMAL_STROKE + 2});
-		}).mouseout(function(){
-			this.attr({"stroke-width": NORMAL_STROKE});
-		});
-		*/
-		
-		var last = polyline.getAnchorsCount()-1;
-		var x = polyline.getAnchor(last).x;
-		var y = polyline.getAnchor(last).y;
-		//var c = this.g.ellipse(x, y, 5, 5);
-		
-		var lastLineIndex = polyline.getLinesCount()-1;
-		var line = polyline.getLine(lastLineIndex);
-		var firstLine = polyline.getLine(0);
-		
-		var arrowHead = null,
-			circleTail = null,
-			defaultSequenceFlowIndicator = null,
-			conditionalSequenceFlowIndicator = null;
-
-		if (connectionType == CONNECTION_TYPE.MESSAGE_FLOW) {
-			circleTail = this._drawCircleTail(firstLine, connectionType);
-		}
-		if(withArrowHead)
-			arrowHead = this._drawArrowHead(line, connectionType);
-		
-		//console.log("isDefault: ", isDefault, ", isDefaultConditionAvailable: ", polyline.isDefaultConditionAvailable);
-		if (isDefault && polyline.isDefaultConditionAvailable) {
-			//var angle = polyline.getLineAngle(0);
-			//console.log("firstLine", firstLine);
-			defaultSequenceFlowIndicator = this._drawDefaultSequenceFlowIndicator(firstLine);
-		}
-		
-		if (conditional) {
-			conditionalSequenceFlowIndicator = this._drawConditionalSequenceFlowIndicator(firstLine);
-		}
-
-        // draw flow name
-        var flowName = contextObject.name;
-        if (flowName) {
-            var xPointArray = contextObject.xPointArray;
-            var yPointArray = contextObject.yPointArray;
-            var textX = xPointArray[0] < xPointArray[1] ? xPointArray[0] : xPointArray[1];
-            var textY = yPointArray[0] < yPointArray[1] ? yPointArray[1] : yPointArray[0];
-            // fix xy
-            textX += 20;
-            textY -= 10;
-            this.g.text(textX, textY, flowName).attr(LABEL_FONT);
-        }
-		
-		var st = this.g.set();
-		st.push(polyline.element, arrowHead, circleTail, conditionalSequenceFlowIndicator);
-		polyline.element.data("set", st);
-		polyline.element.data("withArrowHead", withArrowHead);
-		
-		var polyCloneAttrNormal = {"stroke-width": this.getStroke() + 5, stroke: Color.get(132,112,255), opacity: 0.0, cursor: "hand"};
-		var polyClone = st.clone().attr(polyCloneAttrNormal).hover(function () {
-				//if (polyLine.data("isSelected")) return;
-				polyClone.attr({opacity: 0.2});
-			}, function () {
-				//if (polyLine.data("isSelected")) return;
-				polyClone.attr({opacity: 0.0});
-			});
-		polyClone.data("objectId", polyline.element.id);
-		polyClone.click(function(){
-			var instance = this;
-			var objectId = instance.data("objectId");
-			var object = this.paper.getById(objectId);
-			var contextObject = object.data("contextObject");
-			if (contextObject) {
-				console.log("[flow], objectId: " + object.id +", flow: " + contextObject.flow);
-				ProcessDiagramGenerator.showFlowInfo(contextObject);
-			}
-		}).dblclick(function(){
-			console.log("!!! DOUBLE CLICK !!!");
-		}).hover(function (mouseEvent) {
-			var instance = this;
-			var objectId = instance.data("objectId");
-			var object = this.paper.getById(objectId);
-			var contextObject = object.data("contextObject");
-			if (contextObject)
-				ProcessDiagramGenerator.showFlowInfo(contextObject);
-		});
-		polyClone.data("parentId", uuid);
-		
-		if (!connectionType || connectionType == CONNECTION_TYPE.SEQUENCE_FLOW)
-			polyline.element.attr("stroke-width", this.getStroke());
-		else if (connectionType == CONNECTION_TYPE.MESSAGE_FLOW)
-			polyline.element.attr({"stroke-dasharray": "--"});
-		else if (connectionType == CONNECTION_TYPE.ASSOCIATION)
-			polyline.element.attr({"stroke-dasharray": ". "});
-		
-		this.setPaint(originalPaint);
-		this.setStroke(originalStroke);
-	},
-	
-	_drawDefaultSequenceFlowIndicator: function(line) {
-		//console.log("line: ", line);
-		
-		var len = 10; c = len/2, f = 8;
-		var defaultIndicator = this.g.path("M" + (-c) + " " + 0 + "L" + (c) + " " + 0);
-		defaultIndicator.attr("stroke-width", this.getStroke()+0);
-		defaultIndicator.attr("stroke", this.getPaint());
-		
-		
-		var cosAngle = Math.cos((line.angle));
-		var sinAngle = Math.sin((line.angle));
-		
-		var dx = f * cosAngle;
-		var dy = f * sinAngle;
-		
-		var x1 = line.x1 + dx + 0*c*cosAngle;
-		var y1 = line.y1 + dy + 0*c*sinAngle;
-		
-		defaultIndicator.transform("t" + (x1) + "," + (y1) + "");
-		defaultIndicator.transform("...r" + Raphael.deg(line.angle - 3*Math.PI / 4) + " " + 0 + " " + 0);
-		/*
-		var c0 = this.g.ellipse(0, 0, 1, 1).attr({stroke: Color.Blue});
-		c0.transform("t" + (line.x1) + "," + (line.y1) + "");
-		var center = this.g.ellipse(0, 0, 1, 1).attr({stroke: Color.Red});
-		center.transform("t" + (line.x1+dx) + "," + (line.y1+dy) + "");
-		*/
-		
-		return defaultIndicator;
-	},
-	
-	drawSequenceflow: function(waypoints, conditional, isDefault, highLighted) {
-		var withArrowHead = true;
-		this._drawFlow(waypoints, conditional, isDefault, highLighted, withArrowHead, CONNECTION_TYPE.SEQUENCE_FLOW);
-	},
-	
-	drawMessageflow: function(waypoints, highLighted) {
-		var withArrowHead = true;
-		var conditional=isDefault=false;
-		this._drawFlow(waypoints, conditional, isDefault, highLighted, withArrowHead, CONNECTION_TYPE.MESSAGE_FLOW);
-	},
-	
-	drawAssociation: function(waypoints, withArrowHead, highLighted) {
-		var withArrowHead = withArrowHead;
-		var conditional=isDefault=false;
-		this._drawFlow(waypoints, conditional, isDefault, highLighted, withArrowHead, CONNECTION_TYPE.ASSOCIATION);
-	},
-  
-	_drawCircleTail: function(line, connectionType){
-		var diameter = ARROW_WIDTH/2*1.5;
-		
-		// anti smoothing
-		if (this.strokeWidth%2 == 1)
-			line.x1 += .5, line.y1 += .5;
-		
-		var circleTail = this.g.ellipse(line.x1, line.y1, diameter, diameter);
-		circleTail.attr("fill", Color.white);
-		circleTail.attr("stroke", this.getPaint());
-		
-		return circleTail;
-	},
-	
-	_drawArrowHead: function(line, connectionType){
-		var doubleArrowWidth = 2 * ARROW_WIDTH;
-		
-		if (connectionType == CONNECTION_TYPE.ASSOCIATION)
-			var arrowHead = this.g.path("M-" + (ARROW_WIDTH/2+.5) + " -" + doubleArrowWidth + "L 0 0 L" + (ARROW_WIDTH/2+.5) + " -" + doubleArrowWidth);
-		else
-			var arrowHead = this.g.path("M0 0L-" + (ARROW_WIDTH/2+.5) + " -" + doubleArrowWidth + "L" + (ARROW_WIDTH/2+.5) + " -" + doubleArrowWidth + "z");
-		
-		//arrowHead.transform("t" + 0 + ",-" + this.getStroke() + "");
-		
-		// anti smoothing
-		if (this.strokeWidth%2 == 1)
-			line.x2 += .5, line.y2 += .5;
-		
-		arrowHead.transform("t" + line.x2 + "," + line.y2 + "");
-		arrowHead.transform("...r" + Raphael.deg(line.angle - Math.PI / 2) + " " + 0 + " " + 0);
-		
-		if (!connectionType || connectionType == CONNECTION_TYPE.SEQUENCE_FLOW)
-			arrowHead.attr("fill", this.getPaint());
-		else if (connectionType == CONNECTION_TYPE.MESSAGE_FLOW)
-			arrowHead.attr("fill", Color.white);
-			
-		arrowHead.attr("stroke-width", this.getStroke());
-		arrowHead.attr("stroke", this.getPaint());
-		
-		return arrowHead;
-	},
-	
-	/*
-	drawArrowHead2: function(srcX, srcY, targetX, targetY) {
-		var doubleArrowWidth = 2 * ARROW_WIDTH;
-		
-		//var arrowHead = this.g.path("M-" + ARROW_WIDTH/2 + " -" + doubleArrowWidth + "L0 0" + "L" + ARROW_WIDTH/2 + " -" + doubleArrowWidth + "z");
-		
-		var arrowHead = this.g.path("M0 0L-" + ARROW_WIDTH/1.5 + " -" + doubleArrowWidth + "L" + ARROW_WIDTH/1.5 + " -" + doubleArrowWidth + "z");
-		//var c = DefaultProcessDiagramCanvas.g.ellipse(0, 0, 3, 3);
-		//c.transform("t"+targetX+","+targetY+"");
-		
-		var angle = Math.atan2(targetY - srcY, targetX - srcX);
-		
-		arrowHead.transform("t"+targetX+","+targetY+"");
-		arrowHead.transform("...r" + Raphael.deg(angle - Math.PI / 2) + " "+0+" "+0);
-		
-		//console.log(arrowHead.transform());
-		//console.log("--> " + Raphael.deg(angle - Math.PI / 2));
-		
-		arrowHead.attr("fill", this.getPaint());
-		arrowHead.attr("stroke", this.getPaint());
-		
-		/ *
-		// shaddow
-		var c0 = arrowHead.clone();
-		c0.transform("...t-1 1");
-		c0.attr("stroke-width", this.strokeWidth);
-		c0.attr("stroke", Color.black);
-		c0.attr("opacity", 0.15);
-		c0.toBack();
-		* /
-	},
-	*/
-	
-	_drawConditionalSequenceFlowIndicator: function(line){
-		var horizontal = (CONDITIONAL_INDICATOR_WIDTH * 0.7);
-		var halfOfHorizontal = horizontal / 2;
-		var halfOfVertical = CONDITIONAL_INDICATOR_WIDTH / 2;
-
-		var uuid = null;
-		var waypoints = [{x: 0, y: 0},
-						{x: -halfOfHorizontal, y: halfOfVertical},
-						{x: 0, y: CONDITIONAL_INDICATOR_WIDTH},
-						{x: halfOfHorizontal, y: halfOfVertical}];
-		/*
-		var polyline = new Polyline(uuid, waypoints, this.getStroke());
-		polyline.element = this.g.path(polyline.path);
-		polyline.element.attr("stroke-width", this.getStroke());
-		polyline.element.attr("stroke", this.getPaint());
-		polyline.element.id = uuid;
-		*/
-		var polygone = new Polygone(waypoints, this.getStroke());
-		polygone.element = this.g.path(polygone.path);
-		polygone.element.attr("fill", Color.white);
-		
-		polygone.transform("t" + line.x1 + "," + line.y1 + "");
-		polygone.transform("...r" + Raphael.deg(line.angle - Math.PI / 2) + " " + 0 + " " + 0);
-		
-		
-		var cosAngle = Math.cos((line.angle));
-		var sinAngle = Math.sin((line.angle));
-		
-		//polygone.element.attr("stroke-width", this.getStroke());
-		//polygone.element.attr("stroke", this.getPaint());
-		
-		polygone.attr({"stroke-width": this.getStroke(), "stroke": this.getPaint()});
-		
-		return polygone.element;
-	},
-  
-	drawSequenceflowWithoutArrow: function(waypoints, conditional, isDefault, highLighted) {
-		var withArrowHead = false;
-		this._drawFlow(waypoints, conditional, isDefault, highLighted, withArrowHead, CONNECTION_TYPE.SEQUENCE_FLOW);
-	},
-	
-	/*
-	 * Draw artifacts
-	 */
-	
-	drawPoolOrLane: function(x, y, width, height, name){
-		// anti smoothing
-		if (this.strokeWidth%2 == 1)
-			x = Math.round(x) + .5, y = Math.round(y) + .5;
-		
-		// shape
-		var rect = this.g.rect(x, y, width, height);
-		var attr = {"stroke-width": NORMAL_STROKE, stroke: TASK_STROKE_COLOR};
-		rect.attr(attr);
-		
-		// Add the name as text, vertical
-		if(name != null && name.length > 0) {
-			var attr = POOL_LANE_FONT;
-			
-			// Include some padding
-			var availableTextSpace = height - 6;
-			
-			// Create rotation for derived font
-			var truncated = this.fitTextToWidth(name, availableTextSpace);
-			var realWidth = this.getStringWidth(truncated, attr);
-			var realHeight = this.getStringHeight(truncated, attr);
-			
-			//console.log("truncated:", truncated, ", height:", height, ", realHeight:", realHeight, ", availableTextSpace:", availableTextSpace, ", realWidth:", realWidth);
-			var newX = x + 2 + realHeight*1 - realHeight/2;
-			var newY = 3 + y + availableTextSpace - (availableTextSpace - realWidth) / 2 - realWidth/2;
-			var textElement = this.g.text(newX, newY, truncated).attr(attr);
-			//console.log(".getBBox(): ", t.getBBox());
-			textElement.transform("r" + Raphael.deg(270 * Math.PI/180) + " " + newX + " " + newY);
-		}
-		
-		// TODO: add to set
-	},
-	
-	_drawTask: function(name, x, y, width, height, thickBorder) {
-		var originalPaint = this.getPaint();
-		this.setPaint(TASK_COLOR);
-		
-		// anti smoothing
-		if (this.strokeWidth%2 == 1)
-			x = Math.round(x) + .5, y = Math.round(y) + .5;
-		
-		// shape
-		var shape = this.g.rect(x, y, width, height, TASK_CORNER_ROUND);
-		var attr = {"stroke-width": this.strokeWidth, stroke: TASK_STROKE_COLOR, fill: this.getPaint()};
-		shape.attr(attr);
-		//shape.attr({fill: "90-"+this.getPaint()+"-" + Color.get(250, 250, 244)});
-		
-		var contextObject = this.getConextObject();
-		if (contextObject) {
-			shape.id = contextObject.id;
-			shape.data("contextObject", contextObject);
-		}
-		
-		//var activity = this.getConextObject();
-		//console.log("activity: " + activity.getId(), activity);
-		//Object.clone(activity);
-		
-		/*
-		c.mouseover(function(){
-			this.attr({"stroke-width": NORMAL_STROKE + 2});
-		}).mouseout(function(){
-			this.attr({"stroke-width": NORMAL_STROKE});
-		});
-		*/
-		
-		this.setPaint(originalPaint);
-
-		// white shaddow
-		this.drawShaddow(shape);
-		
-		
-		if (thickBorder) {
-			shape.attr({"stroke-width": THICK_TASK_BORDER_STROKE});
-		} else {
-			//g.draw(rect);
-		}
-		
-		// text
-		if (name) {
-			var fontAttr = TASK_FONT;
-			
-			// Include some padding
-			var paddingX = 5;
-			var paddingY = 5;
-			var availableTextSpace = width - paddingX*2;
-			
-			// TODO: this.setFont
-			// var originalFont = this.getFont();
-			// this.setFont(TASK_FONT)
-			/*
-			var truncated = this.fitTextToWidth(name, availableTextSpace);
-			var realWidth = this.getStringWidth(truncated, fontAttr);
-			var realHeight = this.getStringHeight(truncated, fontAttr);
-			
-			//var t = this.g.text(x + width/2 + realWidth*0/2 + paddingX*0, y + height/2, truncated).attr(fontAttr);
-			*/
-			//console.log("draw task name: " + name);
-			var boxWidth = width - (2 * TEXT_PADDING);
-			var boxHeight = height - ICON_SIZE - ICON_PADDING - ICON_PADDING - MARKER_WIDTH - 2 - 2;
-			var boxX = x + width/2 - boxWidth/2;
-			var boxY = y + height/2 - boxHeight/2 + ICON_PADDING + ICON_PADDING - 2 - 2;
-			/*
-			var boxWidth = width - (2 * ANNOTATION_TEXT_PADDING);
-			var boxHeight = height - (2 * ANNOTATION_TEXT_PADDING);
-			var boxX = x + width/2 - boxWidth/2;
-			var boxY = y + height/2 - boxHeight/2;
-			*/
-			
-			this.drawTaskLabel(name, boxX, boxY, boxWidth, boxHeight);
-		}
-	},
-	
-	drawTaskLabel: function(text, x, y, boxWidth, boxHeight){
-		var originalFont = this.getFont();
-		this.setFont(TASK_FONT);
-			
-		this._drawMultilineText(text, x, y, boxWidth, boxHeight, MULTILINE_VERTICAL_ALIGN_MIDDLE, MULTILINE_HORIZONTAL_ALIGN_MIDDLE);
-		
-		this.setFont(originalFont);
-	},
-	
-	drawAnnotationText: function(text, x, y, width, height){
-		//this._drawMultilineText(text, x, y, width, height, "start");
-		
-		var originalPaint = this.getPaint();
-		var originalFont = this.getFont();
-		
-		this.setPaint(Color.black);
-		this.setFont(TASK_FONT);
-			
-		this._drawMultilineText(text, x, y, width, height, MULTILINE_VERTICAL_ALIGN_TOP, MULTILINE_HORIZONTAL_ALIGN_LEFT);
-		
-		this.setPaint(originalPaint);
-		this.setFont(originalFont);
-	},
-	
-	drawLabel: function(text, x, y, width, height){
-		//this._drawMultilineText(text, x, y, width, height, "start");
-		
-		var originalPaint = this.getPaint();
-		var originalFont = this.getFont();
-		
-		this.setPaint(LABEL_COLOR);
-		//this.setFont(LABEL_FONT);
-		this.setFont(LABEL_FONT_SMOOTH);
-		
-		// predefined box width for labels
-		// TODO: use label width as is, but not height (for stretching)
-		if (!width || !height) {
-		  width = 100;
-		  height = 0;
-		}
-		
-		// TODO: remove it. It is debug
-		x = x - width/2;
-	  
-		this._drawMultilineText(text, x, y, width, height, MULTILINE_VERTICAL_ALIGN_TOP, MULTILINE_HORIZONTAL_ALIGN_MIDDLE);
-		
-		this.setPaint(originalPaint);
-		this.setFont(originalFont);
-	},
-	
-	/*
-	drawMultilineLabel: function(text, x, y){
-		var originalFont = this.getFont();
-		this.setFont(LABEL_FONT_SMOOTH);
-		
-		var boxWidth = 80;
-		x = x - boxWidth/2
-		
-		this._drawMultilineText(text, x, y, boxWidth, null, "middle");
-		this.setFont(originalFont);
-	},
-	*/
-	
-	getStringWidth: function(text, fontAttrs){
-		var textElement = this.g.text(0, 0, text).attr(fontAttrs).hide();
-		var bb = textElement.getBBox();
-		
-		//console.log("string width: ", t.getBBox().width);
-		return textElement.getBBox().width;
-	},
-	getStringHeight: function(text, fontAttrs){
-		var textElement = this.g.text(0, 0, text).attr(fontAttrs).hide();
-		var bb = textElement.getBBox();
-		
-		//console.log("string height: ", t.getBBox().height);
-		return textElement.getBBox().height;
-	},
-	fitTextToWidth: function(original, width) {
-		var text = original;
-
-		// TODO: move attr on parameters
-		var attr = {font: "11px Arial", opacity: 0};
-		
-		// remove length for "..."
-		var dots = this.g.text(0, 0, "...").attr(attr).hide();
-		var dotsBB = dots.getBBox();
-		
-		var maxWidth = width - dotsBB.width;
-		
-		var textElement = this.g.text(0, 0, text).attr(attr).hide();
-		var bb = textElement.getBBox();
-		
-		// it's a little bit incorrect with "..."
-		while (bb.width > maxWidth && text.length > 0) {
-			text = text.substring(0, text.length - 1);
-			textElement.attr({"text": text});
-			bb = textElement.getBBox();
-		}
-
-		// remove element from paper
-		textElement.remove();
-		
-		if (text != original) {
-			text = text + "...";
-		}
-
-		return text;
-	},
-	wrapTextToWidth: function(original, width){
-	
-		//return original;
-		
-		var text = original;
-		var wrappedText = "\n";
-		
-		// TODO: move attr on parameters
-		var attr = {font: "11px Arial", opacity: 0};
-		
-		var textElement = this.g.text(0, 0, wrappedText).attr(attr).hide();
-		var bb = textElement.getBBox();
-		
-		var resultText = "";
-		var i = 0, j = 0;
-		while (text.length > 0) {
-			while (bb.width < width && text.length>0) {
-				// remove "\n"
-				wrappedText = wrappedText.substring(0,wrappedText.length-1);
-				// add new char, add "\n"
-				wrappedText = wrappedText + text.substring(0,1) + "\n";
-				text = text.substring(1);
-				
-				textElement.attr({"text": wrappedText});
-				bb = textElement.getBBox();
-				i++;
-				if (i>200) break;
-			}
-			// remove "\n"
-			wrappedText = wrappedText.substring(0, wrappedText.length - 1);
-			
-			if (text.length == 0) {
-				resultText += wrappedText;
-				break;
-			}
-			
-			// return last char to text
-			text = wrappedText.substring(wrappedText.length-1) + text;
-			// remove last char from wrappedText
-			wrappedText = wrappedText.substring(0, wrappedText.length-1) + "\n";
-			
-			textElement.attr({"text": wrappedText});
-			bb = textElement.getBBox();
-			
-			//console.log(">> ", wrappedText, ", ", text);
-			resultText += wrappedText;
-			wrappedText = "\n";
-			
-			j++;
-			if (j>20) break;
-		}
-		// remove element from paper
-		textElement.remove();
-		
-		return resultText;
-	},
-	
-	wrapTextToWidth2: function(original, width){
-		var text = original;
-		var wrappedText = "\n";
-		
-		// TODO: move attr on parameters
-		var attr = {font: "11px Arial", opacity: 0};
-		
-		var textElement = this.g.text(0, 0, wrappedText).attr(attr).hide();
-		var bb = textElement.getBBox();
-		
-		var resultText = "";
-		var i = 0, j = 0;
-		while (text.length > 0) {
-			while (bb.width < width && text.length>0) {
-				// remove "\n"
-				wrappedText = wrappedText.substring(0,wrappedText.length-1);
-				// add new char, add "\n"
-				wrappedText = wrappedText + text.substring(0,1) + "\n";
-				text = text.substring(1);
-				
-				textElement.attr({"text": wrappedText});
-				bb = textElement.getBBox();
-				i++;
-				if (i>200) break;
-			}
-			// remove "\n"
-			wrappedText = wrappedText.substring(0, wrappedText.length - 1);
-			
-			if (text.length == 0) {
-				resultText += wrappedText;
-				break;
-			}
-			
-			// return last char to text
-			text = wrappedText.substring(wrappedText.length-1) + text;
-			// remove last char from wrappedText
-			wrappedText = wrappedText.substring(0, wrappedText.length-1) + "\n";
-			
-			textElement.attr({"text": wrappedText});
-			bb = textElement.getBBox();
-			
-			//console.log(">> ", wrappedText, ", ", text);
-			resultText += wrappedText;
-			wrappedText = "\n";
-			
-			j++;
-			if (j>20) break;
-		}
-		// remove element from paper
-		textElement.remove();
-		
-		return resultText;
-	},
-	
-	drawUserTask: function(name, x, y, width, height) {
-	  this.g.setStart();
-		this._drawTask(name, x, y, width, height);
-		var img = this.g.image(USERTASK_IMAGE, x + ICON_PADDING, y + ICON_PADDING, ICON_SIZE, ICON_SIZE);
-		var set = this.g.setFinish();
-		this.addHandlers(set, x, y, width, height, "task");
-	},
-	
-	drawScriptTask: function(name, x, y, width, height) {
-	  this.g.setStart();
-		this._drawTask(name, x, y, width, height);
-		var img = this.g.image(SCRIPTTASK_IMAGE, x + ICON_PADDING, y + ICON_PADDING, ICON_SIZE, ICON_SIZE);
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "task");
-	},
-	
-	drawServiceTask: function(name, x, y, width, height) {
-	  this.g.setStart();
-		this._drawTask(name, x, y, width, height);
-		var img = this.g.image(SERVICETASK_IMAGE, x + ICON_PADDING, y + ICON_PADDING, ICON_SIZE, ICON_SIZE);
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "task");
-	},
-	
-	drawReceiveTask: function(name, x, y, width, height) {
-	  this.g.setStart();
-		this._drawTask(name, x, y, width, height);
-		var img = this.g.image(RECEIVETASK_IMAGE, x + 7, y + 7, ICON_SIZE, ICON_SIZE);
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "task");
-	},
-	
-	drawSendTask: function(name, x, y, width, height) {
-	  this.g.setStart();
-		this._drawTask(name, x, y, width, height);
-		var img = this.g.image(SENDTASK_IMAGE, x + 7, y + 7, ICON_SIZE, ICON_SIZE);
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "task");
-	},
-	
-	drawManualTask: function(name, x, y, width, height) {
-	  this.g.setStart();
-		this._drawTask(name, x, y, width, height);
-		var img = this.g.image(MANUALTASK_IMAGE, x + 7, y + 7, ICON_SIZE, ICON_SIZE);
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "task");
-	},
-	
-	drawBusinessRuleTask: function(name, x, y, width, height) {
-	  this.g.setStart();
-		this._drawTask(name, x, y, width, height);
-		var img = this.g.image(BUSINESS_RULE_TASK_IMAGE, x + 7, y + 7, ICON_SIZE, ICON_SIZE);
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "task");
-	},
-	
-	drawExpandedSubProcess: function(name, x, y, width, height, isTriggeredByEvent){
-	  this.g.setStart();
-		// anti smoothing
-		if (this.strokeWidth%2 == 1)
-			x = Math.round(x) + .5, y = Math.round(y) + .5;
-		
-		// shape
-		var rect = this.g.rect(x, y, width, height, EXPANDED_SUBPROCESS_CORNER_ROUND);
-		
-		// Use different stroke (dashed)
-		if(isTriggeredByEvent) {
-			rect.attr(EVENT_SUBPROCESS_ATTRS);
-		} else {
-			rect.attr(EXPANDED_SUBPROCESS_ATTRS);
-		}
-		
-		this.setContextToElement(rect);
-		
-		var fontAttr = EXPANDED_SUBPROCESS_FONT;
-		
-		// Include some padding
-		var paddingX = 10;
-		var paddingY = 5;
-		var availableTextSpace = width - paddingX*2;
-		
-		var truncated = this.fitTextToWidth(name, availableTextSpace);
-		var realWidth = this.getStringWidth(truncated, fontAttr);
-		var realHeight = this.getStringHeight(truncated, fontAttr);
-		
-		var textElement = this.g.text(x + width/2 - realWidth*0/2 + 0*paddingX, y + realHeight/2 + paddingY, truncated).attr(fontAttr);
-		
-		var set = this.g.setFinish();
-		// TODO: Expanded Sub Process may has specific handlers
-		//this.addHandlers(set, x, y, width, height, "task");
-	},
-	
-	drawCollapsedSubProcess: function(name, x, y, width, height, isTriggeredByEvent) {
-	  this.g.setStart();
-	  this._drawCollapsedTask(name, x, y, width, height, false);
-	  var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "task");
-	},
-	
-	drawCollapsedCallActivity: function(name, x, y, width, height) {
-	  this.g.setStart();
-		this._drawCollapsedTask(name, x, y, width, height, true);
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "task");
-	},
-
-	_drawCollapsedTask: function(name, x, y, width, height, thickBorder) {
-		// The collapsed marker is now visualized separately
-		this._drawTask(name, x, y, width, height, thickBorder);
-	},
-	
-	drawCollapsedMarker: function(x, y, width, height){
-		// rectangle
-		var rectangleWidth = MARKER_WIDTH;
-		var rectangleHeight = MARKER_WIDTH;
-		
-		// anti smoothing
-		if (this.strokeWidth%2 == 1)
-			y += .5;
-		
-		var rect = this.g.rect(x + (width - rectangleWidth) / 2, y + height - rectangleHeight - 3, rectangleWidth, rectangleHeight);
-		
-		// plus inside rectangle
-		var cx = rect.attr("x") + rect.attr("width")/2;
-		var cy = rect.attr("y") + rect.attr("height")/2;
-		
-		var line = this.g.path(
-			"M" + cx + " " + (cy+2) + "L" + cx + " " + (cy-2) + 
-			"M" + (cx-2) + " " + cy + "L" + (cx+2) + " " + cy
-		).attr({"stroke-width": this.strokeWidth});
-		
-	},
-	
-	drawActivityMarkers: function(x, y, width, height, multiInstanceSequential, multiInstanceParallel, collapsed){
-		if (collapsed) {
-			if (!multiInstanceSequential && !multiInstanceParallel) {
-				this.drawCollapsedMarker(x, y, width, height);
-			} else {
-				this.drawCollapsedMarker(x - MARKER_WIDTH / 2 - 2, y, width, height);
-				if (multiInstanceSequential) {
-					console.log("is collapsed and multiInstanceSequential");
-					this.drawMultiInstanceMarker(true, x + MARKER_WIDTH / 2 + 2, y, width, height);
-				} else if (multiInstanceParallel) {
-					console.log("is collapsed and multiInstanceParallel");
-					this.drawMultiInstanceMarker(false, x + MARKER_WIDTH / 2 + 2, y, width, height);
-				}
-			}
-		} else {
-			if (multiInstanceSequential) {
-				console.log("is multiInstanceSequential");
-				this.drawMultiInstanceMarker(true, x, y, width, height);
-			} else if (multiInstanceParallel) {
-				console.log("is multiInstanceParallel");
-				this.drawMultiInstanceMarker(false, x, y, width, height);
-			}
-		}
-	},
-	
-	drawGateway: function(x, y, width, height) {
-		
-		var rhombus = this.g.path(	"M" + x + " " + (y + (height / 2)) + 
-									"L" + (x + (width / 2)) + " " + (y + height) + 
-									"L" + (x + width) + " " + (y + (height / 2)) +
-									"L" + (x + (width / 2)) + " " + y +
-									"z"
-								);
-		
-		// white shaddow
-		this.drawShaddow(rhombus);
-		
-		rhombus.attr("stroke-width", this.strokeWidth);
-		rhombus.attr("stroke", Color.SlateGrey);
-		rhombus.attr({fill: Color.white});
-		
-		this.setContextToElement(rhombus);
-		
-		return rhombus;
-	},
-	
-	drawParallelGateway: function(x, y, width, height) {
-	  this.g.setStart();
-	  
-		// rhombus
-		this.drawGateway(x, y, width, height);
-
-		// plus inside rhombus
-		var originalStroke = this.getStroke();
-		this.setStroke(GATEWAY_TYPE_STROKE);
-		
-		var plus = this.g.path(
-			"M" + (x + 10) + " " + (y + height / 2) + "L" + (x + width - 10) + " " + (y + height / 2) +	// horizontal
-			"M" + (x + width / 2) + " " + (y + height - 10) + "L" + (x + width / 2) + " " + (y + 10)	// vertical
-		);
-		plus.attr({"stroke-width": this.getStroke(), "stroke": this.getPaint()});
-		
-		this.setStroke(originalStroke);
-		
-		var set = this.g.setFinish();
-		this.addHandlers(set, x, y, width, height, "gateway");
-	},
-	
-	drawExclusiveGateway: function(x, y, width, height) {
-	  this.g.setStart();
-	  
-		// rhombus
-		var rhombus = this.drawGateway(x, y, width, height);
-
-		var quarterWidth = width / 4;
-		var quarterHeight = height / 4;
-		
-		// X inside rhombus
-		var originalStroke = this.getStroke();
-		this.setStroke(GATEWAY_TYPE_STROKE);
-		
-		var iks = this.g.path(
-			"M" + (x + quarterWidth + 3) + " " + (y + quarterHeight + 3) + "L" + (x + 3 * quarterWidth - 3) + " " + (y + 3 * quarterHeight - 3) + 
-			"M" + (x + quarterWidth + 3) + " " + (y + 3 * quarterHeight - 3) + "L" + (x + 3 * quarterWidth - 3) + " " + (y + quarterHeight + 3)
-		);
-		iks.attr({"stroke-width": this.getStroke(), "stroke": this.getPaint()});
-		
-		this.setStroke(originalStroke);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "gateway");
-	},
-	
-	drawInclusiveGateway: function(x, y, width, height){
-	  this.g.setStart();
-	  
-		// rhombus
-		this.drawGateway(x, y, width, height);
-		
-		var diameter = width / 4;
-		
-		// circle inside rhombus
-		var originalStroke = this.getStroke();
-		this.setStroke(GATEWAY_TYPE_STROKE);
-		var circle = this.g.ellipse(width/2 + x, height/2 + y, diameter, diameter);
-		circle.attr({"stroke-width": this.getStroke(), "stroke": this.getPaint()});
-		
-		this.setStroke(originalStroke);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "gateway");
-	},
-	
-	drawEventBasedGateway: function(x, y, width, height){
-	  this.g.setStart();
-	  
-		// rhombus
-		this.drawGateway(x, y, width, height);
-		
-		var diameter = width / 2;
-
-	    // rombus inside rhombus
-	    var originalStroke = this.getStroke();
-		this.setStroke(GATEWAY_TYPE_STROKE);
-	    
-	    
-	    // draw GeneralPath (polygon)
-	    var n=5;
-	    var angle = 2*Math.PI/n;
-	    var x1Points = [];
-	    var y1Points = [];
-		
-		for ( var index = 0; index < n; index++ ) {
-			var v = index*angle - Math.PI/2;
-			x1Points[index] = x + parseInt(Math.round(width/2)) + parseInt(Math.round((width/4)*Math.cos(v)));
-        	y1Points[index] = y + parseInt(Math.round(height/2)) + parseInt(Math.round((height/4)*Math.sin(v)));
-		}
-		//g.drawPolygon(x1Points, y1Points, n);
-		
-		var path = "";
-		for ( var index = 0; index < n; index++ ) {
-			if (index == 0) 
-				path += "M";
-			else 
-				path += "L";
-			path += x1Points[index] + "," + y1Points[index];
-		}
-		path += "z";
-		var polygone = this.g.path(path);
-		polygone.attr("stroke-width", this.strokeWidth);
-		polygone.attr("stroke", this.getPaint());
-		
-		this.setStroke(originalStroke);
-		
-		var set = this.g.setFinish();
-    this.addHandlers(set, x, y, width, height, "gateway");
-	},
-	
-	/*
-	*  drawMultiInstanceMarker
-	*  drawHighLight
-	*  highLightFlow
-	*/
-	
-	drawMultiInstanceMarker: function(sequential, x, y, width, height) {
-		var rectangleWidth = MARKER_WIDTH;
-		var rectangleHeight = MARKER_WIDTH;
-		
-		// anti smoothing
-		if (this.strokeWidth%2 == 1)
-			x += .5;//, y += .5;
-			
-		var lineX = x + (width - rectangleWidth) / 2;
-		var lineY = y + height - rectangleHeight - 3;
-		
-		var originalStroke = this.getStroke();
-		this.setStroke(MULTI_INSTANCE_STROKE);
-		
-		if (sequential) {
-			var line = this.g.path(
-				"M" + lineX + " " + lineY + 							"L" + (lineX + rectangleWidth) + " " + lineY + 
-				"M" + lineX + " " + (lineY + rectangleHeight / 2) + 	"L" + (lineX + rectangleWidth) + " " + (lineY + rectangleHeight / 2) + 
-				"M" + lineX + " " + (lineY + rectangleHeight) + 		"L" + (lineX + rectangleWidth) + " " + (lineY + rectangleHeight)
-			).attr({"stroke-width": this.strokeWidth});
-		} else {
-			var line = this.g.path(
-				"M" + lineX + " " + 							lineY + "L" + lineX + " " + 					(lineY + rectangleHeight) +
-				"M" + (lineX + rectangleWidth / 2) + " " + 	lineY + "L" + (lineX + rectangleWidth / 2) + " " + 	(lineY + rectangleHeight) + 
-				"M" + (lineX + rectangleWidth) + " " + 		lineY + "L" + (lineX + rectangleWidth) + " " + 		(lineY + rectangleHeight)
-			).attr({"stroke-width": this.strokeWidth});
-		}
-		
-		this.setStroke(originalStroke);
-	},
-	
-	drawHighLight: function(x, y, width, height){
-		var originalPaint = this.getPaint();
-		var originalStroke = this.getStroke();
-		
-		this.setPaint(HIGHLIGHT_COLOR);
-		this.setStroke(THICK_TASK_BORDER_STROKE);
-
-		//var c = this.g.rect(x - width/2 - THICK_TASK_BORDER_STROKE, y - height/2 - THICK_TASK_BORDER_STROKE, width + THICK_TASK_BORDER_STROKE*2, height + THICK_TASK_BORDER_STROKE*2, 5);
-		var rect = this.g.rect(x - THICK_TASK_BORDER_STROKE, y - THICK_TASK_BORDER_STROKE, width + THICK_TASK_BORDER_STROKE*2, height + THICK_TASK_BORDER_STROKE*2, TASK_CORNER_ROUND);
-		rect.attr("stroke-width", this.strokeWidth);
-		rect.attr("stroke", this.getPaint());
-		
-		this.setPaint(originalPaint);
-		this.setStroke(originalStroke);
-	},
-	
-	highLightActivity: function(activityId){
-		var shape = this.g.getById(activityId);
-		if (!shape) {
-			console.error("Activity " + activityId + " not found");
-			return;
-		}
-		
-		var contextObject = shape.data("contextObject");
-		if (contextObject)
-			console.log("--> highLightActivity: ["+contextObject.getProperty("type")+"], activityId: " + contextObject.getId());
-		else
-			console.log("--> highLightActivity: ", shape, shape.data("contextObject"));
-		
-		shape.attr("stroke-width", THICK_TASK_BORDER_STROKE);
-		shape.attr("stroke", HIGHLIGHT_COLOR);
-	},
-	
-	highLightFlow: function(flowId){
-		var shapeFlow = this.g.getById(flowId);
-		if (!shapeFlow) {
-			console.error("Flow " + flowId + " not found");
-			return;
-		}
-		
-		var contextObject = shapeFlow.data("contextObject");
-		if (contextObject)
-			console.log("--> highLightFlow: ["+contextObject.id+"] " + contextObject.flow);
-		//console.log("--> highLightFlow: ", flow.flow, flow.data("set"));
-		
-		var st = shapeFlow.data("set");
-		
-		st.attr("stroke-width", SEQUENCEFLOW_HIGHLIGHT_STROKE);
-		st.attr("stroke", HIGHLIGHT_COLOR);
-		var withArrowHead = shapeFlow.data("withArrowHead");
-		if (withArrowHead)
-			st[1].attr("fill", HIGHLIGHT_COLOR);
-		
-		st.forEach(function(el){
-			//console.log("---->", el);
-			//el.attr("")
-		});
-	},
-	
-
-	_drawClock: function(cx, cy, width, height){
-		
-		var circle = this.g.ellipse(cx, cy, 1, 1).attr({stroke:"none", fill: Color.get(232, 239, 241)});
-		//var c = this.g.ellipse(cx, cy, width, height).attr({stroke:"none", fill: Color.red});
-		//x = cx - width/2;
-		//y = cy - height/2;
-	
-		var clock = this.g.path(
-		/* outer circle */ "M15.5,2.374		C8.251,2.375,2.376,8.251,2.374,15.5		C2.376,22.748,8.251,28.623,15.5,28.627c7.249-0.004,13.124-5.879,13.125-13.127C28.624,8.251,22.749,2.375,15.5,2.374z" +
-		/* inner circle */ "M15.5,26.623	C8.909,26.615,4.385,22.09,4.375,15.5	C4.385,8.909,8.909,4.384,15.5,4.374c4.59,0.01,11.115,3.535,11.124,11.125C26.615,22.09,22.091,26.615,15.5,26.623z" +
-		/*  9 */ "M8.625,15.5c-0.001-0.552-0.448-0.999-1.001-1c-0.553,0-1,0.448-1,1c0,0.553,0.449,1,1,1C8.176,16.5,8.624,16.053,8.625,15.5z" +
-		/*  8 */ "M8.179,18.572c-0.478,0.277-0.642,0.889-0.365,1.367c0.275,0.479,0.889,0.641,1.365,0.365c0.479-0.275,0.643-0.887,0.367-1.367C9.27,18.461,8.658,18.297,8.179,18.572z" +
-		/* 10 */ "M9.18,10.696c-0.479-0.276-1.09-0.112-1.366,0.366s-0.111,1.09,0.365,1.366c0.479,0.276,1.09,0.113,1.367-0.366C9.821,11.584,9.657,10.973,9.18,10.696z" +
-		/*  2 */ "M22.822,12.428c0.478-0.275,0.643-0.888,0.366-1.366c-0.275-0.478-0.89-0.642-1.366-0.366c-0.479,0.278-0.642,0.89-0.366,1.367C21.732,12.54,22.344,12.705,22.822,12.428z" +
-		/*  7 */ "M12.062,21.455c-0.478-0.275-1.089-0.111-1.366,0.367c-0.275,0.479-0.111,1.09,0.366,1.365c0.478,0.277,1.091,0.111,1.365-0.365C12.704,22.344,12.54,21.732,12.062,21.455z" +
-		/* 11 */ "M12.062,9.545c0.479-0.276,0.642-0.888,0.366-1.366c-0.276-0.478-0.888-0.642-1.366-0.366s-0.642,0.888-0.366,1.366C10.973,9.658,11.584,9.822,12.062,9.545z" +
-		/*  4 */ "M22.823,18.572c-0.48-0.275-1.092-0.111-1.367,0.365c-0.275,0.479-0.112,1.092,0.367,1.367c0.477,0.275,1.089,0.113,1.365-0.365C23.464,19.461,23.3,18.848,22.823,18.572z" +
-		/*  2 */ "M19.938,7.813c-0.477-0.276-1.091-0.111-1.365,0.366c-0.275,0.48-0.111,1.091,0.366,1.367s1.089,0.112,1.366-0.366C20.581,8.702,20.418,8.089,19.938,7.813z" +
-		/*  3 */ "M23.378,14.5c-0.554,0.002-1.001,0.45-1.001,1c0.001,0.552,0.448,1,1.001,1c0.551,0,1-0.447,1-1C24.378,14.949,23.929,14.5,23.378,14.5z" +
-		/* arrows */ "M15.501,6.624c-0.552,0-1,0.448-1,1l-0.466,7.343l-3.004,1.96c-0.478,0.277-0.642,0.889-0.365,1.365c0.275,0.479,0.889,0.643,1.365,0.367l3.305-1.676C15.39,16.99,15.444,17,15.501,17c0.828,0,1.5-0.671,1.5-1.5l-0.5-7.876C16.501,7.072,16.053,6.624,15.501,6.624z" +
-		/*  9 */ "M15.501,22.377c-0.552,0-1,0.447-1,1s0.448,1,1,1s1-0.447,1-1S16.053,22.377,15.501,22.377z" +
-		/*  8 */ "M18.939,21.455c-0.479,0.277-0.643,0.889-0.366,1.367c0.275,0.477,0.888,0.643,1.366,0.365c0.478-0.275,0.642-0.889,0.366-1.365C20.028,21.344,19.417,21.18,18.939,21.455z" +
-		"");
-		clock.attr({fill: Color.black, stroke: "none"});
-		//clock.transform("t " + (cx-29.75/2) + " " + (cy-29.75/2));
-		//clock.transform("...s 0.85");
-		
-		//clock.transform("...s " + .85 + " " + .85);
-		clock.transform("t " + (-2.374) + " " + (-2.374)	);
-		clock.transform("...t -" + (15.5-2.374) + " -" + (15.5-2.374)	);
-		clock.transform("...s " + 1*(width/35) + " " + 1*(height/35));
-		clock.transform("...T " + cx + " " + cy);
-		//clock.transform("t " + (cx-width/2) + " " + (cy-height/2));
-		
-		//console.log(".getBBox(): ", clock.getBBox());
-		//console.log(".attr(): ", c.attrs);
-		circle.attr("rx", clock.getBBox().width/2);
-		circle.attr("ry", clock.getBBox().height/2);
-		
-		//return circle
-	},
-	
-	_drawPentagon: function(cx, cy, width, height, filled){
-		// draw GeneralPath (polygon)
-	    var n=5;
-	    var angle = 2*Math.PI/n;
-	    var waypoints = [];
-		
-		for ( var index = 0; index < n; index++ ) {
-			var v = index*angle - Math.PI/2;
-			var point = {};
-			point.x = -width*1.2/2 + parseInt(Math.round(width*1.2/2)) + parseInt(Math.round((width*1.2/4)*Math.cos(v)));
-        	point.y = -height*1.2/2 + parseInt(Math.round(height*1.2/2)) + parseInt(Math.round((height*1.2/4)*Math.sin(v)));
-			waypoints[index] = point;
-		}
-		
-		var polygone = new Polygone(waypoints, this.getStroke());
-		polygone.element = this.g.path(polygone.path);
-		if (filled)
-			polygone.element.attr("fill", Color.black);
-		else
-			polygone.element.attr("fill", Color.white);
-		
-		polygone.element.transform("s " + 1*(width/35) + " " + 1*(height/35));
-		polygone.element.transform("...T " + cx + " " + cy);
-	},
-	
-	//_drawMultilineText: function(text, x, y, boxWidth, boxHeight, textAnchor) {
-	_drawMultilineText: function(text, x, y, boxWidth, boxHeight, verticalAlign, horizontalAlign) {
-		if (!text || text == "") 
-			return;
-			
-		// Autostretch boxHeight if boxHeight is 0
-		if (boxHeight == 0)
-		  verticalAlign = MULTILINE_VERTICAL_ALIGN_TOP;	  
-	
-		//var TEXT_PADDING = 3;
-		var width = boxWidth;
-		if (boxHeight)
-			var height = boxHeight;
-	
-		var layouts = [];
-		
-		//var font = {font: "11px Arial", opacity: 1, "fill": LABEL_COLOR};
-		var font = this.getFont();
-		var measurer = new LineBreakMeasurer(this.g, x, y, text, font);
-		var lineHeight = measurer.rafaelTextObject.getBBox().height;
-		//console.log("text: ", text.replace(/\n/g, "?"));
-		
-		if (height) {
-			var availableLinesCount = parseInt(height/lineHeight);
-			//console.log("availableLinesCount: " + availableLinesCount);
-		}
-		
-		var i = 1;
-		while (measurer.getPosition() < measurer.text.getEndIndex()) {
-			var layout = measurer.nextLayout(width);
-			//console.log("LAYOUT: " + layout + ", getPosition: " + measurer.getPosition());
-			
-			if (layout != null) {
-				// TODO: and check if measurer has next layout. If no then don't draw  dots
-				if (!availableLinesCount || i < availableLinesCount) {
-					layouts.push(layout);
-				} else {
-					layouts.push(this.fitTextToWidth(layout + "...", boxWidth));
-					break;
-				}
-			}
-			i++;
-		};
-		//console.log(layouts);
-		
-		measurer.rafaelTextObject.attr({"text": layouts.join("\n")});
-		
-		if (horizontalAlign)
-			measurer.rafaelTextObject.attr({"text-anchor": horizontalAlign}); // end, middle, start
-			
-		var bb = measurer.rafaelTextObject.getBBox();
-		// TODO: there is somethin wrong with wertical align. May be: measurer.rafaelTextObject.attr({"y": y + height/2 - bb.height/2})
-		measurer.rafaelTextObject.attr({"y": y + bb.height/2});
-		//var bb = measurer.rafaelTextObject.getBBox();
-		
-		if (measurer.rafaelTextObject.attr("text-anchor") == MULTILINE_HORIZONTAL_ALIGN_MIDDLE )
-			measurer.rafaelTextObject.attr("x",  x +  boxWidth/2);
-		else if (measurer.rafaelTextObject.attr("text-anchor") == MULTILINE_HORIZONTAL_ALIGN_RIGHT )
-			measurer.rafaelTextObject.attr("x",  x +  boxWidth);
-		
-		var boxStyle = {stroke: Color.LightSteelBlue2, "stroke-width": 1.0, "stroke-dasharray": "- "};
-		//var box = this.g.rect(x+.5, y + .5, width, height).attr(boxStyle);
-		var textAreaCX = x + boxWidth/2;
-				var height = boxHeight;
-				if (!height) height = bb.height;
-				var textAreaCY = y + height/2;
-				var dotLeftTop = this.g.ellipse(x, y, 3, 3).attr({"stroke-width": 0, fill: Color.LightSteelBlue, stroke: "none"}).hide();
-				var dotCenter = this.g.ellipse(textAreaCX, textAreaCY, 3, 3).attr({fill: Color.LightSteelBlue2, stroke: "none"}).hide();
-
-				/*
-				// real bbox
-				var bb = measurer.rafaelTextObject.getBBox();
-				var rect = paper.rect(bb.x+.5, bb.y + .5, bb.width, bb.height).attr({"stroke-width": 1});
-				*/
-				var rect = this.g.rect(x, y, boxWidth, height).attr({"stroke-width": 1}).attr(boxStyle).hide();
-				var debugSet = this.g.set();
-				debugSet.push(dotLeftTop, dotCenter, rect);
-				//debugSet.show();
-	},
-	
-	drawTextAnnotation: function(text, x, y, width, height){
-		var lineLength = 18;
-		var path = [];
-		  path.push(["M", x + lineLength, y]);
-		  path.push(["L", x, y]);
-		  path.push(["L", x, y + height]);
-		  path.push(["L", x + lineLength, y + height]);
-		  
-		  path.push(["L", x + lineLength, y + height -1]);
-		  path.push(["L", x + 1, y + height -1]);
-		  path.push(["L", x + 1, y + 1]);
-		  path.push(["L", x + lineLength, y + 1]);
-		  path.push(["z"]);
-	
-		var textAreaLines = this.g.path(path);
-		
-	  var boxWidth = width - (2 * ANNOTATION_TEXT_PADDING);
-      var boxHeight = height - (2 * ANNOTATION_TEXT_PADDING);
-      var boxX = x + width/2 - boxWidth/2;
-      var boxY = y + height/2 - boxHeight/2;
-      
-      // for debug
-          var rectStyle = {stroke: Color(112, 146, 190), "stroke-width": 1.0, "stroke-dasharray": "- "};
-          var r = this.g.rect(boxX, boxY, boxWidth, boxHeight).attr(rectStyle);
-	  //
-      
-	  this.drawAnnotationText(text, boxX, boxY, boxWidth, boxHeight);
-	},
-	
-	drawLabel111111111: function(text, x, y, width, height, labelAttrs){
-		var  debug = false;
-		
-		// text
-		if (text != null && text != undefined && text != "") {
-			var attr = LABEL_FONT;
-			
-			//console.log("x", x, "y", y, "width", width, "height", height );
-			
-			wrappedText = text;
-			if (labelAttrs && labelAttrs.wrapWidth) {
-				wrappedText = this.wrapTextToWidth(wrappedText, labelAttrs.wrapWidth);
-			}
-			var realWidth = this.getStringWidth(wrappedText, attr);
-			var realHeight = this.getStringHeight(wrappedText, attr);
-			
-			var textAreaCX = x + width/2;
-			var textAreaCY = y + 3 + height + this.getStringHeight(wrappedText, attr)/2;
-			
-			var textX = textAreaCX;
-			var textY = textAreaCY;
-
-			var textAttrs = {};
-			if (labelAttrs && labelAttrs.align) {
-				switch (labelAttrs.align) {
-					case "left": 
-						textAttrs["text-anchor"] = "start"; 
-						textX = textX - realWidth/2;
-					break;
-					case "center": 
-						textAttrs["text-anchor"] = "middle"; 
-					break;
-					case "right": 
-						textAttrs["text-anchor"] = "end"; 
-						textX = textX + realWidth/2;
-					break;
-				}
-			}
-			if (labelAttrs && labelAttrs.wrapWidth) {
-				if (true) {
-					// Draw frameborder
-					var textAreaStyle = {stroke: Color.LightSteelBlue2, "stroke-width": 1.0, "stroke-dasharray": "- "};
-					var textAreaX = textAreaCX - realWidth/2;
-					var textAreaY = textAreaCY+.5 - realHeight/2;
-					var textArea = this.g.rect(textAreaX, textAreaY, realWidth, realHeight).attr(textAreaStyle);
-					
-					var textAreaLines = this.g.path("M" + textAreaX + " " + textAreaY + "L" + (textAreaX+realWidth) + " " + (textAreaY+realHeight) + "M" +  + (textAreaX+realWidth) + " " + textAreaY + "L" + textAreaX + " " + (textAreaY+realHeight));
-					textAreaLines.attr(textAreaStyle);
-					
-					this.g.ellipse(textAreaCX, textAreaCY, 3, 3).attr({fill: Color.LightSteelBlue2, stroke: "none"});
-				}
-			}
-			
-			var label = this.g.text(textX, textY, wrappedText).attr(attr).attr(textAttrs);
-			//label.id = Raphael.createUUID();
-			//console.log("label ", label.id, ", ", wrappedText);
-			
-			if (this.fontSmoothing) {
-				label.attr({stroke: LABEL_COLOR, "stroke-width":.4});
-			}
-			
-			// debug
-			if (debug) {
-				var imageAreaStyle = {stroke: Color.grey61, "stroke-width": 1.0, "stroke-dasharray": "- "};
-				var imageArea = this.g.rect(x+.5, y+.5, width, height).attr(imageAreaStyle);
-				var imageAreaLines = this.g.path("M" + x + " " + y + "L" + (x+width) + " " + (y+height) + "M" +  + (x+width) + " " + y + "L" + x + " " + (y+height));
-				imageAreaLines.attr(imageAreaStyle);
-				var dotStyle = {fill: Color.Coral, stroke: "none"};
-				this.g.ellipse(x, y, 3, 3).attr(dotStyle);
-				this.g.ellipse(x+width, y, 2, 2).attr(dotStyle);
-				this.g.ellipse(x+width, y+height, 2, 2).attr(dotStyle);
-				this.g.ellipse(x, y+height, 2, 2).attr(dotStyle);
-			}
-			
-			return label;
-		}
-	},
-	
-	vvoid: function(){}
-};

+ 0 - 1087
unimall-admin-api/src/main/resources/diagram-viewer/js/ProcessDiagramGenerator.js

@@ -1,1087 +0,0 @@
- /**
- * Class to generate an image based the diagram interchange information in a
- * BPMN 2.0 process.
- *
- * @author (Javascript) Dmitry Farafonov
- */
- 
-var ProcessDiagramGenerator = {	
-	options: {},
-	
-	processDiagramCanvas: [],
-	
-	activityDrawInstructions:{},
-	
-	processDiagrams: {},
-	
-	diagramBreadCrumbs: null,
-	
-	init: function(){
-		// start event
-		this.activityDrawInstructions["startEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawNoneStartEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-		
-		// start timer event
-		this.activityDrawInstructions["startTimerEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isInterrupting = activityImpl.getProperty("isInterrupting");
-			processDiagramCanvas.drawTimerStartEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, activityImpl.getProperty("name"));
-		};
-		
-		// start event
-		this.activityDrawInstructions["messageStartEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isInterrupting = activityImpl.getProperty("isInterrupting");
-			processDiagramCanvas.drawMessageStartEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, activityImpl.getProperty("name"));
-		};
-		
-		// start signal event
-		this.activityDrawInstructions["startSignalEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isInterrupting = activityImpl.getProperty("isInterrupting");
-			processDiagramCanvas.drawSignalStartEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, activityImpl.getProperty("name"));
-		};
-		
-		// start multiple event
-		this.activityDrawInstructions["startMultipleEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isInterrupting = activityImpl.getProperty("isInterrupting");
-			processDiagramCanvas.drawMultipleStartEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, activityImpl.getProperty("name"));
-		};
-		
-		// signal catch
-		this.activityDrawInstructions["intermediateSignalCatch"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isInterrupting = activityImpl.getProperty("isInterrupting");
-			processDiagramCanvas.drawCatchingSignalEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, null);
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-			if (label)
-			  processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// message catch
-		this.activityDrawInstructions["intermediateMessageCatch"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isInterrupting = activityImpl.getProperty("isInterrupting");
-			processDiagramCanvas.drawCatchingMessageEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, null);
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// multiple catch
-		this.activityDrawInstructions["intermediateMultipleCatch"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isInterrupting = activityImpl.getProperty("isInterrupting");
-			processDiagramCanvas.drawCatchingMultipleEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, null);
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		
-		
-		// signal throw
-		this.activityDrawInstructions["intermediateSignalThrow"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawThrowingSignalEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), activityImpl.getProperty("name"));
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// message throw
-		this.activityDrawInstructions["intermediateMessageThrow"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawThrowingMessageEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), activityImpl.getProperty("name"));
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// multiple throw
-		this.activityDrawInstructions["intermediateMultipleThrow"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawThrowingMultipleEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), activityImpl.getProperty("name"));
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// none throw
-		this.activityDrawInstructions["intermediateThrowEvent"] = function() {
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawThrowingNoneEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), activityImpl.getProperty("name"));
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// end event
-		this.activityDrawInstructions["endEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawNoneEndEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-		
-		// error end event
-		this.activityDrawInstructions["errorEndEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawErrorEndEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), null);
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// message end event
-		this.activityDrawInstructions["messageEndEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawMessageEndEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), null);
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// signal end event
-		this.activityDrawInstructions["signalEndEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawSignalEndEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), null);
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// multiple end event
-		this.activityDrawInstructions["multipleEndEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawMultipleEndEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), null);
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// terminate end event
-		this.activityDrawInstructions["terminateEndEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawTerminateEndEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// error start event
-		this.activityDrawInstructions["errorStartEvent"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawErrorStartEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), activityImpl.getProperty("name"));
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// task
-		this.activityDrawInstructions["task"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			// TODO: 
-			//console.error("task is not implemented yet");
-			/*
-			var activityImpl = this;
-			processDiagramCanvas.drawTask(activityImpl.getProperty("name"), activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), thickBorder);
-			*/
-		};
-		
-		
-		// user task
-		this.activityDrawInstructions["userTask"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawUserTask(activityImpl.getProperty("name"), activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-		
-		// script task
-		this.activityDrawInstructions["scriptTask"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawScriptTask(activityImpl.getProperty("name"), activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-		
-		// service task
-		this.activityDrawInstructions["serviceTask"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawServiceTask(activityImpl.getProperty("name"), activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-
-		// receive task
-		this.activityDrawInstructions["receiveTask"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawReceiveTask(activityImpl.getProperty("name"), activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-		
-		// send task
-		this.activityDrawInstructions["sendTask"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawSendTask(activityImpl.getProperty("name"), activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-
-		// manual task
-		this.activityDrawInstructions["manualTask"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-		
-			processDiagramCanvas.drawManualTask(activityImpl.getProperty("name"), activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-
-		// businessRuleTask task
-		this.activityDrawInstructions["businessRuleTask"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawBusinessRuleTask(activityImpl.getProperty("name"), activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-
-		// exclusive gateway
-		this.activityDrawInstructions["exclusiveGateway"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawExclusiveGateway(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-		
-		// inclusive gateway
-		this.activityDrawInstructions["inclusiveGateway"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawInclusiveGateway(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-		
-		// parallel gateway
-		this.activityDrawInstructions["parallelGateway"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawParallelGateway(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-		
-		// eventBasedGateway
-		this.activityDrawInstructions["eventBasedGateway"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			processDiagramCanvas.drawEventBasedGateway(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-		
-		// Boundary timer
-		this.activityDrawInstructions["boundaryTimer"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isInterrupting = activityImpl.getProperty("isInterrupting");
-			processDiagramCanvas.drawCatchingTimerEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, null);
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// Boundary catch error
-		this.activityDrawInstructions["boundaryError"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isInterrupting = activityImpl.getProperty("isInterrupting");
-			processDiagramCanvas.drawCatchingErrorEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, null);
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-		
-		// Boundary signal event
-		this.activityDrawInstructions["boundarySignal"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isInterrupting = activityImpl.getProperty("isInterrupting");
-			processDiagramCanvas.drawCatchingSignalEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, null);
-			
-			var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-      if (label)
-        processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-		};
-
-    // Boundary message event
-    this.activityDrawInstructions["boundaryMessage"] = function(){
-        var activityImpl = this.activity;
-        var processDiagramCanvas = this.processDiagramCanvas;
-        processDiagramCanvas.setConextObject(activityImpl);
-
-        var isInterrupting = activityImpl.getProperty("isInterrupting");
-        processDiagramCanvas.drawCatchingMessageEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, null);
-
-        var label = ProcessDiagramGenerator.getActivitiLabel(activityImpl);
-        if (label)
-            processDiagramCanvas.drawLabel(label.text, label.x, label.y, label.width, label.height);
-    };
-		
-		// timer catch event
-		this.activityDrawInstructions["intermediateTimer"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isInterrupting = null;
-			processDiagramCanvas.drawCatchingTimerEvent(activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight(), isInterrupting, activityImpl.getProperty("name"));
-		};
-		
-		// subprocess
-		this.activityDrawInstructions["subProcess"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			// TODO: 
-			
-			processDiagramCanvas.setConextObject(activityImpl);
-			
-			var isExpanded = activityImpl.getProperty("isExpanded");
-			var isTriggeredByEvent = activityImpl.getProperty("triggeredByEvent");
-			if(isTriggeredByEvent == undefined) {
-			  isTriggeredByEvent = true;
-			}
-			// TODO: check why isTriggeredByEvent = true when undefined
-			isTriggeredByEvent = false;
-			
-			if (isExpanded != undefined && isExpanded == false) {
-			  processDiagramCanvas.drawCollapsedSubProcess(activityImpl.getProperty("name"), activityImpl.getX(), activityImpl.getY(),
-					  activityImpl.getWidth(), activityImpl.getHeight(), isTriggeredByEvent);
-			} else {
-			  processDiagramCanvas.drawExpandedSubProcess(activityImpl.getProperty("name"), activityImpl.getX(), activityImpl.getY(),
-					  activityImpl.getWidth(), activityImpl.getHeight(), isTriggeredByEvent);
-			}
-			
-			//console.error("subProcess is not implemented yet");
-		};
-		
-		// call activity
-		this.activityDrawInstructions["callActivity"] = function(){
-			var activityImpl = this.activity;
-			var processDiagramCanvas = this.processDiagramCanvas;
-			processDiagramCanvas.setConextObject(activityImpl);
-			processDiagramCanvas.drawCollapsedCallActivity(activityImpl.getProperty("name"), activityImpl.getX(), activityImpl.getY(), activityImpl.getWidth(), activityImpl.getHeight());
-		};
-		
-		$(document).ready(function(){
-		  // Protect right click on SVG elements (and on canvas too)
-		  document.body.oncontextmenu = function(event) {
-		    if (window.event.srcElement.tagName == "shape" || window.event.srcElement.tagName == "DIV" && window.event.srcElement.parentElement.className == "diagram") {
-
-		      // IE DIAGRAM CANVAS OR SHAPE DETECTED!
-		      return false;
-		    }
-		    return (!Object.isSVGElement(window.event.srcElement));
-		  };
-		});
-	},
-	
-	 getActivitiLabel:function(activityImpl){
-	   /*
-	     TODO: Label object should be in activityImpl and looks like:
-	     {
-	       x: 250,
-	       y: 250,
-	       width: 80,
-	       height: 30
-	     }
-	     And then:
-	     if (!activityImpl.label)
-	       return null;
-	     var label = activityImpl.label;
-	     label.text = activityImpl.name;
-	     return label;
-	   */
-
-	   // But now default label for all events is:
-	   return {
-	     text: activityImpl.getProperty("name"),
-	     x: activityImpl.getX() + .5 + activityImpl.getWidth()/2,
-	     y: activityImpl.getY() + .5 + activityImpl.getHeight() + ICON_PADDING,
-	     width: 100,
-	     height: 0
-	   };
-	},
-		
-	generateDiagram: function(processDefinitionDiagramLayout){
-		// Init canvas
-		var processDefinitionId = processDefinitionDiagramLayout.processDefinition.id;
-		//console.log("Init canvas ", processDefinitionId);
-		
-		if (this.getProcessDiagram(processDefinitionId) != undefined) {
-			// TODO: may be reset canvas if exists.. Or just show
-			//console.log("ProcessDiagram '" + processDefinitionId + "' is already generated. Just show it.");
-			return;
-		}
-		var processDiagram = this.initProcessDiagramCanvas(processDefinitionDiagramLayout);
-		var processDiagramCanvas = processDiagram.diagramCanvas;
-		
-		// Draw pool shape, if process is participant in collaboration
-		
-		if(processDefinitionDiagramLayout.participantProcess != undefined) {
-		  //console.log("Draw pool shape");
-		  var pProc = processDefinitionDiagramLayout.participantProcess;
-		  processDiagramCanvas.drawPoolOrLane(pProc.x, pProc.y, pProc.width, pProc.height, pProc.name);
-		}
-		
-		var laneSets = processDefinitionDiagramLayout.laneSets;
-		var activities = processDefinitionDiagramLayout.activities;
-		var sequenceFlows = processDefinitionDiagramLayout.sequenceFlows;
-		
-		
-		pb1.set('value', 0);
-		var cnt = 0;
-		if (laneSets) 
-			for(var i in laneSets) {
-				cnt += laneSets[i].lanes.length;
-			}
-		if (activities) 
-			cnt += activities.length;
-		if (sequenceFlows) 
-			cnt += sequenceFlows.length;
-		var step = (cnt>0)? 100/cnt : 0;
-		var progress = 0;
-		//console.log("progress bar step: ", step);
-		
-		var task1 = new $.AsyncQueue();
-		
-			// Draw lanes
-			
-			task1.add(function (task1) {
-				if (!laneSets) laneSets = [];
-				//console.log("> draw lane sets, count:", laneSets.length)
-			});
-			
-			for(var i in laneSets) {
-				var laneSet = laneSets[i];
-				//laneSet.id, laneSet.name
-				
-				task1.add(laneSet.lanes,function (task1, lane) {
-					progress += step;
-					pb1.set('value', parseInt(progress));
-					
-					//console.log("--> laneId: " + lane.name + ", name: " + lane.name);
-					
-					processDiagramCanvas.drawPoolOrLane(lane.x, lane.y, lane.width, lane.height, lane.name);
-				});
-			}
-			
-			// Draw activities
-			
-			task1.add(function (task1) {
-				if (!activities) activities = [];
-				//console.log("> draw activities, count:", activities.length)
-			});
-			
-			var activitiesLength = activities.length;
-			task1.add(activities,function (task1, activityJson) {
-				var activity = new ActivityImpl(activityJson);
-				activitiesLength --;
-				progress += step;
-				pb1.set('value', parseInt(progress));
-				//console.log(activitiesLength, "--> activityId: " + activity.getId() + ", name: " + activity.getProperty("name"));
-				ProcessDiagramGenerator.drawActivity(processDiagramCanvas, activity);
-			});
-			
-			// Draw sequence-flows
-			
-			task1.add(function (task1) {
-				if (!sequenceFlows) sequenceFlows = [];
-				//console.log("> draw sequence flows, count:", sequenceFlows.length)
-			});
-			
-			var flowsLength = sequenceFlows.length;
-			task1.add(sequenceFlows,function (task1, flow) {
-				var waypoints = [];
-				for(var j in flow.xPointArray) {
-					waypoints[j] = {x: flow.xPointArray[j], y: flow.yPointArray[j]};
-				}
-				var isDefault = flow.isDefault;
-				var isConditional = flow.isConditional;
-				var isHighLighted = flow.isHighLighted;
-				
-				// TODO: add source and destination for sequence flows in REST
-				// parse for test
-					var f = flow.flow;
-					var matches = f.match(/\((.*)\)--.*-->\((.*)\)/);
-					var sourceActivityId, destinationActivityId;
-					if (matches != null) {
-						sourceActivityId = matches[1];
-						destinationActivityId = matches[2];
-					}
-					flow.sourceActivityId = sourceActivityId;
-					flow.destinationActivityId = destinationActivityId;
-				//
-				flowsLength--;
-				progress += step;
-				pb1.set('value', parseInt(progress));
-				
-				//console.log(flowsLength, "--> flow: " + flow.flow);
-				
-				processDiagramCanvas.setConextObject(flow);
-				processDiagramCanvas.drawSequenceflow(waypoints, isConditional, isDefault, isHighLighted);
-			});
-			
-			task1.onComplete(function(){
-				if (progress<100)
-					pb1.set('value', 100);
-				//console.log("COMPLETE!!!");
-					
-				//console.timeEnd('generateDiagram');
-			});
-			
-			task1.run();
-	},
-	
-	getProcessDiagram: function (processDefinitionId) {
-		return this.processDiagrams[processDefinitionId];
-	},
-	
-	initProcessDiagramCanvas: function (processDefinitionDiagramLayout) {
-		var minX = 0;
-		var maxX = 0;
-		var minY = 0;
-		var maxY = 0;
-		
-		if(processDefinitionDiagramLayout.participantProcess != undefined) {
-		  var pProc = processDefinitionDiagramLayout.participantProcess;
-		  
-		  minX = pProc.x;
-		  maxX = pProc.x + pProc.width;
-		  minY = pProc.y;
-		  maxY = pProc.y + pProc.height;
-		}
-
-		var activities = processDefinitionDiagramLayout.activities;
-		for(var i in activities) {
-			var activityJson = activities[i];
-			var activity = new ActivityImpl(activityJson);
-			
-			// width
-			if (activity.getX() + activity.getWidth() > maxX) {
-				maxX = activity.getX() + activity.getWidth();
-			}
-			if (activity.getX() < minX) {
-				minX = activity.getX();
-			}
-			// height
-			if (activity.getY() + activity.getHeight() > maxY) {
-				maxY = activity.getY() + activity.getHeight();
-			}
-			if (activity.getY() < minY) {
-				minY = activity.getY();
-			}
-		}
-		
-		var sequenceFlows = processDefinitionDiagramLayout.sequenceFlows;
-		for(var i in sequenceFlows) {
-			var flow = sequenceFlows[i];
-			var waypoints = [];
-			for(var j in flow.xPointArray) {
-				waypoints[j] = {x: flow.xPointArray[j], y: flow.yPointArray[j]};
-				
-				// width
-				if (waypoints[j].x > maxX) {
-					maxX = waypoints[j].x;
-				}
-				if (waypoints[j].x < minX) {
-					minX = waypoints[j].x;
-				}
-				// height
-				if (waypoints[j].y > maxY) {
-					maxY = waypoints[j].y;
-				}
-				if (waypoints[j].y < minY) {
-					minY = waypoints[j].y;
-				}
-			}
-		}
-		
-		var laneSets = processDefinitionDiagramLayout.laneSets;
-		for(var i in laneSets) {
-			var laneSet = laneSets[i];
-			//laneSet.id, laneSet.name
-			
-			for(var j in laneSet.lanes) {
-				var lane = laneSet.lanes[j];
-				// width
-				if (lane.x + lane.width > maxX) {
-				  maxX = lane.x + lane.width;
-				}
-				if (lane.x < minX) {
-				  minX = lane.x;
-				}
-				// height
-				if (lane.y + lane.height > maxY) {
-				  maxY = lane.y + lane.height;
-				}
-				if (lane.y < minY) {
-				  minY = lane.y;
-				}
-			}
-		}
-	
-		var diagramCanvas = new ProcessDiagramCanvas();
-		if (diagramCanvas) {
-			
-			// create div in diagramHolder
-			var diagramHolder = document.getElementById(this.options.diagramHolderId);
-			if (!diagramHolder)
-				throw {msg: "Diagram holder not found", error: "diagramHolderNotFound"};
-			var div = document.createElement("DIV");
-			div.id = processDefinitionDiagramLayout.processDefinition.id;
-			div.className = "diagram";
-			diagramHolder.appendChild(div);
-			
-			diagramCanvas.init(maxX + 20, maxY + 20, processDefinitionDiagramLayout.processDefinition.id);
-			this.processDiagrams[processDefinitionDiagramLayout.processDefinition.id] = {
-				processDefinitionDiagramLayout: processDefinitionDiagramLayout,
-				diagramCanvas: diagramCanvas
-			};
-		}
-		return this.getProcessDiagram(processDefinitionDiagramLayout.processDefinition.id);
-		//return new DefaultProcessDiagramCanvas(maxX + 10, maxY + 10, minX, minY);
-	},
-	
-	drawActivity: function(processDiagramCanvas, activity, highLightedActivities) {
-		var type = activity.getProperty("type");
-		var drawInstruction = this.activityDrawInstructions[type];
-		if (drawInstruction != null) {	
-			drawInstruction.apply({processDiagramCanvas:processDiagramCanvas, activity:activity});
-		} else {
-			//console.error("no drawInstruction for " + type + ": ", activity);
-		}
-		
-		// Actually draw the markers
-		if (activity.getProperty("multiInstance") != undefined || activity.getProperty("collapsed") != undefined) {
-			//console.log(activity.getProperty("name"), activity.properties);
-			var multiInstanceSequential = (activity.getProperty("multiInstance") == "sequential");
-			var multiInstanceParallel = (activity.getProperty("multiInstance") == "parrallel");
-			var collapsed = activity.getProperty("collapsed");
-				processDiagramCanvas.drawActivityMarkers(activity.getX(), activity.getY(), activity.getWidth(), activity.getHeight(), 
-					multiInstanceSequential, multiInstanceParallel, collapsed);
-		}
-		/*
-		processDiagramCanvas.drawActivityMarkers(activity.getX(), activity.getY(), activity.getWidth(), activity.getHeight(), multiInstanceSequential,
-              multiInstanceParallel, collapsed);
-		*/
-
-		// TODO: Draw highlighted activities if they are present
-		
-	},
-	
-	setHighLights: function(highLights){
-		if (highLights.processDefinitionId == undefined) {
-			//console.error("Process instance " + highLights.processInstanceId + " doesn't exist");
-			return;
-		}
-		
-		var processDiagram = this.getProcessDiagram(highLights.processDefinitionId);
-		if (processDiagram == undefined) {
-			//console.error("Process diagram " + highLights.processDefinitionId + " not found");
-			return;
-		}
-		
-		var processDiagramCanvas = processDiagram.diagramCanvas;
-		
-		// TODO: remove highLightes from all activities before set new highLight
-		for (var i in highLights.activities) {
-			var activityId = highLights.activities[i];
-			processDiagramCanvas.highLightActivity(activityId);
-		}
-		
-		// TODO: remove highLightes from all flows before set new highLight
-		for (var i in highLights.flows) {
-			var flowId = highLights.flows[i];
-			var object = processDiagramCanvas.g.getById(flowId);
-			var flow = object.data("contextObject");
-			flow.isHighLighted = true;
-			processDiagramCanvas.highLightFlow(flowId);
-		}
-	},
-	
-	drawHighLights: function(processInstanceId) {
-		// Load highLights for the processInstanceId
-		/*
-		var url = Lang.sub(this.options.processInstanceHighLightsUrl, {processInstanceId: processInstanceId});
-		$.ajax({
-			url: url,
-			type: 'GET',
-			dataType: 'json',
-			cache: false,
-			async: true,
-		}).done(function(data) {
-			var highLights = data;
-			if (!highLights) {
-				console.log("highLights not found");
-				return;
-			}
-			
-			console.log("highLights[" + highLights.processDefinitionId + "][" + processInstanceId + "]: ", highLights);
-			
-			ProcessDiagramGenerator.setHighLights(highLights);
-		}).fail(function(jqXHR, textStatus){
-			console.log('Get HighLights['+processDefinitionId+'] failure: ', textStatus, jqXHR);
-		});
-		*/
-		ActivitiRest.getHighLights(processInstanceId, this._drawHighLights);
-	},
-	_drawHighLights: function() {
-		var highLights = this.highLights;
-		ProcessDiagramGenerator.setHighLights(highLights);
-	},
-	
-	// Load processDefinition
-	
-	drawDiagram: function(processDefinitionId) {
-		// Hide all diagrams
-		var diagrams = $("#" + this.options.diagramHolderId + " div.diagram");
-		diagrams.addClass("hidden");
-	
-	
-		// If processDefinitionId doesn't contain ":" then it's a "processDefinitionKey", not an id.
-		// Get process definition by key
-		if (processDefinitionId.indexOf(":") < 0) {
-			ActivitiRest.getProcessDefinitionByKey(processDefinitionId, this._drawDiagram);
-		} else {
-			this._drawDiagram.apply({processDefinitionId: processDefinitionId});
-		}
-	},
-	_drawDiagram: function() {
-		var processDefinitionId = this.processDefinitionId;
-		
-		ProcessDiagramGenerator.addBreadCrumbsItem(processDefinitionId);
-		
-		
-		// Check if processDefinition is already loaded and rendered
-		
-		
-		var processDiagram = ProcessDiagramGenerator.getProcessDiagram(processDefinitionId);
-
-		if (processDiagram != undefined && processDiagram != null) {
-			//console.log("Process diagram " + processDefinitionId + " is already loaded");
-			//return;
-			
-			var diagram = document.getElementById(processDefinitionId);
-			$(diagram).removeClass("hidden");
-			
-			// Regenerate image
-			var processDefinitionDiagramLayout = processDiagram.processDefinitionDiagramLayout;
-			ProcessDiagramGenerator.generateDiagram(processDefinitionDiagramLayout);
-			
-			return;
-		}
-
-		//console.time('loadDiagram');
-		
-		// Load processDefinition
-		
-		ActivitiRest.getProcessDefinition(processDefinitionId, ProcessDiagramGenerator._generateDiagram);
-	},
-	_generateDiagram: function() {
-		var processDefinitionDiagramLayout = this.processDefinitionDiagramLayout;
-		
-		//console.log("process-definition-diagram-layout["+processDefinitionDiagramLayout.processDefinition.id+"]: ", processDefinitionDiagramLayout);
-		
-		//console.timeEnd('loadDiagram');
-		//console.time('generateDiagram');
-		
-		pb1.set('value', 0);
-		ProcessDiagramGenerator.generateDiagram(processDefinitionDiagramLayout);
-	},
-	
-	getProcessDefinitionByKey: function(processDefinitionKey) {
-		var url = Lang.sub(this.options.processDefinitionByKeyUrl, {processDefinitionKey: processDefinitionKey});
-		
-		var processDefinition;
-		$.ajax({
-			url: url,
-			type: 'POST',
-			dataType: 'json',
-			cache: false,
-			async: false
-		}).done(function(data) { 
-			//console.log("ajax returned data");
-			//console.log("ajax returned data:", data);
-			processDefinition = data;
-			if (!processDefinition) {
-				//console.error("Process definition '" + processDefinitionKey + "' not found");
-			}
-		}).fail(function(jqXHR, textStatus){
-			//console.error('Get diagram layout['+processDefinitionKey+'] failure: ', textStatus, jqXHR);
-		});
-		
-		if (processDefinition) {
-			//console.log("Get process definition by key '" + processDefinitionKey + "': ", processDefinition.id);
-			return processDefinition;
-		} else {
-			return null;
-		}
-	},
-	
-	addBreadCrumbsItem: function(processDefinitionId){
-		var TPL_UL_CONTAINER = '<ul></ul>',
-			TPL_LI_CONTAINER = '<li id="{id}", processDefinitionId="{processDefinitionId}"><span>{name}</span></li>';
-		
-		if (!this.diagramBreadCrumbs)
-			this.diagramBreadCrumbs = $("#" + this.options.diagramBreadCrumbsId);
-		if (!this.diagramBreadCrumbs) return;
-		
-		
-		var ul = this.diagramBreadCrumbs.find("ul");
-		//console.log("ul: ", ul);
-		if (ul.size() == 0) {
-			ul = $(TPL_UL_CONTAINER);
-			this.diagramBreadCrumbs.append(ul);
-			
-		}
-		var liListOld = ul.find("li");
-		//console.warn("liListOld", liListOld);
-		
-		// TODO: if there is any items after current then remove that before adding new item (m.b. it is a duplicate)
-		var currentBreadCrumbsItemId = this.currentBreadCrumbsItemId;
-			found = false;
-		liListOld.each(
-			function(index, item) {
-				//console.warn("item:", $(this));
-				if (!found && currentBreadCrumbsItemId == $(this).attr("id")) {
-					found = true;
-					return;
-				}
-				if (found) {
-					//console.warn("remove ", $(this).attr("id"));
-					$(this).remove();
-				}
-			}
-		);
-		
-		var liListNew = ul.find("li");
-		
-		//console.log("liListNew size: ", liListNew.size());
-		var values = {
-			id: 'breadCrumbsItem_' + liListNew.size(),
-			processDefinitionId: processDefinitionId,
-			name: processDefinitionId
-		};
-		
-		
-		var tpl = Lang.sub(TPL_LI_CONTAINER, values);
-		//console.log("tpl: ", tpl);
-		ul.append(tpl);
-		
-		var li = ul.find("#" + values.id);
-		//console.warn("li:", li);
-		$('#' + values.id).on('click', this._breadCrumbsItemClick);
-		
-		ul.find("li").removeClass("selected");
-		li.attr("num", liListNew.size());
-		li.addClass("selected");
-		this.currentBreadCrumbsItemId = li.attr("id");
-	},
-	_breadCrumbsItemClick: function(){
-		var li = $(this),
-			id = li.attr("id"),
-			processDefinitionId = li.attr("processDefinitionId");
-		//console.warn("_breadCrumbsItemClick: ", id, ", processDefinitionId: ", processDefinitionId);
-		
-		var ul = ProcessDiagramGenerator.diagramBreadCrumbs.one("ul");
-		ul.find("li").removeClass("selected");
-		li.addClass("selected");
-		ProcessDiagramGenerator.currentBreadCrumbsItemId = li.attr("id");
-		
-		// Hide all diagrams
-		var diagrams = $("#"+ProcessDiagramGenerator.options.diagramHolderId+" div.diagram");
-		diagrams.addClass("hidden");
-		
-		var processDiagram = ProcessDiagramGenerator.getProcessDiagram(processDefinitionId);
-		
-		var diagram = document.getElementById(processDefinitionId);
-		if (!diagram) return;
-		$(diagram).removeClass("hidden");
-		
-		// Regenerate image
-		var processDefinitionDiagramLayout = processDiagram.processDefinitionDiagramLayout;
-		ProcessDiagramGenerator.generateDiagram(processDefinitionDiagramLayout);
-	},
-	
-	showFlowInfo: function(flow){
-		var diagramInfo = $("#" + this.options.diagramInfoId);
-		if (!diagramInfo) return;
-		
-		var values = {
-			flow: flow.flow,
-			isDefault: (flow.isDefault)? "true":"",
-			isConditional: (flow.isConditional)? "true":"",
-			isHighLighted: (flow.isHighLighted)? "true":"",
-			sourceActivityId: flow.sourceActivityId,
-			destinationActivityId: flow.destinationActivityId
-		};
-		var TPL_FLOW_INFO = '<div>{flow}</div>' 
-				+ '<div><b>sourceActivityId</b>: {sourceActivityId}</div>'
-				+ '<div><b>destinationActivityId</b>: {destinationActivityId}</div>'
-				+ '<div><b>isDefault</b>: {isDefault}</div>'
-				+ '<div><b>isConditional</b>: {isConditional}</div>'
-				+ '<div><b>isHighLighted</b>: {isHighLighted}</div>';
-		var tpl = Lang.sub(TPL_FLOW_INFO, values);
-		//console.log("info: ", tpl);
-		diagramInfo.html(tpl);
-	},
-	
-	showActivityInfo: function(activity){
-		var diagramInfo = $("#" + this.options.diagramInfoId);
-		if (!diagramInfo) return;
-		
-		var values = {
-			activityId: activity.getId(),
-			name: activity.getProperty("name"),
-			type: activity.getProperty("type")
-		};
-		var TPL_ACTIVITY_INFO = '' 
-				+ '<div><b>activityId</b>: {activityId}</div>'
-				+ '<div><b>name</b>: {name}</div>'
-				+ '<div><b>type</b>: {type}</div>';
-		var TPL_CALLACTIVITY_INFO = ''
-				+ '<div><b>collapsed</b>: {collapsed}</div>'
-				+ '<div><b>processDefinitonKey</b>: {processDefinitonKey}</div>';
-		
-		var template = TPL_ACTIVITY_INFO;
-		if (activity.getProperty("type") == "callActivity") {
-			values.collapsed = activity.getProperty("collapsed");
-			values.processDefinitonKey = activity.getProperty("processDefinitonKey");
-			template += TPL_CALLACTIVITY_INFO;
-		} else if (activity.getProperty("type") == "callActivity") {
-		
-		}
-				
-		var tpl = Lang.sub(template, values);
-		//console.log("info: ", tpl);
-		diagramInfo.html(tpl);
-	},
-	
-	hideInfo: function(){
-	  var diagramInfo = $("#" + this.options.diagramInfoId);
-	  if (!diagramInfo) return;
-	  diagramInfo.html("");
-	},
-	
-	vvoid: function(){}
-};
-
-var Lang = {
-	SUBREGEX: /\{\s*([^\|\}]+?)\s*(?:\|([^\}]*))?\s*\}/g,
-	UNDEFINED: 'undefined',
-	isUndefined: function(o) {
-		return typeof o === Lang.UNDEFINED;
-	},
-	sub: function(s, o) {
-		return ((s.replace) ? s.replace(Lang.SUBREGEX, function(match, key) {
-			return (!Lang.isUndefined(o[key])) ? o[key] : match;
-		}) : s);
-	}
-};
-
-if (Lang.isUndefined(console)) {
-    console = { log: function() {}, warn: function() {}, error: function() {}};
-}
-ProcessDiagramGenerator.init();

+ 0 - 125
unimall-admin-api/src/main/resources/diagram-viewer/js/jquery/jquery.asyncqueue.js

@@ -1,125 +0,0 @@
-/*
-* This file is part of the jquery plugin "asyncQueue".
-*
-* (c) Sebastien Roch <roch.sebastien@gmail.com>
-* @author (parallel) Dmitry Farafonov
-*
-* For the full copyright and license information, please view the LICENSE
-* file that was distributed with this source code.
-*/
-(function($){
-    $.AsyncQueue = function() {
-        var that = this,
-            queue = [],
-			completeFunc,
-            failureFunc,
-            paused = false,
-            lastCallbackData,
-            _run,
-			_complete,
-			inQueue = 0,
-			defaultTimeOut = 10;
-
-        _run = function() {
-            var f = queue.shift();
-
-            if (f) {
-				inQueue++;
-				setTimeout(function(){
-					f.fn.apply(that, [that]);
-				
-					if (!f.isParallel)
-						if (paused === false) {
-							_run();
-						}
-					inQueue --;
-					if (inQueue == 0 && queue.length == 0)
-						_complete();
-				}, f.timeOut);                
-				
-				if (f.isParallel)
-					if (paused === false) {
-						_run();
-					}
-            }
-        };
-		
-		_complete = function(){
-			if (completeFunc)
-					completeFunc.apply(that, [that]);
-		};
-
-		this.onComplete = function(func) {
-            completeFunc = func;
-        };
-		
-		this.onFailure = function(func) {
-            failureFunc = func;
-        };
-
-        this.add = function(func) {
-			// TODO: add callback for queue[i] complete
-			
-			var obj = arguments[0];
-			if (obj && Object.prototype.toString.call(obj) === "[object Array]") {
-				var fn = arguments[1];
-				var timeOut = (typeof(arguments[2]) != "undefined")? arguments[2] : defaultTimeOut;
-				if (typeof(fn) == "function") {
-					for(var i = 0; i < obj.length; i++) {
-						var f = function(objx){
-							queue.push({isParallel: true, fn: function(){fn.apply(that, [that, objx]);}, timeOut: timeOut});
-						}(obj[i])
-					}
-				}
-			} else {
-				var fn = arguments[0];
-				var timeOut = (typeof(arguments[1]) != "undefined")? arguments[2] : defaultTimeOut;
-				queue.push({isParallel: false, fn: func, timeOut: timeOut});
-			}
-            return this;
-        };
-		
-		this.addParallel = function(func, timeOut) {
-			// TODO: add callback for queue[i] complete
-			
-            queue.push({isParallel: true, fn: func, timeOut: timeOut});
-            return this;
-        };
-
-        this.storeData = function(dataObject) {
-            lastCallbackData = dataObject;
-            return this;
-        };
-
-        this.lastCallbackData = function () {
-            return lastCallbackData;
-        };
-
-        this.run = function() {
-            paused = false;
-            _run();
-        };
-
-        this.pause = function () {
-            paused = true;
-            return this;
-        };
-
-        this.failure = function() {
-            paused = true;
-            if (failureFunc) {
-                var args = [that];
-                for(i = 0; i < arguments.length; i++) {
-                    args.push(arguments[i]);
-                }
-                failureFunc.apply(that, args);
-            }
-        };
-		
-		this.size = function(){
-			return queue.length;
-		};
-
-        return this;
-    }
-})(jQuery);

+ 0 - 9266
unimall-admin-api/src/main/resources/diagram-viewer/js/jquery/jquery.js

@@ -1,9266 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.7.1
- * http://jquery.com/
- *
- * Copyright 2011, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Mon Nov 21 21:11:03 2011 -0500
- */
-(function( window, undefined ) {
-
-// Use the correct document accordingly with window argument (sandbox)
-var document = window.document,
-	navigator = window.navigator,
-	location = window.location;
-var jQuery = (function() {
-
-// Define a local copy of jQuery
-var jQuery = function( selector, context ) {
-		// The jQuery object is actually just the init constructor 'enhanced'
-		return new jQuery.fn.init( selector, context, rootjQuery );
-	},
-
-	// Map over jQuery in case of overwrite
-	_jQuery = window.jQuery,
-
-	// Map over the $ in case of overwrite
-	_$ = window.$,
-
-	// A central reference to the root jQuery(document)
-	rootjQuery,
-
-	// A simple way to check for HTML strings or ID strings
-	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
-	quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
-
-	// Check if a string has a non-whitespace character in it
-	rnotwhite = /\S/,
-
-	// Used for trimming whitespace
-	trimLeft = /^\s+/,
-	trimRight = /\s+$/,
-
-	// Match a standalone tag
-	rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
-
-	// JSON RegExp
-	rvalidchars = /^[\],:{}\s]*$/,
-	rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
-	rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
-	rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
-
-	// Useragent RegExp
-	rwebkit = /(webkit)[ \/]([\w.]+)/,
-	ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
-	rmsie = /(msie) ([\w.]+)/,
-	rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
-
-	// Matches dashed string for camelizing
-	rdashAlpha = /-([a-z]|[0-9])/ig,
-	rmsPrefix = /^-ms-/,
-
-	// Used by jQuery.camelCase as callback to replace()
-	fcamelCase = function( all, letter ) {
-		return ( letter + "" ).toUpperCase();
-	},
-
-	// Keep a UserAgent string for use with jQuery.browser
-	userAgent = navigator.userAgent,
-
-	// For matching the engine and version of the browser
-	browserMatch,
-
-	// The deferred used on DOM ready
-	readyList,
-
-	// The ready event handler
-	DOMContentLoaded,
-
-	// Save a reference to some core methods
-	toString = Object.prototype.toString,
-	hasOwn = Object.prototype.hasOwnProperty,
-	push = Array.prototype.push,
-	slice = Array.prototype.slice,
-	trim = String.prototype.trim,
-	indexOf = Array.prototype.indexOf,
-
-	// [[Class]] -> type pairs
-	class2type = {};
-
-jQuery.fn = jQuery.prototype = {
-	constructor: jQuery,
-	init: function( selector, context, rootjQuery ) {
-		var match, elem, ret, doc;
-
-		// Handle $(""), $(null), or $(undefined)
-		if ( !selector ) {
-			return this;
-		}
-
-		// Handle $(DOMElement)
-		if ( selector.nodeType ) {
-			this.context = this[0] = selector;
-			this.length = 1;
-			return this;
-		}
-
-		// The body element only exists once, optimize finding it
-		if ( selector === "body" && !context && document.body ) {
-			this.context = document;
-			this[0] = document.body;
-			this.selector = selector;
-			this.length = 1;
-			return this;
-		}
-
-		// Handle HTML strings
-		if ( typeof selector === "string" ) {
-			// Are we dealing with HTML string or an ID?
-			if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
-				// Assume that strings that start and end with <> are HTML and skip the regex check
-				match = [ null, selector, null ];
-
-			} else {
-				match = quickExpr.exec( selector );
-			}
-
-			// Verify a match, and that no context was specified for #id
-			if ( match && (match[1] || !context) ) {
-
-				// HANDLE: $(html) -> $(array)
-				if ( match[1] ) {
-					context = context instanceof jQuery ? context[0] : context;
-					doc = ( context ? context.ownerDocument || context : document );
-
-					// If a single string is passed in and it's a single tag
-					// just do a createElement and skip the rest
-					ret = rsingleTag.exec( selector );
-
-					if ( ret ) {
-						if ( jQuery.isPlainObject( context ) ) {
-							selector = [ document.createElement( ret[1] ) ];
-							jQuery.fn.attr.call( selector, context, true );
-
-						} else {
-							selector = [ doc.createElement( ret[1] ) ];
-						}
-
-					} else {
-						ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
-						selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
-					}
-
-					return jQuery.merge( this, selector );
-
-				// HANDLE: $("#id")
-				} else {
-					elem = document.getElementById( match[2] );
-
-					// Check parentNode to catch when Blackberry 4.6 returns
-					// nodes that are no longer in the document #6963
-					if ( elem && elem.parentNode ) {
-						// Handle the case where IE and Opera return items
-						// by name instead of ID
-						if ( elem.id !== match[2] ) {
-							return rootjQuery.find( selector );
-						}
-
-						// Otherwise, we inject the element directly into the jQuery object
-						this.length = 1;
-						this[0] = elem;
-					}
-
-					this.context = document;
-					this.selector = selector;
-					return this;
-				}
-
-			// HANDLE: $(expr, $(...))
-			} else if ( !context || context.jquery ) {
-				return ( context || rootjQuery ).find( selector );
-
-			// HANDLE: $(expr, context)
-			// (which is just equivalent to: $(context).find(expr)
-			} else {
-				return this.constructor( context ).find( selector );
-			}
-
-		// HANDLE: $(function)
-		// Shortcut for document ready
-		} else if ( jQuery.isFunction( selector ) ) {
-			return rootjQuery.ready( selector );
-		}
-
-		if ( selector.selector !== undefined ) {
-			this.selector = selector.selector;
-			this.context = selector.context;
-		}
-
-		return jQuery.makeArray( selector, this );
-	},
-
-	// Start with an empty selector
-	selector: "",
-
-	// The current version of jQuery being used
-	jquery: "1.7.1",
-
-	// The default length of a jQuery object is 0
-	length: 0,
-
-	// The number of elements contained in the matched element set
-	size: function() {
-		return this.length;
-	},
-
-	toArray: function() {
-		return slice.call( this, 0 );
-	},
-
-	// Get the Nth element in the matched element set OR
-	// Get the whole matched element set as a clean array
-	get: function( num ) {
-		return num == null ?
-
-			// Return a 'clean' array
-			this.toArray() :
-
-			// Return just the object
-			( num < 0 ? this[ this.length + num ] : this[ num ] );
-	},
-
-	// Take an array of elements and push it onto the stack
-	// (returning the new matched element set)
-	pushStack: function( elems, name, selector ) {
-		// Build a new jQuery matched element set
-		var ret = this.constructor();
-
-		if ( jQuery.isArray( elems ) ) {
-			push.apply( ret, elems );
-
-		} else {
-			jQuery.merge( ret, elems );
-		}
-
-		// Add the old object onto the stack (as a reference)
-		ret.prevObject = this;
-
-		ret.context = this.context;
-
-		if ( name === "find" ) {
-			ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
-		} else if ( name ) {
-			ret.selector = this.selector + "." + name + "(" + selector + ")";
-		}
-
-		// Return the newly-formed element set
-		return ret;
-	},
-
-	// Execute a callback for every element in the matched set.
-	// (You can seed the arguments with an array of args, but this is
-	// only used internally.)
-	each: function( callback, args ) {
-		return jQuery.each( this, callback, args );
-	},
-
-	ready: function( fn ) {
-		// Attach the listeners
-		jQuery.bindReady();
-
-		// Add the callback
-		readyList.add( fn );
-
-		return this;
-	},
-
-	eq: function( i ) {
-		i = +i;
-		return i === -1 ?
-			this.slice( i ) :
-			this.slice( i, i + 1 );
-	},
-
-	first: function() {
-		return this.eq( 0 );
-	},
-
-	last: function() {
-		return this.eq( -1 );
-	},
-
-	slice: function() {
-		return this.pushStack( slice.apply( this, arguments ),
-			"slice", slice.call(arguments).join(",") );
-	},
-
-	map: function( callback ) {
-		return this.pushStack( jQuery.map(this, function( elem, i ) {
-			return callback.call( elem, i, elem );
-		}));
-	},
-
-	end: function() {
-		return this.prevObject || this.constructor(null);
-	},
-
-	// For internal use only.
-	// Behaves like an Array's method, not like a jQuery method.
-	push: push,
-	sort: [].sort,
-	splice: [].splice
-};
-
-// Give the init function the jQuery prototype for later instantiation
-jQuery.fn.init.prototype = jQuery.fn;
-
-jQuery.extend = jQuery.fn.extend = function() {
-	var options, name, src, copy, copyIsArray, clone,
-		target = arguments[0] || {},
-		i = 1,
-		length = arguments.length,
-		deep = false;
-
-	// Handle a deep copy situation
-	if ( typeof target === "boolean" ) {
-		deep = target;
-		target = arguments[1] || {};
-		// skip the boolean and the target
-		i = 2;
-	}
-
-	// Handle case when target is a string or something (possible in deep copy)
-	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
-		target = {};
-	}
-
-	// extend jQuery itself if only one argument is passed
-	if ( length === i ) {
-		target = this;
-		--i;
-	}
-
-	for ( ; i < length; i++ ) {
-		// Only deal with non-null/undefined values
-		if ( (options = arguments[ i ]) != null ) {
-			// Extend the base object
-			for ( name in options ) {
-				src = target[ name ];
-				copy = options[ name ];
-
-				// Prevent never-ending loop
-				if ( target === copy ) {
-					continue;
-				}
-
-				// Recurse if we're merging plain objects or arrays
-				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
-					if ( copyIsArray ) {
-						copyIsArray = false;
-						clone = src && jQuery.isArray(src) ? src : [];
-
-					} else {
-						clone = src && jQuery.isPlainObject(src) ? src : {};
-					}
-
-					// Never move original objects, clone them
-					target[ name ] = jQuery.extend( deep, clone, copy );
-
-				// Don't bring in undefined values
-				} else if ( copy !== undefined ) {
-					target[ name ] = copy;
-				}
-			}
-		}
-	}
-
-	// Return the modified object
-	return target;
-};
-
-jQuery.extend({
-	noConflict: function( deep ) {
-		if ( window.$ === jQuery ) {
-			window.$ = _$;
-		}
-
-		if ( deep && window.jQuery === jQuery ) {
-			window.jQuery = _jQuery;
-		}
-
-		return jQuery;
-	},
-
-	// Is the DOM ready to be used? Set to true once it occurs.
-	isReady: false,
-
-	// A counter to track how many items to wait for before
-	// the ready event fires. See #6781
-	readyWait: 1,
-
-	// Hold (or release) the ready event
-	holdReady: function( hold ) {
-		if ( hold ) {
-			jQuery.readyWait++;
-		} else {
-			jQuery.ready( true );
-		}
-	},
-
-	// Handle when the DOM is ready
-	ready: function( wait ) {
-		// Either a released hold or an DOMready/load event and not yet ready
-		if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
-			// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
-			if ( !document.body ) {
-				return setTimeout( jQuery.ready, 1 );
-			}
-
-			// Remember that the DOM is ready
-			jQuery.isReady = true;
-
-			// If a normal DOM Ready event fired, decrement, and wait if need be
-			if ( wait !== true && --jQuery.readyWait > 0 ) {
-				return;
-			}
-
-			// If there are functions bound, to execute
-			readyList.fireWith( document, [ jQuery ] );
-
-			// Trigger any bound ready events
-			if ( jQuery.fn.trigger ) {
-				jQuery( document ).trigger( "ready" ).off( "ready" );
-			}
-		}
-	},
-
-	bindReady: function() {
-		if ( readyList ) {
-			return;
-		}
-
-		readyList = jQuery.Callbacks( "once memory" );
-
-		// Catch cases where $(document).ready() is called after the
-		// browser event has already occurred.
-		if ( document.readyState === "complete" ) {
-			// Handle it asynchronously to allow scripts the opportunity to delay ready
-			return setTimeout( jQuery.ready, 1 );
-		}
-
-		// Mozilla, Opera and webkit nightlies currently support this event
-		if ( document.addEventListener ) {
-			// Use the handy event callback
-			document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-
-			// A fallback to window.onload, that will always work
-			window.addEventListener( "load", jQuery.ready, false );
-
-		// If IE event model is used
-		} else if ( document.attachEvent ) {
-			// ensure firing before onload,
-			// maybe late but safe also for iframes
-			document.attachEvent( "onreadystatechange", DOMContentLoaded );
-
-			// A fallback to window.onload, that will always work
-			window.attachEvent( "onload", jQuery.ready );
-
-			// If IE and not a frame
-			// continually check to see if the document is ready
-			var toplevel = false;
-
-			try {
-				toplevel = window.frameElement == null;
-			} catch(e) {}
-
-			if ( document.documentElement.doScroll && toplevel ) {
-				doScrollCheck();
-			}
-		}
-	},
-
-	// See test/unit/core.js for details concerning isFunction.
-	// Since version 1.3, DOM methods and functions like alert
-	// aren't supported. They return false on IE (#2968).
-	isFunction: function( obj ) {
-		return jQuery.type(obj) === "function";
-	},
-
-	isArray: Array.isArray || function( obj ) {
-		return jQuery.type(obj) === "array";
-	},
-
-	// A crude way of determining if an object is a window
-	isWindow: function( obj ) {
-		return obj && typeof obj === "object" && "setInterval" in obj;
-	},
-
-	isNumeric: function( obj ) {
-		return !isNaN( parseFloat(obj) ) && isFinite( obj );
-	},
-
-	type: function( obj ) {
-		return obj == null ?
-			String( obj ) :
-			class2type[ toString.call(obj) ] || "object";
-	},
-
-	isPlainObject: function( obj ) {
-		// Must be an Object.
-		// Because of IE, we also have to check the presence of the constructor property.
-		// Make sure that DOM nodes and window objects don't pass through, as well
-		if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
-			return false;
-		}
-
-		try {
-			// Not own constructor property must be Object
-			if ( obj.constructor &&
-				!hasOwn.call(obj, "constructor") &&
-				!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
-				return false;
-			}
-		} catch ( e ) {
-			// IE8,9 Will throw exceptions on certain host objects #9897
-			return false;
-		}
-
-		// Own properties are enumerated firstly, so to speed up,
-		// if last one is own, then all properties are own.
-
-		var key;
-		for ( key in obj ) {}
-
-		return key === undefined || hasOwn.call( obj, key );
-	},
-
-	isEmptyObject: function( obj ) {
-		for ( var name in obj ) {
-			return false;
-		}
-		return true;
-	},
-
-	error: function( msg ) {
-		throw new Error( msg );
-	},
-
-	parseJSON: function( data ) {
-		if ( typeof data !== "string" || !data ) {
-			return null;
-		}
-
-		// Make sure leading/trailing whitespace is removed (IE can't handle it)
-		data = jQuery.trim( data );
-
-		// Attempt to parse using the native JSON parser first
-		if ( window.JSON && window.JSON.parse ) {
-			return window.JSON.parse( data );
-		}
-
-		// Make sure the incoming data is actual JSON
-		// Logic borrowed from http://json.org/json2.js
-		if ( rvalidchars.test( data.replace( rvalidescape, "@" )
-			.replace( rvalidtokens, "]" )
-			.replace( rvalidbraces, "")) ) {
-
-			return ( new Function( "return " + data ) )();
-
-		}
-		jQuery.error( "Invalid JSON: " + data );
-	},
-
-	// Cross-browser xml parsing
-	parseXML: function( data ) {
-		var xml, tmp;
-		try {
-			if ( window.DOMParser ) { // Standard
-				tmp = new DOMParser();
-				xml = tmp.parseFromString( data , "text/xml" );
-			} else { // IE
-				xml = new ActiveXObject( "Microsoft.XMLDOM" );
-				xml.async = "false";
-				xml.loadXML( data );
-			}
-		} catch( e ) {
-			xml = undefined;
-		}
-		if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
-			jQuery.error( "Invalid XML: " + data );
-		}
-		return xml;
-	},
-
-	noop: function() {},
-
-	// Evaluates a script in a global context
-	// Workarounds based on findings by Jim Driscoll
-	// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
-	globalEval: function( data ) {
-		if ( data && rnotwhite.test( data ) ) {
-			// We use execScript on Internet Explorer
-			// We use an anonymous function so that context is window
-			// rather than jQuery in Firefox
-			( window.execScript || function( data ) {
-				window[ "eval" ].call( window, data );
-			} )( data );
-		}
-	},
-
-	// Convert dashed to camelCase; used by the css and data modules
-	// Microsoft forgot to hump their vendor prefix (#9572)
-	camelCase: function( string ) {
-		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
-	},
-
-	nodeName: function( elem, name ) {
-		return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
-	},
-
-	// args is for internal usage only
-	each: function( object, callback, args ) {
-		var name, i = 0,
-			length = object.length,
-			isObj = length === undefined || jQuery.isFunction( object );
-
-		if ( args ) {
-			if ( isObj ) {
-				for ( name in object ) {
-					if ( callback.apply( object[ name ], args ) === false ) {
-						break;
-					}
-				}
-			} else {
-				for ( ; i < length; ) {
-					if ( callback.apply( object[ i++ ], args ) === false ) {
-						break;
-					}
-				}
-			}
-
-		// A special, fast, case for the most util use of each
-		} else {
-			if ( isObj ) {
-				for ( name in object ) {
-					if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
-						break;
-					}
-				}
-			} else {
-				for ( ; i < length; ) {
-					if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
-						break;
-					}
-				}
-			}
-		}
-
-		return object;
-	},
-
-	// Use native String.trim function wherever possible
-	trim: trim ?
-		function( text ) {
-			return text == null ?
-				"" :
-				trim.call( text );
-		} :
-
-		// Otherwise use our own trimming functionality
-		function( text ) {
-			return text == null ?
-				"" :
-				text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
-		},
-
-	// results is for internal usage only
-	makeArray: function( array, results ) {
-		var ret = results || [];
-
-		if ( array != null ) {
-			// The window, strings (and functions) also have 'length'
-			// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
-			var type = jQuery.type( array );
-
-			if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
-				push.call( ret, array );
-			} else {
-				jQuery.merge( ret, array );
-			}
-		}
-
-		return ret;
-	},
-
-	inArray: function( elem, array, i ) {
-		var len;
-
-		if ( array ) {
-			if ( indexOf ) {
-				return indexOf.call( array, elem, i );
-			}
-
-			len = array.length;
-			i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
-
-			for ( ; i < len; i++ ) {
-				// Skip accessing in sparse arrays
-				if ( i in array && array[ i ] === elem ) {
-					return i;
-				}
-			}
-		}
-
-		return -1;
-	},
-
-	merge: function( first, second ) {
-		var i = first.length,
-			j = 0;
-
-		if ( typeof second.length === "number" ) {
-			for ( var l = second.length; j < l; j++ ) {
-				first[ i++ ] = second[ j ];
-			}
-
-		} else {
-			while ( second[j] !== undefined ) {
-				first[ i++ ] = second[ j++ ];
-			}
-		}
-
-		first.length = i;
-
-		return first;
-	},
-
-	grep: function( elems, callback, inv ) {
-		var ret = [], retVal;
-		inv = !!inv;
-
-		// Go through the array, only saving the items
-		// that pass the validator function
-		for ( var i = 0, length = elems.length; i < length; i++ ) {
-			retVal = !!callback( elems[ i ], i );
-			if ( inv !== retVal ) {
-				ret.push( elems[ i ] );
-			}
-		}
-
-		return ret;
-	},
-
-	// arg is for internal usage only
-	map: function( elems, callback, arg ) {
-		var value, key, ret = [],
-			i = 0,
-			length = elems.length,
-			// jquery objects are treated as arrays
-			isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
-
-		// Go through the array, translating each of the items to their
-		if ( isArray ) {
-			for ( ; i < length; i++ ) {
-				value = callback( elems[ i ], i, arg );
-
-				if ( value != null ) {
-					ret[ ret.length ] = value;
-				}
-			}
-
-		// Go through every key on the object,
-		} else {
-			for ( key in elems ) {
-				value = callback( elems[ key ], key, arg );
-
-				if ( value != null ) {
-					ret[ ret.length ] = value;
-				}
-			}
-		}
-
-		// Flatten any nested arrays
-		return ret.concat.apply( [], ret );
-	},
-
-	// A global GUID counter for objects
-	guid: 1,
-
-	// Bind a function to a context, optionally partially applying any
-	// arguments.
-	proxy: function( fn, context ) {
-		if ( typeof context === "string" ) {
-			var tmp = fn[ context ];
-			context = fn;
-			fn = tmp;
-		}
-
-		// Quick check to determine if target is callable, in the spec
-		// this throws a TypeError, but we will just return undefined.
-		if ( !jQuery.isFunction( fn ) ) {
-			return undefined;
-		}
-
-		// Simulated bind
-		var args = slice.call( arguments, 2 ),
-			proxy = function() {
-				return fn.apply( context, args.concat( slice.call( arguments ) ) );
-			};
-
-		// Set the guid of unique handler to the same of original handler, so it can be removed
-		proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
-
-		return proxy;
-	},
-
-	// Mutifunctional method to get and set values to a collection
-	// The value/s can optionally be executed if it's a function
-	access: function( elems, key, value, exec, fn, pass ) {
-		var length = elems.length;
-
-		// Setting many attributes
-		if ( typeof key === "object" ) {
-			for ( var k in key ) {
-				jQuery.access( elems, k, key[k], exec, fn, value );
-			}
-			return elems;
-		}
-
-		// Setting one attribute
-		if ( value !== undefined ) {
-			// Optionally, function values get executed if exec is true
-			exec = !pass && exec && jQuery.isFunction(value);
-
-			for ( var i = 0; i < length; i++ ) {
-				fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
-			}
-
-			return elems;
-		}
-
-		// Getting an attribute
-		return length ? fn( elems[0], key ) : undefined;
-	},
-
-	now: function() {
-		return ( new Date() ).getTime();
-	},
-
-	// Use of jQuery.browser is frowned upon.
-	// More details: http://docs.jquery.com/Utilities/jQuery.browser
-	uaMatch: function( ua ) {
-		ua = ua.toLowerCase();
-
-		var match = rwebkit.exec( ua ) ||
-			ropera.exec( ua ) ||
-			rmsie.exec( ua ) ||
-			ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
-			[];
-
-		return { browser: match[1] || "", version: match[2] || "0" };
-	},
-
-	sub: function() {
-		function jQuerySub( selector, context ) {
-			return new jQuerySub.fn.init( selector, context );
-		}
-		jQuery.extend( true, jQuerySub, this );
-		jQuerySub.superclass = this;
-		jQuerySub.fn = jQuerySub.prototype = this();
-		jQuerySub.fn.constructor = jQuerySub;
-		jQuerySub.sub = this.sub;
-		jQuerySub.fn.init = function init( selector, context ) {
-			if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
-				context = jQuerySub( context );
-			}
-
-			return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
-		};
-		jQuerySub.fn.init.prototype = jQuerySub.fn;
-		var rootjQuerySub = jQuerySub(document);
-		return jQuerySub;
-	},
-
-	browser: {}
-});
-
-// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
-	class2type[ "[object " + name + "]" ] = name.toLowerCase();
-});
-
-browserMatch = jQuery.uaMatch( userAgent );
-if ( browserMatch.browser ) {
-	jQuery.browser[ browserMatch.browser ] = true;
-	jQuery.browser.version = browserMatch.version;
-}
-
-// Deprecated, use jQuery.browser.webkit instead
-if ( jQuery.browser.webkit ) {
-	jQuery.browser.safari = true;
-}
-
-// IE doesn't match non-breaking spaces with \s
-if ( rnotwhite.test( "\xA0" ) ) {
-	trimLeft = /^[\s\xA0]+/;
-	trimRight = /[\s\xA0]+$/;
-}
-
-// All jQuery objects should point back to these
-rootjQuery = jQuery(document);
-
-// Cleanup functions for the document ready method
-if ( document.addEventListener ) {
-	DOMContentLoaded = function() {
-		document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-		jQuery.ready();
-	};
-
-} else if ( document.attachEvent ) {
-	DOMContentLoaded = function() {
-		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
-		if ( document.readyState === "complete" ) {
-			document.detachEvent( "onreadystatechange", DOMContentLoaded );
-			jQuery.ready();
-		}
-	};
-}
-
-// The DOM ready check for Internet Explorer
-function doScrollCheck() {
-	if ( jQuery.isReady ) {
-		return;
-	}
-
-	try {
-		// If IE is used, use the trick by Diego Perini
-		// http://javascript.nwbox.com/IEContentLoaded/
-		document.documentElement.doScroll("left");
-	} catch(e) {
-		setTimeout( doScrollCheck, 1 );
-		return;
-	}
-
-	// and execute any waiting functions
-	jQuery.ready();
-}
-
-return jQuery;
-
-})();
-
-
-// String to Object flags format cache
-var flagsCache = {};
-
-// Convert String-formatted flags into Object-formatted ones and store in cache
-function createFlags( flags ) {
-	var object = flagsCache[ flags ] = {},
-		i, length;
-	flags = flags.split( /\s+/ );
-	for ( i = 0, length = flags.length; i < length; i++ ) {
-		object[ flags[i] ] = true;
-	}
-	return object;
-}
-
-/*
- * Create a callback list using the following parameters:
- *
- *	flags:	an optional list of space-separated flags that will change how
- *			the callback list behaves
- *
- * By default a callback list will act like an event callback list and can be
- * "fired" multiple times.
- *
- * Possible flags:
- *
- *	once:			will ensure the callback list can only be fired once (like a Deferred)
- *
- *	memory:			will keep track of previous values and will call any callback added
- *					after the list has been fired right away with the latest "memorized"
- *					values (like a Deferred)
- *
- *	unique:			will ensure a callback can only be added once (no duplicate in the list)
- *
- *	stopOnFalse:	interrupt callings when a callback returns false
- *
- */
-jQuery.Callbacks = function( flags ) {
-
-	// Convert flags from String-formatted to Object-formatted
-	// (we check in cache first)
-	flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
-
-	var // Actual callback list
-		list = [],
-		// Stack of fire calls for repeatable lists
-		stack = [],
-		// Last fire value (for non-forgettable lists)
-		memory,
-		// Flag to know if list is currently firing
-		firing,
-		// First callback to fire (used internally by add and fireWith)
-		firingStart,
-		// End of the loop when firing
-		firingLength,
-		// Index of currently firing callback (modified by remove if needed)
-		firingIndex,
-		// Add one or several callbacks to the list
-		add = function( args ) {
-			var i,
-				length,
-				elem,
-				type,
-				actual;
-			for ( i = 0, length = args.length; i < length; i++ ) {
-				elem = args[ i ];
-				type = jQuery.type( elem );
-				if ( type === "array" ) {
-					// Inspect recursively
-					add( elem );
-				} else if ( type === "function" ) {
-					// Add if not in unique mode and callback is not in
-					if ( !flags.unique || !self.has( elem ) ) {
-						list.push( elem );
-					}
-				}
-			}
-		},
-		// Fire callbacks
-		fire = function( context, args ) {
-			args = args || [];
-			memory = !flags.memory || [ context, args ];
-			firing = true;
-			firingIndex = firingStart || 0;
-			firingStart = 0;
-			firingLength = list.length;
-			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
-				if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
-					memory = true; // Mark as halted
-					break;
-				}
-			}
-			firing = false;
-			if ( list ) {
-				if ( !flags.once ) {
-					if ( stack && stack.length ) {
-						memory = stack.shift();
-						self.fireWith( memory[ 0 ], memory[ 1 ] );
-					}
-				} else if ( memory === true ) {
-					self.disable();
-				} else {
-					list = [];
-				}
-			}
-		},
-		// Actual Callbacks object
-		self = {
-			// Add a callback or a collection of callbacks to the list
-			add: function() {
-				if ( list ) {
-					var length = list.length;
-					add( arguments );
-					// Do we need to add the callbacks to the
-					// current firing batch?
-					if ( firing ) {
-						firingLength = list.length;
-					// With memory, if we're not firing then
-					// we should call right away, unless previous
-					// firing was halted (stopOnFalse)
-					} else if ( memory && memory !== true ) {
-						firingStart = length;
-						fire( memory[ 0 ], memory[ 1 ] );
-					}
-				}
-				return this;
-			},
-			// Remove a callback from the list
-			remove: function() {
-				if ( list ) {
-					var args = arguments,
-						argIndex = 0,
-						argLength = args.length;
-					for ( ; argIndex < argLength ; argIndex++ ) {
-						for ( var i = 0; i < list.length; i++ ) {
-							if ( args[ argIndex ] === list[ i ] ) {
-								// Handle firingIndex and firingLength
-								if ( firing ) {
-									if ( i <= firingLength ) {
-										firingLength--;
-										if ( i <= firingIndex ) {
-											firingIndex--;
-										}
-									}
-								}
-								// Remove the element
-								list.splice( i--, 1 );
-								// If we have some unicity property then
-								// we only need to do this once
-								if ( flags.unique ) {
-									break;
-								}
-							}
-						}
-					}
-				}
-				return this;
-			},
-			// Control if a given callback is in the list
-			has: function( fn ) {
-				if ( list ) {
-					var i = 0,
-						length = list.length;
-					for ( ; i < length; i++ ) {
-						if ( fn === list[ i ] ) {
-							return true;
-						}
-					}
-				}
-				return false;
-			},
-			// Remove all callbacks from the list
-			empty: function() {
-				list = [];
-				return this;
-			},
-			// Have the list do nothing anymore
-			disable: function() {
-				list = stack = memory = undefined;
-				return this;
-			},
-			// Is it disabled?
-			disabled: function() {
-				return !list;
-			},
-			// Lock the list in its current state
-			lock: function() {
-				stack = undefined;
-				if ( !memory || memory === true ) {
-					self.disable();
-				}
-				return this;
-			},
-			// Is it locked?
-			locked: function() {
-				return !stack;
-			},
-			// Call all callbacks with the given context and arguments
-			fireWith: function( context, args ) {
-				if ( stack ) {
-					if ( firing ) {
-						if ( !flags.once ) {
-							stack.push( [ context, args ] );
-						}
-					} else if ( !( flags.once && memory ) ) {
-						fire( context, args );
-					}
-				}
-				return this;
-			},
-			// Call all the callbacks with the given arguments
-			fire: function() {
-				self.fireWith( this, arguments );
-				return this;
-			},
-			// To know if the callbacks have already been called at least once
-			fired: function() {
-				return !!memory;
-			}
-		};
-
-	return self;
-};
-
-
-
-
-var // Static reference to slice
-	sliceDeferred = [].slice;
-
-jQuery.extend({
-
-	Deferred: function( func ) {
-		var doneList = jQuery.Callbacks( "once memory" ),
-			failList = jQuery.Callbacks( "once memory" ),
-			progressList = jQuery.Callbacks( "memory" ),
-			state = "pending",
-			lists = {
-				resolve: doneList,
-				reject: failList,
-				notify: progressList
-			},
-			promise = {
-				done: doneList.add,
-				fail: failList.add,
-				progress: progressList.add,
-
-				state: function() {
-					return state;
-				},
-
-				// Deprecated
-				isResolved: doneList.fired,
-				isRejected: failList.fired,
-
-				then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
-					deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
-					return this;
-				},
-				always: function() {
-					deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
-					return this;
-				},
-				pipe: function( fnDone, fnFail, fnProgress ) {
-					return jQuery.Deferred(function( newDefer ) {
-						jQuery.each( {
-							done: [ fnDone, "resolve" ],
-							fail: [ fnFail, "reject" ],
-							progress: [ fnProgress, "notify" ]
-						}, function( handler, data ) {
-							var fn = data[ 0 ],
-								action = data[ 1 ],
-								returned;
-							if ( jQuery.isFunction( fn ) ) {
-								deferred[ handler ](function() {
-									returned = fn.apply( this, arguments );
-									if ( returned && jQuery.isFunction( returned.promise ) ) {
-										returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
-									} else {
-										newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
-									}
-								});
-							} else {
-								deferred[ handler ]( newDefer[ action ] );
-							}
-						});
-					}).promise();
-				},
-				// Get a promise for this deferred
-				// If obj is provided, the promise aspect is added to the object
-				promise: function( obj ) {
-					if ( obj == null ) {
-						obj = promise;
-					} else {
-						for ( var key in promise ) {
-							obj[ key ] = promise[ key ];
-						}
-					}
-					return obj;
-				}
-			},
-			deferred = promise.promise({}),
-			key;
-
-		for ( key in lists ) {
-			deferred[ key ] = lists[ key ].fire;
-			deferred[ key + "With" ] = lists[ key ].fireWith;
-		}
-
-		// Handle state
-		deferred.done( function() {
-			state = "resolved";
-		}, failList.disable, progressList.lock ).fail( function() {
-			state = "rejected";
-		}, doneList.disable, progressList.lock );
-
-		// Call given func if any
-		if ( func ) {
-			func.call( deferred, deferred );
-		}
-
-		// All done!
-		return deferred;
-	},
-
-	// Deferred helper
-	when: function( firstParam ) {
-		var args = sliceDeferred.call( arguments, 0 ),
-			i = 0,
-			length = args.length,
-			pValues = new Array( length ),
-			count = length,
-			pCount = length,
-			deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
-				firstParam :
-				jQuery.Deferred(),
-			promise = deferred.promise();
-		function resolveFunc( i ) {
-			return function( value ) {
-				args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
-				if ( !( --count ) ) {
-					deferred.resolveWith( deferred, args );
-				}
-			};
-		}
-		function progressFunc( i ) {
-			return function( value ) {
-				pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
-				deferred.notifyWith( promise, pValues );
-			};
-		}
-		if ( length > 1 ) {
-			for ( ; i < length; i++ ) {
-				if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
-					args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
-				} else {
-					--count;
-				}
-			}
-			if ( !count ) {
-				deferred.resolveWith( deferred, args );
-			}
-		} else if ( deferred !== firstParam ) {
-			deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
-		}
-		return promise;
-	}
-});
-
-
-
-
-jQuery.support = (function() {
-
-	var support,
-		all,
-		a,
-		select,
-		opt,
-		input,
-		marginDiv,
-		fragment,
-		tds,
-		events,
-		eventName,
-		i,
-		isSupported,
-		div = document.createElement( "div" ),
-		documentElement = document.documentElement;
-
-	// Preliminary tests
-	div.setAttribute("className", "t");
-	div.innerHTML = "   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
-
-	all = div.getElementsByTagName( "*" );
-	a = div.getElementsByTagName( "a" )[ 0 ];
-
-	// Can't get basic test support
-	if ( !all || !all.length || !a ) {
-		return {};
-	}
-
-	// First batch of supports tests
-	select = document.createElement( "select" );
-	opt = select.appendChild( document.createElement("option") );
-	input = div.getElementsByTagName( "input" )[ 0 ];
-
-	support = {
-		// IE strips leading whitespace when .innerHTML is used
-		leadingWhitespace: ( div.firstChild.nodeType === 3 ),
-
-		// Make sure that tbody elements aren't automatically inserted
-		// IE will insert them into empty tables
-		tbody: !div.getElementsByTagName("tbody").length,
-
-		// Make sure that link elements get serialized correctly by innerHTML
-		// This requires a wrapper element in IE
-		htmlSerialize: !!div.getElementsByTagName("link").length,
-
-		// Get the style information from getAttribute
-		// (IE uses .cssText instead)
-		style: /top/.test( a.getAttribute("style") ),
-
-		// Make sure that URLs aren't manipulated
-		// (IE normalizes it by default)
-		hrefNormalized: ( a.getAttribute("href") === "/a" ),
-
-		// Make sure that element opacity exists
-		// (IE uses filter instead)
-		// Use a regex to work around a WebKit issue. See #5145
-		opacity: /^0.55/.test( a.style.opacity ),
-
-		// Verify style float existence
-		// (IE uses styleFloat instead of cssFloat)
-		cssFloat: !!a.style.cssFloat,
-
-		// Make sure that if no value is specified for a checkbox
-		// that it defaults to "on".
-		// (WebKit defaults to "" instead)
-		checkOn: ( input.value === "on" ),
-
-		// Make sure that a selected-by-default option has a working selected property.
-		// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
-		optSelected: opt.selected,
-
-		// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
-		getSetAttribute: div.className !== "t",
-
-		// Tests for enctype support on a form(#6743)
-		enctype: !!document.createElement("form").enctype,
-
-		// Makes sure cloning an html5 element does not cause problems
-		// Where outerHTML is undefined, this still works
-		html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
-
-		// Will be defined later
-		submitBubbles: true,
-		changeBubbles: true,
-		focusinBubbles: false,
-		deleteExpando: true,
-		noCloneEvent: true,
-		inlineBlockNeedsLayout: false,
-		shrinkWrapBlocks: false,
-		reliableMarginRight: true
-	};
-
-	// Make sure checked status is properly cloned
-	input.checked = true;
-	support.noCloneChecked = input.cloneNode( true ).checked;
-
-	// Make sure that the options inside disabled selects aren't marked as disabled
-	// (WebKit marks them as disabled)
-	select.disabled = true;
-	support.optDisabled = !opt.disabled;
-
-	// Test to see if it's possible to delete an expando from an element
-	// Fails in Internet Explorer
-	try {
-		delete div.test;
-	} catch( e ) {
-		support.deleteExpando = false;
-	}
-
-	if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
-		div.attachEvent( "onclick", function() {
-			// Cloning a node shouldn't copy over any
-			// bound event handlers (IE does this)
-			support.noCloneEvent = false;
-		});
-		div.cloneNode( true ).fireEvent( "onclick" );
-	}
-
-	// Check if a radio maintains its value
-	// after being appended to the DOM
-	input = document.createElement("input");
-	input.value = "t";
-	input.setAttribute("type", "radio");
-	support.radioValue = input.value === "t";
-
-	input.setAttribute("checked", "checked");
-	div.appendChild( input );
-	fragment = document.createDocumentFragment();
-	fragment.appendChild( div.lastChild );
-
-	// WebKit doesn't clone checked state correctly in fragments
-	support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
-
-	// Check if a disconnected checkbox will retain its checked
-	// value of true after appended to the DOM (IE6/7)
-	support.appendChecked = input.checked;
-
-	fragment.removeChild( input );
-	fragment.appendChild( div );
-
-	div.innerHTML = "";
-
-	// Check if div with explicit width and no margin-right incorrectly
-	// gets computed margin-right based on width of container. For more
-	// info see bug #3333
-	// Fails in WebKit before Feb 2011 nightlies
-	// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
-	if ( window.getComputedStyle ) {
-		marginDiv = document.createElement( "div" );
-		marginDiv.style.width = "0";
-		marginDiv.style.marginRight = "0";
-		div.style.width = "2px";
-		div.appendChild( marginDiv );
-		support.reliableMarginRight =
-			( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
-	}
-
-	// Technique from Juriy Zaytsev
-	// http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
-	// We only care about the case where non-standard event systems
-	// are used, namely in IE. Short-circuiting here helps us to
-	// avoid an eval call (in setAttribute) which can cause CSP
-	// to go haywire. See: https://developer.mozilla.org/en/Security/CSP
-	if ( div.attachEvent ) {
-		for( i in {
-			submit: 1,
-			change: 1,
-			focusin: 1
-		}) {
-			eventName = "on" + i;
-			isSupported = ( eventName in div );
-			if ( !isSupported ) {
-				div.setAttribute( eventName, "return;" );
-				isSupported = ( typeof div[ eventName ] === "function" );
-			}
-			support[ i + "Bubbles" ] = isSupported;
-		}
-	}
-
-	fragment.removeChild( div );
-
-	// Null elements to avoid leaks in IE
-	fragment = select = opt = marginDiv = div = input = null;
-
-	// Run tests that need a body at doc ready
-	jQuery(function() {
-		var container, outer, inner, table, td, offsetSupport,
-			conMarginTop, ptlm, vb, style, html,
-			body = document.getElementsByTagName("body")[0];
-
-		if ( !body ) {
-			// Return for frameset docs that don't have a body
-			return;
-		}
-
-		conMarginTop = 1;
-		ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;";
-		vb = "visibility:hidden;border:0;";
-		style = "style='" + ptlm + "border:5px solid #000;padding:0;'";
-		html = "<div " + style + "><div></div></div>" +
-			"<table " + style + " cellpadding='0' cellspacing='0'>" +
-			"<tr><td></td></tr></table>";
-
-		container = document.createElement("div");
-		container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
-		body.insertBefore( container, body.firstChild );
-
-		// Construct the test element
-		div = document.createElement("div");
-		container.appendChild( div );
-
-		// Check if table cells still have offsetWidth/Height when they are set
-		// to display:none and there are still other visible table cells in a
-		// table row; if so, offsetWidth/Height are not reliable for use when
-		// determining if an element has been hidden directly using
-		// display:none (it is still safe to use offsets if a parent element is
-		// hidden; don safety goggles and see bug #4512 for more information).
-		// (only IE 8 fails this test)
-		div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
-		tds = div.getElementsByTagName( "td" );
-		isSupported = ( tds[ 0 ].offsetHeight === 0 );
-
-		tds[ 0 ].style.display = "";
-		tds[ 1 ].style.display = "none";
-
-		// Check if empty table cells still have offsetWidth/Height
-		// (IE <= 8 fail this test)
-		support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
-
-		// Figure out if the W3C box model works as expected
-		div.innerHTML = "";
-		div.style.width = div.style.paddingLeft = "1px";
-		jQuery.boxModel = support.boxModel = div.offsetWidth === 2;
-
-		if ( typeof div.style.zoom !== "undefined" ) {
-			// Check if natively block-level elements act like inline-block
-			// elements when setting their display to 'inline' and giving
-			// them layout
-			// (IE < 8 does this)
-			div.style.display = "inline";
-			div.style.zoom = 1;
-			support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
-
-			// Check if elements with layout shrink-wrap their children
-			// (IE 6 does this)
-			div.style.display = "";
-			div.innerHTML = "<div style='width:4px;'></div>";
-			support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
-		}
-
-		div.style.cssText = ptlm + vb;
-		div.innerHTML = html;
-
-		outer = div.firstChild;
-		inner = outer.firstChild;
-		td = outer.nextSibling.firstChild.firstChild;
-
-		offsetSupport = {
-			doesNotAddBorder: ( inner.offsetTop !== 5 ),
-			doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
-		};
-
-		inner.style.position = "fixed";
-		inner.style.top = "20px";
-
-		// safari subtracts parent border width here which is 5px
-		offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
-		inner.style.position = inner.style.top = "";
-
-		outer.style.overflow = "hidden";
-		outer.style.position = "relative";
-
-		offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
-		offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
-
-		body.removeChild( container );
-		div  = container = null;
-
-		jQuery.extend( support, offsetSupport );
-	});
-
-	return support;
-})();
-
-
-
-
-var rbrace = /^(?:\{.*\}|\[.*\])$/,
-	rmultiDash = /([A-Z])/g;
-
-jQuery.extend({
-	cache: {},
-
-	// Please use with caution
-	uuid: 0,
-
-	// Unique for each copy of jQuery on the page
-	// Non-digits removed to match rinlinejQuery
-	expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
-
-	// The following elements throw uncatchable exceptions if you
-	// attempt to add expando properties to them.
-	noData: {
-		"embed": true,
-		// Ban all objects except for Flash (which handle expandos)
-		"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
-		"applet": true
-	},
-
-	hasData: function( elem ) {
-		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
-		return !!elem && !isEmptyDataObject( elem );
-	},
-
-	data: function( elem, name, data, pvt /* Internal Use Only */ ) {
-		if ( !jQuery.acceptData( elem ) ) {
-			return;
-		}
-
-		var privateCache, thisCache, ret,
-			internalKey = jQuery.expando,
-			getByName = typeof name === "string",
-
-			// We have to handle DOM nodes and JS objects differently because IE6-7
-			// can't GC object references properly across the DOM-JS boundary
-			isNode = elem.nodeType,
-
-			// Only DOM nodes need the global jQuery cache; JS object data is
-			// attached directly to the object so GC can occur automatically
-			cache = isNode ? jQuery.cache : elem,
-
-			// Only defining an ID for JS objects if its cache already exists allows
-			// the code to shortcut on the same path as a DOM node with no cache
-			id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
-			isEvents = name === "events";
-
-		// Avoid doing any more work than we need to when trying to get data on an
-		// object that has no data at all
-		if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
-			return;
-		}
-
-		if ( !id ) {
-			// Only DOM nodes need a new unique ID for each element since their data
-			// ends up in the global cache
-			if ( isNode ) {
-				elem[ internalKey ] = id = ++jQuery.uuid;
-			} else {
-				id = internalKey;
-			}
-		}
-
-		if ( !cache[ id ] ) {
-			cache[ id ] = {};
-
-			// Avoids exposing jQuery metadata on plain JS objects when the object
-			// is serialized using JSON.stringify
-			if ( !isNode ) {
-				cache[ id ].toJSON = jQuery.noop;
-			}
-		}
-
-		// An object can be passed to jQuery.data instead of a key/value pair; this gets
-		// shallow copied over onto the existing cache
-		if ( typeof name === "object" || typeof name === "function" ) {
-			if ( pvt ) {
-				cache[ id ] = jQuery.extend( cache[ id ], name );
-			} else {
-				cache[ id ].data = jQuery.extend( cache[ id ].data, name );
-			}
-		}
-
-		privateCache = thisCache = cache[ id ];
-
-		// jQuery data() is stored in a separate object inside the object's internal data
-		// cache in order to avoid key collisions between internal data and user-defined
-		// data.
-		if ( !pvt ) {
-			if ( !thisCache.data ) {
-				thisCache.data = {};
-			}
-
-			thisCache = thisCache.data;
-		}
-
-		if ( data !== undefined ) {
-			thisCache[ jQuery.camelCase( name ) ] = data;
-		}
-
-		// Users should not attempt to inspect the internal events object using jQuery.data,
-		// it is undocumented and subject to change. But does anyone listen? No.
-		if ( isEvents && !thisCache[ name ] ) {
-			return privateCache.events;
-		}
-
-		// Check for both converted-to-camel and non-converted data property names
-		// If a data property was specified
-		if ( getByName ) {
-
-			// First Try to find as-is property data
-			ret = thisCache[ name ];
-
-			// Test for null|undefined property data
-			if ( ret == null ) {
-
-				// Try to find the camelCased property
-				ret = thisCache[ jQuery.camelCase( name ) ];
-			}
-		} else {
-			ret = thisCache;
-		}
-
-		return ret;
-	},
-
-	removeData: function( elem, name, pvt /* Internal Use Only */ ) {
-		if ( !jQuery.acceptData( elem ) ) {
-			return;
-		}
-
-		var thisCache, i, l,
-
-			// Reference to internal data cache key
-			internalKey = jQuery.expando,
-
-			isNode = elem.nodeType,
-
-			// See jQuery.data for more information
-			cache = isNode ? jQuery.cache : elem,
-
-			// See jQuery.data for more information
-			id = isNode ? elem[ internalKey ] : internalKey;
-
-		// If there is already no cache entry for this object, there is no
-		// purpose in continuing
-		if ( !cache[ id ] ) {
-			return;
-		}
-
-		if ( name ) {
-
-			thisCache = pvt ? cache[ id ] : cache[ id ].data;
-
-			if ( thisCache ) {
-
-				// Support array or space separated string names for data keys
-				if ( !jQuery.isArray( name ) ) {
-
-					// try the string as a key before any manipulation
-					if ( name in thisCache ) {
-						name = [ name ];
-					} else {
-
-						// split the camel cased version by spaces unless a key with the spaces exists
-						name = jQuery.camelCase( name );
-						if ( name in thisCache ) {
-							name = [ name ];
-						} else {
-							name = name.split( " " );
-						}
-					}
-				}
-
-				for ( i = 0, l = name.length; i < l; i++ ) {
-					delete thisCache[ name[i] ];
-				}
-
-				// If there is no data left in the cache, we want to continue
-				// and let the cache object itself get destroyed
-				if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
-					return;
-				}
-			}
-		}
-
-		// See jQuery.data for more information
-		if ( !pvt ) {
-			delete cache[ id ].data;
-
-			// Don't destroy the parent cache unless the internal data object
-			// had been the only thing left in it
-			if ( !isEmptyDataObject(cache[ id ]) ) {
-				return;
-			}
-		}
-
-		// Browsers that fail expando deletion also refuse to delete expandos on
-		// the window, but it will allow it on all other JS objects; other browsers
-		// don't care
-		// Ensure that `cache` is not a window object #10080
-		if ( jQuery.support.deleteExpando || !cache.setInterval ) {
-			delete cache[ id ];
-		} else {
-			cache[ id ] = null;
-		}
-
-		// We destroyed the cache and need to eliminate the expando on the node to avoid
-		// false lookups in the cache for entries that no longer exist
-		if ( isNode ) {
-			// IE does not allow us to delete expando properties from nodes,
-			// nor does it have a removeAttribute function on Document nodes;
-			// we must handle all of these cases
-			if ( jQuery.support.deleteExpando ) {
-				delete elem[ internalKey ];
-			} else if ( elem.removeAttribute ) {
-				elem.removeAttribute( internalKey );
-			} else {
-				elem[ internalKey ] = null;
-			}
-		}
-	},
-
-	// For internal use only.
-	_data: function( elem, name, data ) {
-		return jQuery.data( elem, name, data, true );
-	},
-
-	// A method for determining if a DOM node can handle the data expando
-	acceptData: function( elem ) {
-		if ( elem.nodeName ) {
-			var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
-
-			if ( match ) {
-				return !(match === true || elem.getAttribute("classid") !== match);
-			}
-		}
-
-		return true;
-	}
-});
-
-jQuery.fn.extend({
-	data: function( key, value ) {
-		var parts, attr, name,
-			data = null;
-
-		if ( typeof key === "undefined" ) {
-			if ( this.length ) {
-				data = jQuery.data( this[0] );
-
-				if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) {
-					attr = this[0].attributes;
-					for ( var i = 0, l = attr.length; i < l; i++ ) {
-						name = attr[i].name;
-
-						if ( name.indexOf( "data-" ) === 0 ) {
-							name = jQuery.camelCase( name.substring(5) );
-
-							dataAttr( this[0], name, data[ name ] );
-						}
-					}
-					jQuery._data( this[0], "parsedAttrs", true );
-				}
-			}
-
-			return data;
-
-		} else if ( typeof key === "object" ) {
-			return this.each(function() {
-				jQuery.data( this, key );
-			});
-		}
-
-		parts = key.split(".");
-		parts[1] = parts[1] ? "." + parts[1] : "";
-
-		if ( value === undefined ) {
-			data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
-
-			// Try to fetch any internally stored data first
-			if ( data === undefined && this.length ) {
-				data = jQuery.data( this[0], key );
-				data = dataAttr( this[0], key, data );
-			}
-
-			return data === undefined && parts[1] ?
-				this.data( parts[0] ) :
-				data;
-
-		} else {
-			return this.each(function() {
-				var self = jQuery( this ),
-					args = [ parts[0], value ];
-
-				self.triggerHandler( "setData" + parts[1] + "!", args );
-				jQuery.data( this, key, value );
-				self.triggerHandler( "changeData" + parts[1] + "!", args );
-			});
-		}
-	},
-
-	removeData: function( key ) {
-		return this.each(function() {
-			jQuery.removeData( this, key );
-		});
-	}
-});
-
-function dataAttr( elem, key, data ) {
-	// If nothing was found internally, try to fetch any
-	// data from the HTML5 data-* attribute
-	if ( data === undefined && elem.nodeType === 1 ) {
-
-		var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
-
-		data = elem.getAttribute( name );
-
-		if ( typeof data === "string" ) {
-			try {
-				data = data === "true" ? true :
-				data === "false" ? false :
-				data === "null" ? null :
-				jQuery.isNumeric( data ) ? parseFloat( data ) :
-					rbrace.test( data ) ? jQuery.parseJSON( data ) :
-					data;
-			} catch( e ) {}
-
-			// Make sure we set the data so it isn't changed later
-			jQuery.data( elem, key, data );
-
-		} else {
-			data = undefined;
-		}
-	}
-
-	return data;
-}
-
-// checks a cache object for emptiness
-function isEmptyDataObject( obj ) {
-	for ( var name in obj ) {
-
-		// if the public data object is empty, the private is still empty
-		if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
-			continue;
-		}
-		if ( name !== "toJSON" ) {
-			return false;
-		}
-	}
-
-	return true;
-}
-
-
-
-
-function handleQueueMarkDefer( elem, type, src ) {
-	var deferDataKey = type + "defer",
-		queueDataKey = type + "queue",
-		markDataKey = type + "mark",
-		defer = jQuery._data( elem, deferDataKey );
-	if ( defer &&
-		( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
-		( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
-		// Give room for hard-coded callbacks to fire first
-		// and eventually mark/queue something else on the element
-		setTimeout( function() {
-			if ( !jQuery._data( elem, queueDataKey ) &&
-				!jQuery._data( elem, markDataKey ) ) {
-				jQuery.removeData( elem, deferDataKey, true );
-				defer.fire();
-			}
-		}, 0 );
-	}
-}
-
-jQuery.extend({
-
-	_mark: function( elem, type ) {
-		if ( elem ) {
-			type = ( type || "fx" ) + "mark";
-			jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
-		}
-	},
-
-	_unmark: function( force, elem, type ) {
-		if ( force !== true ) {
-			type = elem;
-			elem = force;
-			force = false;
-		}
-		if ( elem ) {
-			type = type || "fx";
-			var key = type + "mark",
-				count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
-			if ( count ) {
-				jQuery._data( elem, key, count );
-			} else {
-				jQuery.removeData( elem, key, true );
-				handleQueueMarkDefer( elem, type, "mark" );
-			}
-		}
-	},
-
-	queue: function( elem, type, data ) {
-		var q;
-		if ( elem ) {
-			type = ( type || "fx" ) + "queue";
-			q = jQuery._data( elem, type );
-
-			// Speed up dequeue by getting out quickly if this is just a lookup
-			if ( data ) {
-				if ( !q || jQuery.isArray(data) ) {
-					q = jQuery._data( elem, type, jQuery.makeArray(data) );
-				} else {
-					q.push( data );
-				}
-			}
-			return q || [];
-		}
-	},
-
-	dequeue: function( elem, type ) {
-		type = type || "fx";
-
-		var queue = jQuery.queue( elem, type ),
-			fn = queue.shift(),
-			hooks = {};
-
-		// If the fx queue is dequeued, always remove the progress sentinel
-		if ( fn === "inprogress" ) {
-			fn = queue.shift();
-		}
-
-		if ( fn ) {
-			// Add a progress sentinel to prevent the fx queue from being
-			// automatically dequeued
-			if ( type === "fx" ) {
-				queue.unshift( "inprogress" );
-			}
-
-			jQuery._data( elem, type + ".run", hooks );
-			fn.call( elem, function() {
-				jQuery.dequeue( elem, type );
-			}, hooks );
-		}
-
-		if ( !queue.length ) {
-			jQuery.removeData( elem, type + "queue " + type + ".run", true );
-			handleQueueMarkDefer( elem, type, "queue" );
-		}
-	}
-});
-
-jQuery.fn.extend({
-	queue: function( type, data ) {
-		if ( typeof type !== "string" ) {
-			data = type;
-			type = "fx";
-		}
-
-		if ( data === undefined ) {
-			return jQuery.queue( this[0], type );
-		}
-		return this.each(function() {
-			var queue = jQuery.queue( this, type, data );
-
-			if ( type === "fx" && queue[0] !== "inprogress" ) {
-				jQuery.dequeue( this, type );
-			}
-		});
-	},
-	dequeue: function( type ) {
-		return this.each(function() {
-			jQuery.dequeue( this, type );
-		});
-	},
-	// Based off of the plugin by Clint Helfers, with permission.
-	// http://blindsignals.com/index.php/2009/07/jquery-delay/
-	delay: function( time, type ) {
-		time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
-		type = type || "fx";
-
-		return this.queue( type, function( next, hooks ) {
-			var timeout = setTimeout( next, time );
-			hooks.stop = function() {
-				clearTimeout( timeout );
-			};
-		});
-	},
-	clearQueue: function( type ) {
-		return this.queue( type || "fx", [] );
-	},
-	// Get a promise resolved when queues of a certain type
-	// are emptied (fx is the type by default)
-	promise: function( type, object ) {
-		if ( typeof type !== "string" ) {
-			object = type;
-			type = undefined;
-		}
-		type = type || "fx";
-		var defer = jQuery.Deferred(),
-			elements = this,
-			i = elements.length,
-			count = 1,
-			deferDataKey = type + "defer",
-			queueDataKey = type + "queue",
-			markDataKey = type + "mark",
-			tmp;
-		function resolve() {
-			if ( !( --count ) ) {
-				defer.resolveWith( elements, [ elements ] );
-			}
-		}
-		while( i-- ) {
-			if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
-					( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
-						jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
-					jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
-				count++;
-				tmp.add( resolve );
-			}
-		}
-		resolve();
-		return defer.promise();
-	}
-});
-
-
-
-
-var rclass = /[\n\t\r]/g,
-	rspace = /\s+/,
-	rreturn = /\r/g,
-	rtype = /^(?:button|input)$/i,
-	rfocusable = /^(?:button|input|object|select|textarea)$/i,
-	rclickable = /^a(?:rea)?$/i,
-	rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
-	getSetAttribute = jQuery.support.getSetAttribute,
-	nodeHook, boolHook, fixSpecified;
-
-jQuery.fn.extend({
-	attr: function( name, value ) {
-		return jQuery.access( this, name, value, true, jQuery.attr );
-	},
-
-	removeAttr: function( name ) {
-		return this.each(function() {
-			jQuery.removeAttr( this, name );
-		});
-	},
-
-	prop: function( name, value ) {
-		return jQuery.access( this, name, value, true, jQuery.prop );
-	},
-
-	removeProp: function( name ) {
-		name = jQuery.propFix[ name ] || name;
-		return this.each(function() {
-			// try/catch handles cases where IE balks (such as removing a property on window)
-			try {
-				this[ name ] = undefined;
-				delete this[ name ];
-			} catch( e ) {}
-		});
-	},
-
-	addClass: function( value ) {
-		var classNames, i, l, elem,
-			setClass, c, cl;
-
-		if ( jQuery.isFunction( value ) ) {
-			return this.each(function( j ) {
-				jQuery( this ).addClass( value.call(this, j, this.className) );
-			});
-		}
-
-		if ( value && typeof value === "string" ) {
-			classNames = value.split( rspace );
-
-			for ( i = 0, l = this.length; i < l; i++ ) {
-				elem = this[ i ];
-
-				if ( elem.nodeType === 1 ) {
-					if ( !elem.className && classNames.length === 1 ) {
-						elem.className = value;
-
-					} else {
-						setClass = " " + elem.className + " ";
-
-						for ( c = 0, cl = classNames.length; c < cl; c++ ) {
-							if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
-								setClass += classNames[ c ] + " ";
-							}
-						}
-						elem.className = jQuery.trim( setClass );
-					}
-				}
-			}
-		}
-
-		return this;
-	},
-
-	removeClass: function( value ) {
-		var classNames, i, l, elem, className, c, cl;
-
-		if ( jQuery.isFunction( value ) ) {
-			return this.each(function( j ) {
-				jQuery( this ).removeClass( value.call(this, j, this.className) );
-			});
-		}
-
-		if ( (value && typeof value === "string") || value === undefined ) {
-			classNames = ( value || "" ).split( rspace );
-
-			for ( i = 0, l = this.length; i < l; i++ ) {
-				elem = this[ i ];
-
-				if ( elem.nodeType === 1 && elem.className ) {
-					if ( value ) {
-						className = (" " + elem.className + " ").replace( rclass, " " );
-						for ( c = 0, cl = classNames.length; c < cl; c++ ) {
-							className = className.replace(" " + classNames[ c ] + " ", " ");
-						}
-						elem.className = jQuery.trim( className );
-
-					} else {
-						elem.className = "";
-					}
-				}
-			}
-		}
-
-		return this;
-	},
-
-	toggleClass: function( value, stateVal ) {
-		var type = typeof value,
-			isBool = typeof stateVal === "boolean";
-
-		if ( jQuery.isFunction( value ) ) {
-			return this.each(function( i ) {
-				jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
-			});
-		}
-
-		return this.each(function() {
-			if ( type === "string" ) {
-				// toggle individual class names
-				var className,
-					i = 0,
-					self = jQuery( this ),
-					state = stateVal,
-					classNames = value.split( rspace );
-
-				while ( (className = classNames[ i++ ]) ) {
-					// check each className given, space seperated list
-					state = isBool ? state : !self.hasClass( className );
-					self[ state ? "addClass" : "removeClass" ]( className );
-				}
-
-			} else if ( type === "undefined" || type === "boolean" ) {
-				if ( this.className ) {
-					// store className if set
-					jQuery._data( this, "__className__", this.className );
-				}
-
-				// toggle whole className
-				this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
-			}
-		});
-	},
-
-	hasClass: function( selector ) {
-		var className = " " + selector + " ",
-			i = 0,
-			l = this.length;
-		for ( ; i < l; i++ ) {
-			if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
-				return true;
-			}
-		}
-
-		return false;
-	},
-
-	val: function( value ) {
-		var hooks, ret, isFunction,
-			elem = this[0];
-
-		if ( !arguments.length ) {
-			if ( elem ) {
-				hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
-
-				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
-					return ret;
-				}
-
-				ret = elem.value;
-
-				return typeof ret === "string" ?
-					// handle most util string cases
-					ret.replace(rreturn, "") :
-					// handle cases where value is null/undef or number
-					ret == null ? "" : ret;
-			}
-
-			return;
-		}
-
-		isFunction = jQuery.isFunction( value );
-
-		return this.each(function( i ) {
-			var self = jQuery(this), val;
-
-			if ( this.nodeType !== 1 ) {
-				return;
-			}
-
-			if ( isFunction ) {
-				val = value.call( this, i, self.val() );
-			} else {
-				val = value;
-			}
-
-			// Treat null/undefined as ""; convert numbers to string
-			if ( val == null ) {
-				val = "";
-			} else if ( typeof val === "number" ) {
-				val += "";
-			} else if ( jQuery.isArray( val ) ) {
-				val = jQuery.map(val, function ( value ) {
-					return value == null ? "" : value + "";
-				});
-			}
-
-			hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];
-
-			// If set returns undefined, fall back to normal setting
-			if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
-				this.value = val;
-			}
-		});
-	}
-});
-
-jQuery.extend({
-	valHooks: {
-		option: {
-			get: function( elem ) {
-				// attributes.value is undefined in Blackberry 4.7 but
-				// uses .value. See #6932
-				var val = elem.attributes.value;
-				return !val || val.specified ? elem.value : elem.text;
-			}
-		},
-		select: {
-			get: function( elem ) {
-				var value, i, max, option,
-					index = elem.selectedIndex,
-					values = [],
-					options = elem.options,
-					one = elem.type === "select-one";
-
-				// Nothing was selected
-				if ( index < 0 ) {
-					return null;
-				}
-
-				// Loop through all the selected options
-				i = one ? index : 0;
-				max = one ? index + 1 : options.length;
-				for ( ; i < max; i++ ) {
-					option = options[ i ];
-
-					// Don't return options that are disabled or in a disabled optgroup
-					if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
-							(!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
-
-						// Get the specific value for the option
-						value = jQuery( option ).val();
-
-						// We don't need an array for one selects
-						if ( one ) {
-							return value;
-						}
-
-						// Multi-Selects return an array
-						values.push( value );
-					}
-				}
-
-				// Fixes Bug #2551 -- select.val() broken in IE after form.reset()
-				if ( one && !values.length && options.length ) {
-					return jQuery( options[ index ] ).val();
-				}
-
-				return values;
-			},
-
-			set: function( elem, value ) {
-				var values = jQuery.makeArray( value );
-
-				jQuery(elem).find("option").each(function() {
-					this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
-				});
-
-				if ( !values.length ) {
-					elem.selectedIndex = -1;
-				}
-				return values;
-			}
-		}
-	},
-
-	attrFn: {
-		val: true,
-		css: true,
-		html: true,
-		text: true,
-		data: true,
-		width: true,
-		height: true,
-		offset: true
-	},
-
-	attr: function( elem, name, value, pass ) {
-		var ret, hooks, notxml,
-			nType = elem.nodeType;
-
-		// don't get/set attributes on text, comment and attribute nodes
-		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
-			return;
-		}
-
-		if ( pass && name in jQuery.attrFn ) {
-			return jQuery( elem )[ name ]( value );
-		}
-
-		// Fallback to prop when attributes are not supported
-		if ( typeof elem.getAttribute === "undefined" ) {
-			return jQuery.prop( elem, name, value );
-		}
-
-		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
-		// All attributes are lowercase
-		// Grab necessary hook if one is defined
-		if ( notxml ) {
-			name = name.toLowerCase();
-			hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
-		}
-
-		if ( value !== undefined ) {
-
-			if ( value === null ) {
-				jQuery.removeAttr( elem, name );
-				return;
-
-			} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
-				return ret;
-
-			} else {
-				elem.setAttribute( name, "" + value );
-				return value;
-			}
-
-		} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
-			return ret;
-
-		} else {
-
-			ret = elem.getAttribute( name );
-
-			// Non-existent attributes return null, we normalize to undefined
-			return ret === null ?
-				undefined :
-				ret;
-		}
-	},
-
-	removeAttr: function( elem, value ) {
-		var propName, attrNames, name, l,
-			i = 0;
-
-		if ( value && elem.nodeType === 1 ) {
-			attrNames = value.toLowerCase().split( rspace );
-			l = attrNames.length;
-
-			for ( ; i < l; i++ ) {
-				name = attrNames[ i ];
-
-				if ( name ) {
-					propName = jQuery.propFix[ name ] || name;
-
-					// See #9699 for explanation of this approach (setting first, then removal)
-					jQuery.attr( elem, name, "" );
-					elem.removeAttribute( getSetAttribute ? name : propName );
-
-					// Set corresponding property to false for boolean attributes
-					if ( rboolean.test( name ) && propName in elem ) {
-						elem[ propName ] = false;
-					}
-				}
-			}
-		}
-	},
-
-	attrHooks: {
-		type: {
-			set: function( elem, value ) {
-				// We can't allow the type property to be changed (since it causes problems in IE)
-				if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
-					jQuery.error( "type property can't be changed" );
-				} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
-					// Setting the type on a radio button after the value resets the value in IE6-9
-					// Reset value to it's default in case type is set after value
-					// This is for element creation
-					var val = elem.value;
-					elem.setAttribute( "type", value );
-					if ( val ) {
-						elem.value = val;
-					}
-					return value;
-				}
-			}
-		},
-		// Use the value property for back compat
-		// Use the nodeHook for button elements in IE6/7 (#1954)
-		value: {
-			get: function( elem, name ) {
-				if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
-					return nodeHook.get( elem, name );
-				}
-				return name in elem ?
-					elem.value :
-					null;
-			},
-			set: function( elem, value, name ) {
-				if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
-					return nodeHook.set( elem, value, name );
-				}
-				// Does not return so that setAttribute is also used
-				elem.value = value;
-			}
-		}
-	},
-
-	propFix: {
-		tabindex: "tabIndex",
-		readonly: "readOnly",
-		"for": "htmlFor",
-		"class": "className",
-		maxlength: "maxLength",
-		cellspacing: "cellSpacing",
-		cellpadding: "cellPadding",
-		rowspan: "rowSpan",
-		colspan: "colSpan",
-		usemap: "useMap",
-		frameborder: "frameBorder",
-		contenteditable: "contentEditable"
-	},
-
-	prop: function( elem, name, value ) {
-		var ret, hooks, notxml,
-			nType = elem.nodeType;
-
-		// don't get/set properties on text, comment and attribute nodes
-		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
-			return;
-		}
-
-		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
-		if ( notxml ) {
-			// Fix name and attach hooks
-			name = jQuery.propFix[ name ] || name;
-			hooks = jQuery.propHooks[ name ];
-		}
-
-		if ( value !== undefined ) {
-			if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
-				return ret;
-
-			} else {
-				return ( elem[ name ] = value );
-			}
-
-		} else {
-			if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
-				return ret;
-
-			} else {
-				return elem[ name ];
-			}
-		}
-	},
-
-	propHooks: {
-		tabIndex: {
-			get: function( elem ) {
-				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
-				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
-				var attributeNode = elem.getAttributeNode("tabindex");
-
-				return attributeNode && attributeNode.specified ?
-					parseInt( attributeNode.value, 10 ) :
-					rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
-						0 :
-						undefined;
-			}
-		}
-	}
-});
-
-// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
-jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
-
-// Hook for boolean attributes
-boolHook = {
-	get: function( elem, name ) {
-		// Align boolean attributes with corresponding properties
-		// Fall back to attribute presence where some booleans are not supported
-		var attrNode,
-			property = jQuery.prop( elem, name );
-		return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
-			name.toLowerCase() :
-			undefined;
-	},
-	set: function( elem, value, name ) {
-		var propName;
-		if ( value === false ) {
-			// Remove boolean attributes when set to false
-			jQuery.removeAttr( elem, name );
-		} else {
-			// value is true since we know at this point it's type boolean and not false
-			// Set boolean attributes to the same name and set the DOM property
-			propName = jQuery.propFix[ name ] || name;
-			if ( propName in elem ) {
-				// Only set the IDL specifically if it already exists on the element
-				elem[ propName ] = true;
-			}
-
-			elem.setAttribute( name, name.toLowerCase() );
-		}
-		return name;
-	}
-};
-
-// IE6/7 do not support getting/setting some attributes with get/setAttribute
-if ( !getSetAttribute ) {
-
-	fixSpecified = {
-		name: true,
-		id: true
-	};
-
-	// Use this for any attribute in IE6/7
-	// This fixes almost every IE6/7 issue
-	nodeHook = jQuery.valHooks.button = {
-		get: function( elem, name ) {
-			var ret;
-			ret = elem.getAttributeNode( name );
-			return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
-				ret.nodeValue :
-				undefined;
-		},
-		set: function( elem, value, name ) {
-			// Set the existing or create a new attribute node
-			var ret = elem.getAttributeNode( name );
-			if ( !ret ) {
-				ret = document.createAttribute( name );
-				elem.setAttributeNode( ret );
-			}
-			return ( ret.nodeValue = value + "" );
-		}
-	};
-
-	// Apply the nodeHook to tabindex
-	jQuery.attrHooks.tabindex.set = nodeHook.set;
-
-	// Set width and height to auto instead of 0 on empty string( Bug #8150 )
-	// This is for removals
-	jQuery.each([ "width", "height" ], function( i, name ) {
-		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
-			set: function( elem, value ) {
-				if ( value === "" ) {
-					elem.setAttribute( name, "auto" );
-					return value;
-				}
-			}
-		});
-	});
-
-	// Set contenteditable to false on removals(#10429)
-	// Setting to empty string throws an error as an invalid value
-	jQuery.attrHooks.contenteditable = {
-		get: nodeHook.get,
-		set: function( elem, value, name ) {
-			if ( value === "" ) {
-				value = "false";
-			}
-			nodeHook.set( elem, value, name );
-		}
-	};
-}
-
-
-// Some attributes require a special call on IE
-if ( !jQuery.support.hrefNormalized ) {
-	jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
-		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
-			get: function( elem ) {
-				var ret = elem.getAttribute( name, 2 );
-				return ret === null ? undefined : ret;
-			}
-		});
-	});
-}
-
-if ( !jQuery.support.style ) {
-	jQuery.attrHooks.style = {
-		get: function( elem ) {
-			// Return undefined in the case of empty string
-			// Normalize to lowercase since IE uppercases css property names
-			return elem.style.cssText.toLowerCase() || undefined;
-		},
-		set: function( elem, value ) {
-			return ( elem.style.cssText = "" + value );
-		}
-	};
-}
-
-// Safari mis-reports the default selected property of an option
-// Accessing the parent's selectedIndex property fixes it
-if ( !jQuery.support.optSelected ) {
-	jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
-		get: function( elem ) {
-			var parent = elem.parentNode;
-
-			if ( parent ) {
-				parent.selectedIndex;
-
-				// Make sure that it also works with optgroups, see #5701
-				if ( parent.parentNode ) {
-					parent.parentNode.selectedIndex;
-				}
-			}
-			return null;
-		}
-	});
-}
-
-// IE6/7 call enctype encoding
-if ( !jQuery.support.enctype ) {
-	jQuery.propFix.enctype = "encoding";
-}
-
-// Radios and checkboxes getter/setter
-if ( !jQuery.support.checkOn ) {
-	jQuery.each([ "radio", "checkbox" ], function() {
-		jQuery.valHooks[ this ] = {
-			get: function( elem ) {
-				// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
-				return elem.getAttribute("value") === null ? "on" : elem.value;
-			}
-		};
-	});
-}
-jQuery.each([ "radio", "checkbox" ], function() {
-	jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
-		set: function( elem, value ) {
-			if ( jQuery.isArray( value ) ) {
-				return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
-			}
-		}
-	});
-});
-
-
-
-
-var rformElems = /^(?:textarea|input|select)$/i,
-	rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
-	rhoverHack = /\bhover(\.\S+)?\b/,
-	rkeyEvent = /^key/,
-	rmouseEvent = /^(?:mouse|contextmenu)|click/,
-	rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
-	rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
-	quickParse = function( selector ) {
-		var quick = rquickIs.exec( selector );
-		if ( quick ) {
-			//   0  1    2   3
-			// [ _, tag, id, class ]
-			quick[1] = ( quick[1] || "" ).toLowerCase();
-			quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
-		}
-		return quick;
-	},
-	quickIs = function( elem, m ) {
-		var attrs = elem.attributes || {};
-		return (
-			(!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
-			(!m[2] || (attrs.id || {}).value === m[2]) &&
-			(!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))
-		);
-	},
-	hoverHack = function( events ) {
-		return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
-	};
-
-/*
- * Helper functions for managing events -- not part of the public interface.
- * Props to Dean Edwards' addEvent library for many of the ideas.
- */
-jQuery.event = {
-
-	add: function( elem, types, handler, data, selector ) {
-
-		var elemData, eventHandle, events,
-			t, tns, type, namespaces, handleObj,
-			handleObjIn, quick, handlers, special;
-
-		// Don't attach events to noData or text/comment nodes (allow plain objects tho)
-		if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
-			return;
-		}
-
-		// Caller can pass in an object of custom data in lieu of the handler
-		if ( handler.handler ) {
-			handleObjIn = handler;
-			handler = handleObjIn.handler;
-		}
-
-		// Make sure that the handler has a unique ID, used to find/remove it later
-		if ( !handler.guid ) {
-			handler.guid = jQuery.guid++;
-		}
-
-		// Init the element's event structure and main handler, if this is the first
-		events = elemData.events;
-		if ( !events ) {
-			elemData.events = events = {};
-		}
-		eventHandle = elemData.handle;
-		if ( !eventHandle ) {
-			elemData.handle = eventHandle = function( e ) {
-				// Discard the second event of a jQuery.event.trigger() and
-				// when an event is called after a page has unloaded
-				return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
-					jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
-					undefined;
-			};
-			// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
-			eventHandle.elem = elem;
-		}
-
-		// Handle multiple events separated by a space
-		// jQuery(...).bind("mouseover mouseout", fn);
-		types = jQuery.trim( hoverHack(types) ).split( " " );
-		for ( t = 0; t < types.length; t++ ) {
-
-			tns = rtypenamespace.exec( types[t] ) || [];
-			type = tns[1];
-			namespaces = ( tns[2] || "" ).split( "." ).sort();
-
-			// If event changes its type, use the special event handlers for the changed type
-			special = jQuery.event.special[ type ] || {};
-
-			// If selector defined, determine special event api type, otherwise given type
-			type = ( selector ? special.delegateType : special.bindType ) || type;
-
-			// Update special based on newly reset type
-			special = jQuery.event.special[ type ] || {};
-
-			// handleObj is passed to all event handlers
-			handleObj = jQuery.extend({
-				type: type,
-				origType: tns[1],
-				data: data,
-				handler: handler,
-				guid: handler.guid,
-				selector: selector,
-				quick: quickParse( selector ),
-				namespace: namespaces.join(".")
-			}, handleObjIn );
-
-			// Init the event handler queue if we're the first
-			handlers = events[ type ];
-			if ( !handlers ) {
-				handlers = events[ type ] = [];
-				handlers.delegateCount = 0;
-
-				// Only use addEventListener/attachEvent if the special events handler returns false
-				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
-					// Bind the global event handler to the element
-					if ( elem.addEventListener ) {
-						elem.addEventListener( type, eventHandle, false );
-
-					} else if ( elem.attachEvent ) {
-						elem.attachEvent( "on" + type, eventHandle );
-					}
-				}
-			}
-
-			if ( special.add ) {
-				special.add.call( elem, handleObj );
-
-				if ( !handleObj.handler.guid ) {
-					handleObj.handler.guid = handler.guid;
-				}
-			}
-
-			// Add to the element's handler list, delegates in front
-			if ( selector ) {
-				handlers.splice( handlers.delegateCount++, 0, handleObj );
-			} else {
-				handlers.push( handleObj );
-			}
-
-			// Keep track of which events have ever been used, for event optimization
-			jQuery.event.global[ type ] = true;
-		}
-
-		// Nullify elem to prevent memory leaks in IE
-		elem = null;
-	},
-
-	global: {},
-
-	// Detach an event or set of events from an element
-	remove: function( elem, types, handler, selector, mappedTypes ) {
-
-		var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
-			t, tns, type, origType, namespaces, origCount,
-			j, events, special, handle, eventType, handleObj;
-
-		if ( !elemData || !(events = elemData.events) ) {
-			return;
-		}
-
-		// Once for each type.namespace in types; type may be omitted
-		types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
-		for ( t = 0; t < types.length; t++ ) {
-			tns = rtypenamespace.exec( types[t] ) || [];
-			type = origType = tns[1];
-			namespaces = tns[2];
-
-			// Unbind all events (on this namespace, if provided) for the element
-			if ( !type ) {
-				for ( type in events ) {
-					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
-				}
-				continue;
-			}
-
-			special = jQuery.event.special[ type ] || {};
-			type = ( selector? special.delegateType : special.bindType ) || type;
-			eventType = events[ type ] || [];
-			origCount = eventType.length;
-			namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
-
-			// Remove matching events
-			for ( j = 0; j < eventType.length; j++ ) {
-				handleObj = eventType[ j ];
-
-				if ( ( mappedTypes || origType === handleObj.origType ) &&
-					 ( !handler || handler.guid === handleObj.guid ) &&
-					 ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
-					 ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
-					eventType.splice( j--, 1 );
-
-					if ( handleObj.selector ) {
-						eventType.delegateCount--;
-					}
-					if ( special.remove ) {
-						special.remove.call( elem, handleObj );
-					}
-				}
-			}
-
-			// Remove generic event handler if we removed something and no more handlers exist
-			// (avoids potential for endless recursion during removal of special event handlers)
-			if ( eventType.length === 0 && origCount !== eventType.length ) {
-				if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
-					jQuery.removeEvent( elem, type, elemData.handle );
-				}
-
-				delete events[ type ];
-			}
-		}
-
-		// Remove the expando if it's no longer used
-		if ( jQuery.isEmptyObject( events ) ) {
-			handle = elemData.handle;
-			if ( handle ) {
-				handle.elem = null;
-			}
-
-			// removeData also checks for emptiness and clears the expando if empty
-			// so use it instead of delete
-			jQuery.removeData( elem, [ "events", "handle" ], true );
-		}
-	},
-
-	// Events that are safe to short-circuit if no handlers are attached.
-	// Native DOM events should not be added, they may have inline handlers.
-	customEvent: {
-		"getData": true,
-		"setData": true,
-		"changeData": true
-	},
-
-	trigger: function( event, data, elem, onlyHandlers ) {
-		// Don't do events on text and comment nodes
-		if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
-			return;
-		}
-
-		// Event object or event type
-		var type = event.type || event,
-			namespaces = [],
-			cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
-
-		// focus/blur morphs to focusin/out; ensure we're not firing them right now
-		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
-			return;
-		}
-
-		if ( type.indexOf( "!" ) >= 0 ) {
-			// Exclusive events trigger only for the exact event (no namespaces)
-			type = type.slice(0, -1);
-			exclusive = true;
-		}
-
-		if ( type.indexOf( "." ) >= 0 ) {
-			// Namespaced trigger; create a regexp to match event type in handle()
-			namespaces = type.split(".");
-			type = namespaces.shift();
-			namespaces.sort();
-		}
-
-		if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
-			// No jQuery handlers for this event type, and it can't have inline handlers
-			return;
-		}
-
-		// Caller can pass in an Event, Object, or just an event type string
-		event = typeof event === "object" ?
-			// jQuery.Event object
-			event[ jQuery.expando ] ? event :
-			// Object literal
-			new jQuery.Event( type, event ) :
-			// Just the event type (string)
-			new jQuery.Event( type );
-
-		event.type = type;
-		event.isTrigger = true;
-		event.exclusive = exclusive;
-		event.namespace = namespaces.join( "." );
-		event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
-		ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
-
-		// Handle a global trigger
-		if ( !elem ) {
-
-			// TODO: Stop taunting the data cache; remove global events and always attach to document
-			cache = jQuery.cache;
-			for ( i in cache ) {
-				if ( cache[ i ].events && cache[ i ].events[ type ] ) {
-					jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
-				}
-			}
-			return;
-		}
-
-		// Clean up the event in case it is being reused
-		event.result = undefined;
-		if ( !event.target ) {
-			event.target = elem;
-		}
-
-		// Clone any incoming data and prepend the event, creating the handler arg list
-		data = data != null ? jQuery.makeArray( data ) : [];
-		data.unshift( event );
-
-		// Allow special events to draw outside the lines
-		special = jQuery.event.special[ type ] || {};
-		if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
-			return;
-		}
-
-		// Determine event propagation path in advance, per W3C events spec (#9951)
-		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
-		eventPath = [[ elem, special.bindType || type ]];
-		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
-
-			bubbleType = special.delegateType || type;
-			cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
-			old = null;
-			for ( ; cur; cur = cur.parentNode ) {
-				eventPath.push([ cur, bubbleType ]);
-				old = cur;
-			}
-
-			// Only add window if we got to document (e.g., not plain obj or detached DOM)
-			if ( old && old === elem.ownerDocument ) {
-				eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
-			}
-		}
-
-		// Fire handlers on the event path
-		for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
-
-			cur = eventPath[i][0];
-			event.type = eventPath[i][1];
-
-			handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
-			if ( handle ) {
-				handle.apply( cur, data );
-			}
-			// Note that this is a bare JS function and not a jQuery handler
-			handle = ontype && cur[ ontype ];
-			if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
-				event.preventDefault();
-			}
-		}
-		event.type = type;
-
-		// If nobody prevented the default action, do it now
-		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
-
-			if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
-				!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
-
-				// Call a native DOM method on the target with the same name name as the event.
-				// Can't use an .isFunction() check here because IE6/7 fails that test.
-				// Don't do default actions on window, that's where global variables be (#6170)
-				// IE<9 dies on focus/blur to hidden element (#1486)
-				if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
-
-					// Don't re-trigger an onFOO event when we call its FOO() method
-					old = elem[ ontype ];
-
-					if ( old ) {
-						elem[ ontype ] = null;
-					}
-
-					// Prevent re-triggering of the same event, since we already bubbled it above
-					jQuery.event.triggered = type;
-					elem[ type ]();
-					jQuery.event.triggered = undefined;
-
-					if ( old ) {
-						elem[ ontype ] = old;
-					}
-				}
-			}
-		}
-
-		return event.result;
-	},
-
-	dispatch: function( event ) {
-
-		// Make a writable jQuery.Event from the native event object
-		event = jQuery.event.fix( event || window.event );
-
-		var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
-			delegateCount = handlers.delegateCount,
-			args = [].slice.call( arguments, 0 ),
-			run_all = !event.exclusive && !event.namespace,
-			handlerQueue = [],
-			i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;
-
-		// Use the fix-ed jQuery.Event rather than the (read-only) native event
-		args[0] = event;
-		event.delegateTarget = this;
-
-		// Determine handlers that should run if there are delegated events
-		// Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861)
-		if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) {
-
-			// Pregenerate a single jQuery object for reuse with .is()
-			jqcur = jQuery(this);
-			jqcur.context = this.ownerDocument || this;
-
-			for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
-				selMatch = {};
-				matches = [];
-				jqcur[0] = cur;
-				for ( i = 0; i < delegateCount; i++ ) {
-					handleObj = handlers[ i ];
-					sel = handleObj.selector;
-
-					if ( selMatch[ sel ] === undefined ) {
-						selMatch[ sel ] = (
-							handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
-						);
-					}
-					if ( selMatch[ sel ] ) {
-						matches.push( handleObj );
-					}
-				}
-				if ( matches.length ) {
-					handlerQueue.push({ elem: cur, matches: matches });
-				}
-			}
-		}
-
-		// Add the remaining (directly-bound) handlers
-		if ( handlers.length > delegateCount ) {
-			handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
-		}
-
-		// Run delegates first; they may want to stop propagation beneath us
-		for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
-			matched = handlerQueue[ i ];
-			event.currentTarget = matched.elem;
-
-			for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
-				handleObj = matched.matches[ j ];
-
-				// Triggered event must either 1) be non-exclusive and have no namespace, or
-				// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
-				if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
-
-					event.data = handleObj.data;
-					event.handleObj = handleObj;
-
-					ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
-							.apply( matched.elem, args );
-
-					if ( ret !== undefined ) {
-						event.result = ret;
-						if ( ret === false ) {
-							event.preventDefault();
-							event.stopPropagation();
-						}
-					}
-				}
-			}
-		}
-
-		return event.result;
-	},
-
-	// Includes some event props shared by KeyEvent and MouseEvent
-	// *** attrChange attrName relatedNode srcElement  are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
-	props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
-
-	fixHooks: {},
-
-	keyHooks: {
-		props: "char charCode key keyCode".split(" "),
-		filter: function( event, original ) {
-
-			// Add which for key events
-			if ( event.which == null ) {
-				event.which = original.charCode != null ? original.charCode : original.keyCode;
-			}
-
-			return event;
-		}
-	},
-
-	mouseHooks: {
-		props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
-		filter: function( event, original ) {
-			var eventDoc, doc, body,
-				button = original.button,
-				fromElement = original.fromElement;
-
-			// Calculate pageX/Y if missing and clientX/Y available
-			if ( event.pageX == null && original.clientX != null ) {
-				eventDoc = event.target.ownerDocument || document;
-				doc = eventDoc.documentElement;
-				body = eventDoc.body;
-
-				event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
-				event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
-			}
-
-			// Add relatedTarget, if necessary
-			if ( !event.relatedTarget && fromElement ) {
-				event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
-			}
-
-			// Add which for click: 1 === left; 2 === middle; 3 === right
-			// Note: button is not normalized, so don't use it
-			if ( !event.which && button !== undefined ) {
-				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
-			}
-
-			return event;
-		}
-	},
-
-	fix: function( event ) {
-		if ( event[ jQuery.expando ] ) {
-			return event;
-		}
-
-		// Create a writable copy of the event object and normalize some properties
-		var i, prop,
-			originalEvent = event,
-			fixHook = jQuery.event.fixHooks[ event.type ] || {},
-			copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
-
-		event = jQuery.Event( originalEvent );
-
-		for ( i = copy.length; i; ) {
-			prop = copy[ --i ];
-			event[ prop ] = originalEvent[ prop ];
-		}
-
-		// Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
-		if ( !event.target ) {
-			event.target = originalEvent.srcElement || document;
-		}
-
-		// Target should not be a text node (#504, Safari)
-		if ( event.target.nodeType === 3 ) {
-			event.target = event.target.parentNode;
-		}
-
-		// For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
-		if ( event.metaKey === undefined ) {
-			event.metaKey = event.ctrlKey;
-		}
-
-		return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
-	},
-
-	special: {
-		ready: {
-			// Make sure the ready event is setup
-			setup: jQuery.bindReady
-		},
-
-		load: {
-			// Prevent triggered image.load events from bubbling to window.load
-			noBubble: true
-		},
-
-		focus: {
-			delegateType: "focusin"
-		},
-		blur: {
-			delegateType: "focusout"
-		},
-
-		beforeunload: {
-			setup: function( data, namespaces, eventHandle ) {
-				// We only want to do this special case on windows
-				if ( jQuery.isWindow( this ) ) {
-					this.onbeforeunload = eventHandle;
-				}
-			},
-
-			teardown: function( namespaces, eventHandle ) {
-				if ( this.onbeforeunload === eventHandle ) {
-					this.onbeforeunload = null;
-				}
-			}
-		}
-	},
-
-	simulate: function( type, elem, event, bubble ) {
-		// Piggyback on a donor event to simulate a different one.
-		// Fake originalEvent to avoid donor's stopPropagation, but if the
-		// simulated event prevents default then we do the same on the donor.
-		var e = jQuery.extend(
-			new jQuery.Event(),
-			event,
-			{ type: type,
-				isSimulated: true,
-				originalEvent: {}
-			}
-		);
-		if ( bubble ) {
-			jQuery.event.trigger( e, null, elem );
-		} else {
-			jQuery.event.dispatch.call( elem, e );
-		}
-		if ( e.isDefaultPrevented() ) {
-			event.preventDefault();
-		}
-	}
-};
-
-// Some plugins are using, but it's undocumented/deprecated and will be removed.
-// The 1.7 special event interface should provide all the hooks needed now.
-jQuery.event.handle = jQuery.event.dispatch;
-
-jQuery.removeEvent = document.removeEventListener ?
-	function( elem, type, handle ) {
-		if ( elem.removeEventListener ) {
-			elem.removeEventListener( type, handle, false );
-		}
-	} :
-	function( elem, type, handle ) {
-		if ( elem.detachEvent ) {
-			elem.detachEvent( "on" + type, handle );
-		}
-	};
-
-jQuery.Event = function( src, props ) {
-	// Allow instantiation without the 'new' keyword
-	if ( !(this instanceof jQuery.Event) ) {
-		return new jQuery.Event( src, props );
-	}
-
-	// Event object
-	if ( src && src.type ) {
-		this.originalEvent = src;
-		this.type = src.type;
-
-		// Events bubbling up the document may have been marked as prevented
-		// by a handler lower down the tree; reflect the correct value.
-		this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
-			src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
-
-	// Event type
-	} else {
-		this.type = src;
-	}
-
-	// Put explicitly provided properties onto the event object
-	if ( props ) {
-		jQuery.extend( this, props );
-	}
-
-	// Create a timestamp if incoming event doesn't have one
-	this.timeStamp = src && src.timeStamp || jQuery.now();
-
-	// Mark it as fixed
-	this[ jQuery.expando ] = true;
-};
-
-function returnFalse() {
-	return false;
-}
-function returnTrue() {
-	return true;
-}
-
-// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
-// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
-jQuery.Event.prototype = {
-	preventDefault: function() {
-		this.isDefaultPrevented = returnTrue;
-
-		var e = this.originalEvent;
-		if ( !e ) {
-			return;
-		}
-
-		// if preventDefault exists run it on the original event
-		if ( e.preventDefault ) {
-			e.preventDefault();
-
-		// otherwise set the returnValue property of the original event to false (IE)
-		} else {
-			e.returnValue = false;
-		}
-	},
-	stopPropagation: function() {
-		this.isPropagationStopped = returnTrue;
-
-		var e = this.originalEvent;
-		if ( !e ) {
-			return;
-		}
-		// if stopPropagation exists run it on the original event
-		if ( e.stopPropagation ) {
-			e.stopPropagation();
-		}
-		// otherwise set the cancelBubble property of the original event to true (IE)
-		e.cancelBubble = true;
-	},
-	stopImmediatePropagation: function() {
-		this.isImmediatePropagationStopped = returnTrue;
-		this.stopPropagation();
-	},
-	isDefaultPrevented: returnFalse,
-	isPropagationStopped: returnFalse,
-	isImmediatePropagationStopped: returnFalse
-};
-
-// Create mouseenter/leave events using mouseover/out and event-time checks
-jQuery.each({
-	mouseenter: "mouseover",
-	mouseleave: "mouseout"
-}, function( orig, fix ) {
-	jQuery.event.special[ orig ] = {
-		delegateType: fix,
-		bindType: fix,
-
-		handle: function( event ) {
-			var target = this,
-				related = event.relatedTarget,
-				handleObj = event.handleObj,
-				selector = handleObj.selector,
-				ret;
-
-			// For mousenter/leave call the handler if related is outside the target.
-			// NB: No relatedTarget if the mouse left/entered the browser window
-			if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
-				event.type = handleObj.origType;
-				ret = handleObj.handler.apply( this, arguments );
-				event.type = fix;
-			}
-			return ret;
-		}
-	};
-});
-
-// IE submit delegation
-if ( !jQuery.support.submitBubbles ) {
-
-	jQuery.event.special.submit = {
-		setup: function() {
-			// Only need this for delegated form submit events
-			if ( jQuery.nodeName( this, "form" ) ) {
-				return false;
-			}
-
-			// Lazy-add a submit handler when a descendant form may potentially be submitted
-			jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
-				// Node name check avoids a VML-related crash in IE (#9807)
-				var elem = e.target,
-					form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
-				if ( form && !form._submit_attached ) {
-					jQuery.event.add( form, "submit._submit", function( event ) {
-						// If form was submitted by the user, bubble the event up the tree
-						if ( this.parentNode && !event.isTrigger ) {
-							jQuery.event.simulate( "submit", this.parentNode, event, true );
-						}
-					});
-					form._submit_attached = true;
-				}
-			});
-			// return undefined since we don't need an event listener
-		},
-
-		teardown: function() {
-			// Only need this for delegated form submit events
-			if ( jQuery.nodeName( this, "form" ) ) {
-				return false;
-			}
-
-			// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
-			jQuery.event.remove( this, "._submit" );
-		}
-	};
-}
-
-// IE change delegation and checkbox/radio fix
-if ( !jQuery.support.changeBubbles ) {
-
-	jQuery.event.special.change = {
-
-		setup: function() {
-
-			if ( rformElems.test( this.nodeName ) ) {
-				// IE doesn't fire change on a check/radio until blur; trigger it on click
-				// after a propertychange. Eat the blur-change in special.change.handle.
-				// This still fires onchange a second time for check/radio after blur.
-				if ( this.type === "checkbox" || this.type === "radio" ) {
-					jQuery.event.add( this, "propertychange._change", function( event ) {
-						if ( event.originalEvent.propertyName === "checked" ) {
-							this._just_changed = true;
-						}
-					});
-					jQuery.event.add( this, "click._change", function( event ) {
-						if ( this._just_changed && !event.isTrigger ) {
-							this._just_changed = false;
-							jQuery.event.simulate( "change", this, event, true );
-						}
-					});
-				}
-				return false;
-			}
-			// Delegated event; lazy-add a change handler on descendant inputs
-			jQuery.event.add( this, "beforeactivate._change", function( e ) {
-				var elem = e.target;
-
-				if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
-					jQuery.event.add( elem, "change._change", function( event ) {
-						if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
-							jQuery.event.simulate( "change", this.parentNode, event, true );
-						}
-					});
-					elem._change_attached = true;
-				}
-			});
-		},
-
-		handle: function( event ) {
-			var elem = event.target;
-
-			// Swallow native change events from checkbox/radio, we already triggered them above
-			if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
-				return event.handleObj.handler.apply( this, arguments );
-			}
-		},
-
-		teardown: function() {
-			jQuery.event.remove( this, "._change" );
-
-			return rformElems.test( this.nodeName );
-		}
-	};
-}
-
-// Create "bubbling" focus and blur events
-if ( !jQuery.support.focusinBubbles ) {
-	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-
-		// Attach a single capturing handler while someone wants focusin/focusout
-		var attaches = 0,
-			handler = function( event ) {
-				jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
-			};
-
-		jQuery.event.special[ fix ] = {
-			setup: function() {
-				if ( attaches++ === 0 ) {
-					document.addEventListener( orig, handler, true );
-				}
-			},
-			teardown: function() {
-				if ( --attaches === 0 ) {
-					document.removeEventListener( orig, handler, true );
-				}
-			}
-		};
-	});
-}
-
-jQuery.fn.extend({
-
-	on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
-		var origFn, type;
-
-		// Types can be a map of types/handlers
-		if ( typeof types === "object" ) {
-			// ( types-Object, selector, data )
-			if ( typeof selector !== "string" ) {
-				// ( types-Object, data )
-				data = selector;
-				selector = undefined;
-			}
-			for ( type in types ) {
-				this.on( type, selector, data, types[ type ], one );
-			}
-			return this;
-		}
-
-		if ( data == null && fn == null ) {
-			// ( types, fn )
-			fn = selector;
-			data = selector = undefined;
-		} else if ( fn == null ) {
-			if ( typeof selector === "string" ) {
-				// ( types, selector, fn )
-				fn = data;
-				data = undefined;
-			} else {
-				// ( types, data, fn )
-				fn = data;
-				data = selector;
-				selector = undefined;
-			}
-		}
-		if ( fn === false ) {
-			fn = returnFalse;
-		} else if ( !fn ) {
-			return this;
-		}
-
-		if ( one === 1 ) {
-			origFn = fn;
-			fn = function( event ) {
-				// Can use an empty set, since event contains the info
-				jQuery().off( event );
-				return origFn.apply( this, arguments );
-			};
-			// Use same guid so caller can remove using origFn
-			fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
-		}
-		return this.each( function() {
-			jQuery.event.add( this, types, fn, data, selector );
-		});
-	},
-	one: function( types, selector, data, fn ) {
-		return this.on.call( this, types, selector, data, fn, 1 );
-	},
-	off: function( types, selector, fn ) {
-		if ( types && types.preventDefault && types.handleObj ) {
-			// ( event )  dispatched jQuery.Event
-			var handleObj = types.handleObj;
-			jQuery( types.delegateTarget ).off(
-				handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type,
-				handleObj.selector,
-				handleObj.handler
-			);
-			return this;
-		}
-		if ( typeof types === "object" ) {
-			// ( types-object [, selector] )
-			for ( var type in types ) {
-				this.off( type, selector, types[ type ] );
-			}
-			return this;
-		}
-		if ( selector === false || typeof selector === "function" ) {
-			// ( types [, fn] )
-			fn = selector;
-			selector = undefined;
-		}
-		if ( fn === false ) {
-			fn = returnFalse;
-		}
-		return this.each(function() {
-			jQuery.event.remove( this, types, fn, selector );
-		});
-	},
-
-	bind: function( types, data, fn ) {
-		return this.on( types, null, data, fn );
-	},
-	unbind: function( types, fn ) {
-		return this.off( types, null, fn );
-	},
-
-	live: function( types, data, fn ) {
-		jQuery( this.context ).on( types, this.selector, data, fn );
-		return this;
-	},
-	die: function( types, fn ) {
-		jQuery( this.context ).off( types, this.selector || "**", fn );
-		return this;
-	},
-
-	delegate: function( selector, types, data, fn ) {
-		return this.on( types, selector, data, fn );
-	},
-	undelegate: function( selector, types, fn ) {
-		// ( namespace ) or ( selector, types [, fn] )
-		return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
-	},
-
-	trigger: function( type, data ) {
-		return this.each(function() {
-			jQuery.event.trigger( type, data, this );
-		});
-	},
-	triggerHandler: function( type, data ) {
-		if ( this[0] ) {
-			return jQuery.event.trigger( type, data, this[0], true );
-		}
-	},
-
-	toggle: function( fn ) {
-		// Save reference to arguments for access in closure
-		var args = arguments,
-			guid = fn.guid || jQuery.guid++,
-			i = 0,
-			toggler = function( event ) {
-				// Figure out which function to execute
-				var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
-				jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
-
-				// Make sure that clicks stop
-				event.preventDefault();
-
-				// and execute the function
-				return args[ lastToggle ].apply( this, arguments ) || false;
-			};
-
-		// link all the functions, so any of them can unbind this click handler
-		toggler.guid = guid;
-		while ( i < args.length ) {
-			args[ i++ ].guid = guid;
-		}
-
-		return this.click( toggler );
-	},
-
-	hover: function( fnOver, fnOut ) {
-		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
-	}
-});
-
-jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
-	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
-	"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
-
-	// Handle event binding
-	jQuery.fn[ name ] = function( data, fn ) {
-		if ( fn == null ) {
-			fn = data;
-			data = null;
-		}
-
-		return arguments.length > 0 ?
-			this.on( name, null, data, fn ) :
-			this.trigger( name );
-	};
-
-	if ( jQuery.attrFn ) {
-		jQuery.attrFn[ name ] = true;
-	}
-
-	if ( rkeyEvent.test( name ) ) {
-		jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
-	}
-
-	if ( rmouseEvent.test( name ) ) {
-		jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
-	}
-});
-
-
-
-/*!
- * Sizzle CSS Selector Engine
- *  Copyright 2011, The Dojo Foundation
- *  Released under the MIT, BSD, and GPL Licenses.
- *  More information: http://sizzlejs.com/
- */
-(function(){
-
-var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
-	expando = "sizcache" + (Math.random() + '').replace('.', ''),
-	done = 0,
-	toString = Object.prototype.toString,
-	hasDuplicate = false,
-	baseHasDuplicate = true,
-	rBackslash = /\\/g,
-	rReturn = /\r\n/g,
-	rNonWord = /\W/;
-
-// Here we check if the JavaScript engine is using some sort of
-// optimization where it does not always call our comparision
-// function. If that is the case, discard the hasDuplicate value.
-//   Thus far that includes Google Chrome.
-[0, 0].sort(function() {
-	baseHasDuplicate = false;
-	return 0;
-});
-
-var Sizzle = function( selector, context, results, seed ) {
-	results = results || [];
-	context = context || document;
-
-	var origContext = context;
-
-	if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
-		return [];
-	}
-	
-	if ( !selector || typeof selector !== "string" ) {
-		return results;
-	}
-
-	var m, set, checkSet, extra, ret, cur, pop, i,
-		prune = true,
-		contextXML = Sizzle.isXML( context ),
-		parts = [],
-		soFar = selector;
-	
-	// Reset the position of the chunker regexp (start from head)
-	do {
-		chunker.exec( "" );
-		m = chunker.exec( soFar );
-
-		if ( m ) {
-			soFar = m[3];
-		
-			parts.push( m[1] );
-		
-			if ( m[2] ) {
-				extra = m[3];
-				break;
-			}
-		}
-	} while ( m );
-
-	if ( parts.length > 1 && origPOS.exec( selector ) ) {
-
-		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
-			set = posProcess( parts[0] + parts[1], context, seed );
-
-		} else {
-			set = Expr.relative[ parts[0] ] ?
-				[ context ] :
-				Sizzle( parts.shift(), context );
-
-			while ( parts.length ) {
-				selector = parts.shift();
-
-				if ( Expr.relative[ selector ] ) {
-					selector += parts.shift();
-				}
-				
-				set = posProcess( selector, set, seed );
-			}
-		}
-
-	} else {
-		// Take a shortcut and set the context if the root selector is an ID
-		// (but not if it'll be faster if the inner selector is an ID)
-		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
-				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
-
-			ret = Sizzle.find( parts.shift(), context, contextXML );
-			context = ret.expr ?
-				Sizzle.filter( ret.expr, ret.set )[0] :
-				ret.set[0];
-		}
-
-		if ( context ) {
-			ret = seed ?
-				{ expr: parts.pop(), set: makeArray(seed) } :
-				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
-
-			set = ret.expr ?
-				Sizzle.filter( ret.expr, ret.set ) :
-				ret.set;
-
-			if ( parts.length > 0 ) {
-				checkSet = makeArray( set );
-
-			} else {
-				prune = false;
-			}
-
-			while ( parts.length ) {
-				cur = parts.pop();
-				pop = cur;
-
-				if ( !Expr.relative[ cur ] ) {
-					cur = "";
-				} else {
-					pop = parts.pop();
-				}
-
-				if ( pop == null ) {
-					pop = context;
-				}
-
-				Expr.relative[ cur ]( checkSet, pop, contextXML );
-			}
-
-		} else {
-			checkSet = parts = [];
-		}
-	}
-
-	if ( !checkSet ) {
-		checkSet = set;
-	}
-
-	if ( !checkSet ) {
-		Sizzle.error( cur || selector );
-	}
-
-	if ( toString.call(checkSet) === "[object Array]" ) {
-		if ( !prune ) {
-			results.push.apply( results, checkSet );
-
-		} else if ( context && context.nodeType === 1 ) {
-			for ( i = 0; checkSet[i] != null; i++ ) {
-				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
-					results.push( set[i] );
-				}
-			}
-
-		} else {
-			for ( i = 0; checkSet[i] != null; i++ ) {
-				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
-					results.push( set[i] );
-				}
-			}
-		}
-
-	} else {
-		makeArray( checkSet, results );
-	}
-
-	if ( extra ) {
-		Sizzle( extra, origContext, results, seed );
-		Sizzle.uniqueSort( results );
-	}
-
-	return results;
-};
-
-Sizzle.uniqueSort = function( results ) {
-	if ( sortOrder ) {
-		hasDuplicate = baseHasDuplicate;
-		results.sort( sortOrder );
-
-		if ( hasDuplicate ) {
-			for ( var i = 1; i < results.length; i++ ) {
-				if ( results[i] === results[ i - 1 ] ) {
-					results.splice( i--, 1 );
-				}
-			}
-		}
-	}
-
-	return results;
-};
-
-Sizzle.matches = function( expr, set ) {
-	return Sizzle( expr, null, null, set );
-};
-
-Sizzle.matchesSelector = function( node, expr ) {
-	return Sizzle( expr, null, null, [node] ).length > 0;
-};
-
-Sizzle.find = function( expr, context, isXML ) {
-	var set, i, len, match, type, left;
-
-	if ( !expr ) {
-		return [];
-	}
-
-	for ( i = 0, len = Expr.order.length; i < len; i++ ) {
-		type = Expr.order[i];
-		
-		if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
-			left = match[1];
-			match.splice( 1, 1 );
-
-			if ( left.substr( left.length - 1 ) !== "\\" ) {
-				match[1] = (match[1] || "").replace( rBackslash, "" );
-				set = Expr.find[ type ]( match, context, isXML );
-
-				if ( set != null ) {
-					expr = expr.replace( Expr.match[ type ], "" );
-					break;
-				}
-			}
-		}
-	}
-
-	if ( !set ) {
-		set = typeof context.getElementsByTagName !== "undefined" ?
-			context.getElementsByTagName( "*" ) :
-			[];
-	}
-
-	return { set: set, expr: expr };
-};
-
-Sizzle.filter = function( expr, set, inplace, not ) {
-	var match, anyFound,
-		type, found, item, filter, left,
-		i, pass,
-		old = expr,
-		result = [],
-		curLoop = set,
-		isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
-
-	while ( expr && set.length ) {
-		for ( type in Expr.filter ) {
-			if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
-				filter = Expr.filter[ type ];
-				left = match[1];
-
-				anyFound = false;
-
-				match.splice(1,1);
-
-				if ( left.substr( left.length - 1 ) === "\\" ) {
-					continue;
-				}
-
-				if ( curLoop === result ) {
-					result = [];
-				}
-
-				if ( Expr.preFilter[ type ] ) {
-					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
-
-					if ( !match ) {
-						anyFound = found = true;
-
-					} else if ( match === true ) {
-						continue;
-					}
-				}
-
-				if ( match ) {
-					for ( i = 0; (item = curLoop[i]) != null; i++ ) {
-						if ( item ) {
-							found = filter( item, match, i, curLoop );
-							pass = not ^ found;
-
-							if ( inplace && found != null ) {
-								if ( pass ) {
-									anyFound = true;
-
-								} else {
-									curLoop[i] = false;
-								}
-
-							} else if ( pass ) {
-								result.push( item );
-								anyFound = true;
-							}
-						}
-					}
-				}
-
-				if ( found !== undefined ) {
-					if ( !inplace ) {
-						curLoop = result;
-					}
-
-					expr = expr.replace( Expr.match[ type ], "" );
-
-					if ( !anyFound ) {
-						return [];
-					}
-
-					break;
-				}
-			}
-		}
-
-		// Improper expression
-		if ( expr === old ) {
-			if ( anyFound == null ) {
-				Sizzle.error( expr );
-
-			} else {
-				break;
-			}
-		}
-
-		old = expr;
-	}
-
-	return curLoop;
-};
-
-Sizzle.error = function( msg ) {
-	throw new Error( "Syntax error, unrecognized expression: " + msg );
-};
-
-/**
- * Utility function for retreiving the text value of an array of DOM nodes
- * @param {Array|Element} elem
- */
-var getText = Sizzle.getText = function( elem ) {
-    var i, node,
-		nodeType = elem.nodeType,
-		ret = "";
-
-	if ( nodeType ) {
-		if ( nodeType === 1 || nodeType === 9 ) {
-			// Use textContent || innerText for elements
-			if ( typeof elem.textContent === 'string' ) {
-				return elem.textContent;
-			} else if ( typeof elem.innerText === 'string' ) {
-				// Replace IE's carriage returns
-				return elem.innerText.replace( rReturn, '' );
-			} else {
-				// Traverse it's children
-				for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
-					ret += getText( elem );
-				}
-			}
-		} else if ( nodeType === 3 || nodeType === 4 ) {
-			return elem.nodeValue;
-		}
-	} else {
-
-		// If no nodeType, this is expected to be an array
-		for ( i = 0; (node = elem[i]); i++ ) {
-			// Do not traverse comment nodes
-			if ( node.nodeType !== 8 ) {
-				ret += getText( node );
-			}
-		}
-	}
-	return ret;
-};
-
-var Expr = Sizzle.selectors = {
-	order: [ "ID", "NAME", "TAG" ],
-
-	match: {
-		ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
-		CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
-		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
-		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
-		TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
-		CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
-		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
-		PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
-	},
-
-	leftMatch: {},
-
-	attrMap: {
-		"class": "className",
-		"for": "htmlFor"
-	},
-
-	attrHandle: {
-		href: function( elem ) {
-			return elem.getAttribute( "href" );
-		},
-		type: function( elem ) {
-			return elem.getAttribute( "type" );
-		}
-	},
-
-	relative: {
-		"+": function(checkSet, part){
-			var isPartStr = typeof part === "string",
-				isTag = isPartStr && !rNonWord.test( part ),
-				isPartStrNotTag = isPartStr && !isTag;
-
-			if ( isTag ) {
-				part = part.toLowerCase();
-			}
-
-			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
-				if ( (elem = checkSet[i]) ) {
-					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
-
-					checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
-						elem || false :
-						elem === part;
-				}
-			}
-
-			if ( isPartStrNotTag ) {
-				Sizzle.filter( part, checkSet, true );
-			}
-		},
-
-		">": function( checkSet, part ) {
-			var elem,
-				isPartStr = typeof part === "string",
-				i = 0,
-				l = checkSet.length;
-
-			if ( isPartStr && !rNonWord.test( part ) ) {
-				part = part.toLowerCase();
-
-				for ( ; i < l; i++ ) {
-					elem = checkSet[i];
-
-					if ( elem ) {
-						var parent = elem.parentNode;
-						checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
-					}
-				}
-
-			} else {
-				for ( ; i < l; i++ ) {
-					elem = checkSet[i];
-
-					if ( elem ) {
-						checkSet[i] = isPartStr ?
-							elem.parentNode :
-							elem.parentNode === part;
-					}
-				}
-
-				if ( isPartStr ) {
-					Sizzle.filter( part, checkSet, true );
-				}
-			}
-		},
-
-		"": function(checkSet, part, isXML){
-			var nodeCheck,
-				doneName = done++,
-				checkFn = dirCheck;
-
-			if ( typeof part === "string" && !rNonWord.test( part ) ) {
-				part = part.toLowerCase();
-				nodeCheck = part;
-				checkFn = dirNodeCheck;
-			}
-
-			checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
-		},
-
-		"~": function( checkSet, part, isXML ) {
-			var nodeCheck,
-				doneName = done++,
-				checkFn = dirCheck;
-
-			if ( typeof part === "string" && !rNonWord.test( part ) ) {
-				part = part.toLowerCase();
-				nodeCheck = part;
-				checkFn = dirNodeCheck;
-			}
-
-			checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
-		}
-	},
-
-	find: {
-		ID: function( match, context, isXML ) {
-			if ( typeof context.getElementById !== "undefined" && !isXML ) {
-				var m = context.getElementById(match[1]);
-				// Check parentNode to catch when Blackberry 4.6 returns
-				// nodes that are no longer in the document #6963
-				return m && m.parentNode ? [m] : [];
-			}
-		},
-
-		NAME: function( match, context ) {
-			if ( typeof context.getElementsByName !== "undefined" ) {
-				var ret = [],
-					results = context.getElementsByName( match[1] );
-
-				for ( var i = 0, l = results.length; i < l; i++ ) {
-					if ( results[i].getAttribute("name") === match[1] ) {
-						ret.push( results[i] );
-					}
-				}
-
-				return ret.length === 0 ? null : ret;
-			}
-		},
-
-		TAG: function( match, context ) {
-			if ( typeof context.getElementsByTagName !== "undefined" ) {
-				return context.getElementsByTagName( match[1] );
-			}
-		}
-	},
-	preFilter: {
-		CLASS: function( match, curLoop, inplace, result, not, isXML ) {
-			match = " " + match[1].replace( rBackslash, "" ) + " ";
-
-			if ( isXML ) {
-				return match;
-			}
-
-			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
-				if ( elem ) {
-					if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
-						if ( !inplace ) {
-							result.push( elem );
-						}
-
-					} else if ( inplace ) {
-						curLoop[i] = false;
-					}
-				}
-			}
-
-			return false;
-		},
-
-		ID: function( match ) {
-			return match[1].replace( rBackslash, "" );
-		},
-
-		TAG: function( match, curLoop ) {
-			return match[1].replace( rBackslash, "" ).toLowerCase();
-		},
-
-		CHILD: function( match ) {
-			if ( match[1] === "nth" ) {
-				if ( !match[2] ) {
-					Sizzle.error( match[0] );
-				}
-
-				match[2] = match[2].replace(/^\+|\s*/g, '');
-
-				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
-				var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
-					match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
-					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
-
-				// calculate the numbers (first)n+(last) including if they are negative
-				match[2] = (test[1] + (test[2] || 1)) - 0;
-				match[3] = test[3] - 0;
-			}
-			else if ( match[2] ) {
-				Sizzle.error( match[0] );
-			}
-
-			// TODO: Move to normal caching system
-			match[0] = done++;
-
-			return match;
-		},
-
-		ATTR: function( match, curLoop, inplace, result, not, isXML ) {
-			var name = match[1] = match[1].replace( rBackslash, "" );
-			
-			if ( !isXML && Expr.attrMap[name] ) {
-				match[1] = Expr.attrMap[name];
-			}
-
-			// Handle if an un-quoted value was used
-			match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
-
-			if ( match[2] === "~=" ) {
-				match[4] = " " + match[4] + " ";
-			}
-
-			return match;
-		},
-
-		PSEUDO: function( match, curLoop, inplace, result, not ) {
-			if ( match[1] === "not" ) {
-				// If we're dealing with a complex expression, or a simple one
-				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
-					match[3] = Sizzle(match[3], null, null, curLoop);
-
-				} else {
-					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
-
-					if ( !inplace ) {
-						result.push.apply( result, ret );
-					}
-
-					return false;
-				}
-
-			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
-				return true;
-			}
-			
-			return match;
-		},
-
-		POS: function( match ) {
-			match.unshift( true );
-
-			return match;
-		}
-	},
-	
-	filters: {
-		enabled: function( elem ) {
-			return elem.disabled === false && elem.type !== "hidden";
-		},
-
-		disabled: function( elem ) {
-			return elem.disabled === true;
-		},
-
-		checked: function( elem ) {
-			return elem.checked === true;
-		},
-		
-		selected: function( elem ) {
-			// Accessing this property makes selected-by-default
-			// options in Safari work properly
-			if ( elem.parentNode ) {
-				elem.parentNode.selectedIndex;
-			}
-			
-			return elem.selected === true;
-		},
-
-		parent: function( elem ) {
-			return !!elem.firstChild;
-		},
-
-		empty: function( elem ) {
-			return !elem.firstChild;
-		},
-
-		has: function( elem, i, match ) {
-			return !!Sizzle( match[3], elem ).length;
-		},
-
-		header: function( elem ) {
-			return (/h\d/i).test( elem.nodeName );
-		},
-
-		text: function( elem ) {
-			var attr = elem.getAttribute( "type" ), type = elem.type;
-			// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) 
-			// use getAttribute instead to test this case
-			return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
-		},
-
-		radio: function( elem ) {
-			return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
-		},
-
-		checkbox: function( elem ) {
-			return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
-		},
-
-		file: function( elem ) {
-			return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
-		},
-
-		password: function( elem ) {
-			return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
-		},
-
-		submit: function( elem ) {
-			var name = elem.nodeName.toLowerCase();
-			return (name === "input" || name === "button") && "submit" === elem.type;
-		},
-
-		image: function( elem ) {
-			return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
-		},
-
-		reset: function( elem ) {
-			var name = elem.nodeName.toLowerCase();
-			return (name === "input" || name === "button") && "reset" === elem.type;
-		},
-
-		button: function( elem ) {
-			var name = elem.nodeName.toLowerCase();
-			return name === "input" && "button" === elem.type || name === "button";
-		},
-
-		input: function( elem ) {
-			return (/input|select|textarea|button/i).test( elem.nodeName );
-		},
-
-		focus: function( elem ) {
-			return elem === elem.ownerDocument.activeElement;
-		}
-	},
-	setFilters: {
-		first: function( elem, i ) {
-			return i === 0;
-		},
-
-		last: function( elem, i, match, array ) {
-			return i === array.length - 1;
-		},
-
-		even: function( elem, i ) {
-			return i % 2 === 0;
-		},
-
-		odd: function( elem, i ) {
-			return i % 2 === 1;
-		},
-
-		lt: function( elem, i, match ) {
-			return i < match[3] - 0;
-		},
-
-		gt: function( elem, i, match ) {
-			return i > match[3] - 0;
-		},
-
-		nth: function( elem, i, match ) {
-			return match[3] - 0 === i;
-		},
-
-		eq: function( elem, i, match ) {
-			return match[3] - 0 === i;
-		}
-	},
-	filter: {
-		PSEUDO: function( elem, match, i, array ) {
-			var name = match[1],
-				filter = Expr.filters[ name ];
-
-			if ( filter ) {
-				return filter( elem, i, match, array );
-
-			} else if ( name === "contains" ) {
-				return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
-
-			} else if ( name === "not" ) {
-				var not = match[3];
-
-				for ( var j = 0, l = not.length; j < l; j++ ) {
-					if ( not[j] === elem ) {
-						return false;
-					}
-				}
-
-				return true;
-
-			} else {
-				Sizzle.error( name );
-			}
-		},
-
-		CHILD: function( elem, match ) {
-			var first, last,
-				doneName, parent, cache,
-				count, diff,
-				type = match[1],
-				node = elem;
-
-			switch ( type ) {
-				case "only":
-				case "first":
-					while ( (node = node.previousSibling) )	 {
-						if ( node.nodeType === 1 ) { 
-							return false; 
-						}
-					}
-
-					if ( type === "first" ) { 
-						return true; 
-					}
-
-					node = elem;
-
-				case "last":
-					while ( (node = node.nextSibling) )	 {
-						if ( node.nodeType === 1 ) { 
-							return false; 
-						}
-					}
-
-					return true;
-
-				case "nth":
-					first = match[2];
-					last = match[3];
-
-					if ( first === 1 && last === 0 ) {
-						return true;
-					}
-					
-					doneName = match[0];
-					parent = elem.parentNode;
-	
-					if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
-						count = 0;
-						
-						for ( node = parent.firstChild; node; node = node.nextSibling ) {
-							if ( node.nodeType === 1 ) {
-								node.nodeIndex = ++count;
-							}
-						} 
-
-						parent[ expando ] = doneName;
-					}
-					
-					diff = elem.nodeIndex - last;
-
-					if ( first === 0 ) {
-						return diff === 0;
-
-					} else {
-						return ( diff % first === 0 && diff / first >= 0 );
-					}
-			}
-		},
-
-		ID: function( elem, match ) {
-			return elem.nodeType === 1 && elem.getAttribute("id") === match;
-		},
-
-		TAG: function( elem, match ) {
-			return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
-		},
-		
-		CLASS: function( elem, match ) {
-			return (" " + (elem.className || elem.getAttribute("class")) + " ")
-				.indexOf( match ) > -1;
-		},
-
-		ATTR: function( elem, match ) {
-			var name = match[1],
-				result = Sizzle.attr ?
-					Sizzle.attr( elem, name ) :
-					Expr.attrHandle[ name ] ?
-					Expr.attrHandle[ name ]( elem ) :
-					elem[ name ] != null ?
-						elem[ name ] :
-						elem.getAttribute( name ),
-				value = result + "",
-				type = match[2],
-				check = match[4];
-
-			return result == null ?
-				type === "!=" :
-				!type && Sizzle.attr ?
-				result != null :
-				type === "=" ?
-				value === check :
-				type === "*=" ?
-				value.indexOf(check) >= 0 :
-				type === "~=" ?
-				(" " + value + " ").indexOf(check) >= 0 :
-				!check ?
-				value && result !== false :
-				type === "!=" ?
-				value !== check :
-				type === "^=" ?
-				value.indexOf(check) === 0 :
-				type === "$=" ?
-				value.substr(value.length - check.length) === check :
-				type === "|=" ?
-				value === check || value.substr(0, check.length + 1) === check + "-" :
-				false;
-		},
-
-		POS: function( elem, match, i, array ) {
-			var name = match[2],
-				filter = Expr.setFilters[ name ];
-
-			if ( filter ) {
-				return filter( elem, i, match, array );
-			}
-		}
-	}
-};
-
-var origPOS = Expr.match.POS,
-	fescape = function(all, num){
-		return "\\" + (num - 0 + 1);
-	};
-
-for ( var type in Expr.match ) {
-	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
-	Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
-}
-
-var makeArray = function( array, results ) {
-	array = Array.prototype.slice.call( array, 0 );
-
-	if ( results ) {
-		results.push.apply( results, array );
-		return results;
-	}
-	
-	return array;
-};
-
-// Perform a simple check to determine if the browser is capable of
-// converting a NodeList to an array using builtin methods.
-// Also verifies that the returned array holds DOM nodes
-// (which is not the case in the Blackberry browser)
-try {
-	Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
-
-// Provide a fallback method if it does not work
-} catch( e ) {
-	makeArray = function( array, results ) {
-		var i = 0,
-			ret = results || [];
-
-		if ( toString.call(array) === "[object Array]" ) {
-			Array.prototype.push.apply( ret, array );
-
-		} else {
-			if ( typeof array.length === "number" ) {
-				for ( var l = array.length; i < l; i++ ) {
-					ret.push( array[i] );
-				}
-
-			} else {
-				for ( ; array[i]; i++ ) {
-					ret.push( array[i] );
-				}
-			}
-		}
-
-		return ret;
-	};
-}
-
-var sortOrder, siblingCheck;
-
-if ( document.documentElement.compareDocumentPosition ) {
-	sortOrder = function( a, b ) {
-		if ( a === b ) {
-			hasDuplicate = true;
-			return 0;
-		}
-
-		if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
-			return a.compareDocumentPosition ? -1 : 1;
-		}
-
-		return a.compareDocumentPosition(b) & 4 ? -1 : 1;
-	};
-
-} else {
-	sortOrder = function( a, b ) {
-		// The nodes are identical, we can exit early
-		if ( a === b ) {
-			hasDuplicate = true;
-			return 0;
-
-		// Fallback to using sourceIndex (in IE) if it's available on both nodes
-		} else if ( a.sourceIndex && b.sourceIndex ) {
-			return a.sourceIndex - b.sourceIndex;
-		}
-
-		var al, bl,
-			ap = [],
-			bp = [],
-			aup = a.parentNode,
-			bup = b.parentNode,
-			cur = aup;
-
-		// If the nodes are siblings (or identical) we can do a quick check
-		if ( aup === bup ) {
-			return siblingCheck( a, b );
-
-		// If no parents were found then the nodes are disconnected
-		} else if ( !aup ) {
-			return -1;
-
-		} else if ( !bup ) {
-			return 1;
-		}
-
-		// Otherwise they're somewhere else in the tree so we need
-		// to build up a full list of the parentNodes for comparison
-		while ( cur ) {
-			ap.unshift( cur );
-			cur = cur.parentNode;
-		}
-
-		cur = bup;
-
-		while ( cur ) {
-			bp.unshift( cur );
-			cur = cur.parentNode;
-		}
-
-		al = ap.length;
-		bl = bp.length;
-
-		// Start walking down the tree looking for a discrepancy
-		for ( var i = 0; i < al && i < bl; i++ ) {
-			if ( ap[i] !== bp[i] ) {
-				return siblingCheck( ap[i], bp[i] );
-			}
-		}
-
-		// We ended someplace up the tree so do a sibling check
-		return i === al ?
-			siblingCheck( a, bp[i], -1 ) :
-			siblingCheck( ap[i], b, 1 );
-	};
-
-	siblingCheck = function( a, b, ret ) {
-		if ( a === b ) {
-			return ret;
-		}
-
-		var cur = a.nextSibling;
-
-		while ( cur ) {
-			if ( cur === b ) {
-				return -1;
-			}
-
-			cur = cur.nextSibling;
-		}
-
-		return 1;
-	};
-}
-
-// Check to see if the browser returns elements by name when
-// querying by getElementById (and provide a workaround)
-(function(){
-	// We're going to inject a fake input element with a specified name
-	var form = document.createElement("div"),
-		id = "script" + (new Date()).getTime(),
-		root = document.documentElement;
-
-	form.innerHTML = "<a name='" + id + "'/>";
-
-	// Inject it into the root element, check its status, and remove it quickly
-	root.insertBefore( form, root.firstChild );
-
-	// The workaround has to do additional checks after a getElementById
-	// Which slows things down for other browsers (hence the branching)
-	if ( document.getElementById( id ) ) {
-		Expr.find.ID = function( match, context, isXML ) {
-			if ( typeof context.getElementById !== "undefined" && !isXML ) {
-				var m = context.getElementById(match[1]);
-
-				return m ?
-					m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
-						[m] :
-						undefined :
-					[];
-			}
-		};
-
-		Expr.filter.ID = function( elem, match ) {
-			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
-
-			return elem.nodeType === 1 && node && node.nodeValue === match;
-		};
-	}
-
-	root.removeChild( form );
-
-	// release memory in IE
-	root = form = null;
-})();
-
-(function(){
-	// Check to see if the browser returns only elements
-	// when doing getElementsByTagName("*")
-
-	// Create a fake element
-	var div = document.createElement("div");
-	div.appendChild( document.createComment("") );
-
-	// Make sure no comments are found
-	if ( div.getElementsByTagName("*").length > 0 ) {
-		Expr.find.TAG = function( match, context ) {
-			var results = context.getElementsByTagName( match[1] );
-
-			// Filter out possible comments
-			if ( match[1] === "*" ) {
-				var tmp = [];
-
-				for ( var i = 0; results[i]; i++ ) {
-					if ( results[i].nodeType === 1 ) {
-						tmp.push( results[i] );
-					}
-				}
-
-				results = tmp;
-			}
-
-			return results;
-		};
-	}
-
-	// Check to see if an attribute returns normalized href attributes
-	div.innerHTML = "<a href='#'></a>";
-
-	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
-			div.firstChild.getAttribute("href") !== "#" ) {
-
-		Expr.attrHandle.href = function( elem ) {
-			return elem.getAttribute( "href", 2 );
-		};
-	}
-
-	// release memory in IE
-	div = null;
-})();
-
-if ( document.querySelectorAll ) {
-	(function(){
-		var oldSizzle = Sizzle,
-			div = document.createElement("div"),
-			id = "__sizzle__";
-
-		div.innerHTML = "<p class='TEST'></p>";
-
-		// Safari can't handle uppercase or unicode characters when
-		// in quirks mode.
-		if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
-			return;
-		}
-	
-		Sizzle = function( query, context, extra, seed ) {
-			context = context || document;
-
-			// Only use querySelectorAll on non-XML documents
-			// (ID selectors don't work in non-HTML documents)
-			if ( !seed && !Sizzle.isXML(context) ) {
-				// See if we find a selector to speed up
-				var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
-				
-				if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
-					// Speed-up: Sizzle("TAG")
-					if ( match[1] ) {
-						return makeArray( context.getElementsByTagName( query ), extra );
-					
-					// Speed-up: Sizzle(".CLASS")
-					} else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
-						return makeArray( context.getElementsByClassName( match[2] ), extra );
-					}
-				}
-				
-				if ( context.nodeType === 9 ) {
-					// Speed-up: Sizzle("body")
-					// The body element only exists once, optimize finding it
-					if ( query === "body" && context.body ) {
-						return makeArray( [ context.body ], extra );
-						
-					// Speed-up: Sizzle("#ID")
-					} else if ( match && match[3] ) {
-						var elem = context.getElementById( match[3] );
-
-						// Check parentNode to catch when Blackberry 4.6 returns
-						// nodes that are no longer in the document #6963
-						if ( elem && elem.parentNode ) {
-							// Handle the case where IE and Opera return items
-							// by name instead of ID
-							if ( elem.id === match[3] ) {
-								return makeArray( [ elem ], extra );
-							}
-							
-						} else {
-							return makeArray( [], extra );
-						}
-					}
-					
-					try {
-						return makeArray( context.querySelectorAll(query), extra );
-					} catch(qsaError) {}
-
-				// qSA works strangely on Element-rooted queries
-				// We can work around this by specifying an extra ID on the root
-				// and working up from there (Thanks to Andrew Dupont for the technique)
-				// IE 8 doesn't work on object elements
-				} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
-					var oldContext = context,
-						old = context.getAttribute( "id" ),
-						nid = old || id,
-						hasParent = context.parentNode,
-						relativeHierarchySelector = /^\s*[+~]/.test( query );
-
-					if ( !old ) {
-						context.setAttribute( "id", nid );
-					} else {
-						nid = nid.replace( /'/g, "\\$&" );
-					}
-					if ( relativeHierarchySelector && hasParent ) {
-						context = context.parentNode;
-					}
-
-					try {
-						if ( !relativeHierarchySelector || hasParent ) {
-							return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
-						}
-
-					} catch(pseudoError) {
-					} finally {
-						if ( !old ) {
-							oldContext.removeAttribute( "id" );
-						}
-					}
-				}
-			}
-		
-			return oldSizzle(query, context, extra, seed);
-		};
-
-		for ( var prop in oldSizzle ) {
-			Sizzle[ prop ] = oldSizzle[ prop ];
-		}
-
-		// release memory in IE
-		div = null;
-	})();
-}
-
-(function(){
-	var html = document.documentElement,
-		matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
-
-	if ( matches ) {
-		// Check to see if it's possible to do matchesSelector
-		// on a disconnected node (IE 9 fails this)
-		var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
-			pseudoWorks = false;
-
-		try {
-			// This should fail with an exception
-			// Gecko does not error, returns false instead
-			matches.call( document.documentElement, "[test!='']:sizzle" );
-	
-		} catch( pseudoError ) {
-			pseudoWorks = true;
-		}
-
-		Sizzle.matchesSelector = function( node, expr ) {
-			// Make sure that attribute selectors are quoted
-			expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
-
-			if ( !Sizzle.isXML( node ) ) {
-				try { 
-					if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
-						var ret = matches.call( node, expr );
-
-						// IE 9's matchesSelector returns false on disconnected nodes
-						if ( ret || !disconnectedMatch ||
-								// As well, disconnected nodes are said to be in a document
-								// fragment in IE 9, so check for that
-								node.document && node.document.nodeType !== 11 ) {
-							return ret;
-						}
-					}
-				} catch(e) {}
-			}
-
-			return Sizzle(expr, null, null, [node]).length > 0;
-		};
-	}
-})();
-
-(function(){
-	var div = document.createElement("div");
-
-	div.innerHTML = "<div class='test e'></div><div class='test'></div>";
-
-	// Opera can't find a second classname (in 9.6)
-	// Also, make sure that getElementsByClassName actually exists
-	if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
-		return;
-	}
-
-	// Safari caches class attributes, doesn't catch changes (in 3.2)
-	div.lastChild.className = "e";
-
-	if ( div.getElementsByClassName("e").length === 1 ) {
-		return;
-	}
-	
-	Expr.order.splice(1, 0, "CLASS");
-	Expr.find.CLASS = function( match, context, isXML ) {
-		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
-			return context.getElementsByClassName(match[1]);
-		}
-	};
-
-	// release memory in IE
-	div = null;
-})();
-
-function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
-	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
-		var elem = checkSet[i];
-
-		if ( elem ) {
-			var match = false;
-
-			elem = elem[dir];
-
-			while ( elem ) {
-				if ( elem[ expando ] === doneName ) {
-					match = checkSet[elem.sizset];
-					break;
-				}
-
-				if ( elem.nodeType === 1 && !isXML ){
-					elem[ expando ] = doneName;
-					elem.sizset = i;
-				}
-
-				if ( elem.nodeName.toLowerCase() === cur ) {
-					match = elem;
-					break;
-				}
-
-				elem = elem[dir];
-			}
-
-			checkSet[i] = match;
-		}
-	}
-}
-
-function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
-	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
-		var elem = checkSet[i];
-
-		if ( elem ) {
-			var match = false;
-			
-			elem = elem[dir];
-
-			while ( elem ) {
-				if ( elem[ expando ] === doneName ) {
-					match = checkSet[elem.sizset];
-					break;
-				}
-
-				if ( elem.nodeType === 1 ) {
-					if ( !isXML ) {
-						elem[ expando ] = doneName;
-						elem.sizset = i;
-					}
-
-					if ( typeof cur !== "string" ) {
-						if ( elem === cur ) {
-							match = true;
-							break;
-						}
-
-					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
-						match = elem;
-						break;
-					}
-				}
-
-				elem = elem[dir];
-			}
-
-			checkSet[i] = match;
-		}
-	}
-}
-
-if ( document.documentElement.contains ) {
-	Sizzle.contains = function( a, b ) {
-		return a !== b && (a.contains ? a.contains(b) : true);
-	};
-
-} else if ( document.documentElement.compareDocumentPosition ) {
-	Sizzle.contains = function( a, b ) {
-		return !!(a.compareDocumentPosition(b) & 16);
-	};
-
-} else {
-	Sizzle.contains = function() {
-		return false;
-	};
-}
-
-Sizzle.isXML = function( elem ) {
-	// documentElement is verified for cases where it doesn't yet exist
-	// (such as loading iframes in IE - #4833) 
-	var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
-
-	return documentElement ? documentElement.nodeName !== "HTML" : false;
-};
-
-var posProcess = function( selector, context, seed ) {
-	var match,
-		tmpSet = [],
-		later = "",
-		root = context.nodeType ? [context] : context;
-
-	// Position selectors must be done after the filter
-	// And so must :not(positional) so we move all PSEUDOs to the end
-	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
-		later += match[0];
-		selector = selector.replace( Expr.match.PSEUDO, "" );
-	}
-
-	selector = Expr.relative[selector] ? selector + "*" : selector;
-
-	for ( var i = 0, l = root.length; i < l; i++ ) {
-		Sizzle( selector, root[i], tmpSet, seed );
-	}
-
-	return Sizzle.filter( later, tmpSet );
-};
-
-// EXPOSE
-// Override sizzle attribute retrieval
-Sizzle.attr = jQuery.attr;
-Sizzle.selectors.attrMap = {};
-jQuery.find = Sizzle;
-jQuery.expr = Sizzle.selectors;
-jQuery.expr[":"] = jQuery.expr.filters;
-jQuery.unique = Sizzle.uniqueSort;
-jQuery.text = Sizzle.getText;
-jQuery.isXMLDoc = Sizzle.isXML;
-jQuery.contains = Sizzle.contains;
-
-
-})();
-
-
-var runtil = /Until$/,
-	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
-	// Note: This RegExp should be improved, or likely pulled from Sizzle
-	rmultiselector = /,/,
-	isSimple = /^.[^:#\[\.,]*$/,
-	slice = Array.prototype.slice,
-	POS = jQuery.expr.match.POS,
-	// methods guaranteed to produce a unique set when starting from a unique set
-	guaranteedUnique = {
-		children: true,
-		contents: true,
-		next: true,
-		prev: true
-	};
-
-jQuery.fn.extend({
-	find: function( selector ) {
-		var self = this,
-			i, l;
-
-		if ( typeof selector !== "string" ) {
-			return jQuery( selector ).filter(function() {
-				for ( i = 0, l = self.length; i < l; i++ ) {
-					if ( jQuery.contains( self[ i ], this ) ) {
-						return true;
-					}
-				}
-			});
-		}
-
-		var ret = this.pushStack( "", "find", selector ),
-			length, n, r;
-
-		for ( i = 0, l = this.length; i < l; i++ ) {
-			length = ret.length;
-			jQuery.find( selector, this[i], ret );
-
-			if ( i > 0 ) {
-				// Make sure that the results are unique
-				for ( n = length; n < ret.length; n++ ) {
-					for ( r = 0; r < length; r++ ) {
-						if ( ret[r] === ret[n] ) {
-							ret.splice(n--, 1);
-							break;
-						}
-					}
-				}
-			}
-		}
-
-		return ret;
-	},
-
-	has: function( target ) {
-		var targets = jQuery( target );
-		return this.filter(function() {
-			for ( var i = 0, l = targets.length; i < l; i++ ) {
-				if ( jQuery.contains( this, targets[i] ) ) {
-					return true;
-				}
-			}
-		});
-	},
-
-	not: function( selector ) {
-		return this.pushStack( winnow(this, selector, false), "not", selector);
-	},
-
-	filter: function( selector ) {
-		return this.pushStack( winnow(this, selector, true), "filter", selector );
-	},
-
-	is: function( selector ) {
-		return !!selector && ( 
-			typeof selector === "string" ?
-				// If this is a positional selector, check membership in the returned set
-				// so $("p:first").is("p:last") won't return true for a doc with two "p".
-				POS.test( selector ) ? 
-					jQuery( selector, this.context ).index( this[0] ) >= 0 :
-					jQuery.filter( selector, this ).length > 0 :
-				this.filter( selector ).length > 0 );
-	},
-
-	closest: function( selectors, context ) {
-		var ret = [], i, l, cur = this[0];
-		
-		// Array (deprecated as of jQuery 1.7)
-		if ( jQuery.isArray( selectors ) ) {
-			var level = 1;
-
-			while ( cur && cur.ownerDocument && cur !== context ) {
-				for ( i = 0; i < selectors.length; i++ ) {
-
-					if ( jQuery( cur ).is( selectors[ i ] ) ) {
-						ret.push({ selector: selectors[ i ], elem: cur, level: level });
-					}
-				}
-
-				cur = cur.parentNode;
-				level++;
-			}
-
-			return ret;
-		}
-
-		// String
-		var pos = POS.test( selectors ) || typeof selectors !== "string" ?
-				jQuery( selectors, context || this.context ) :
-				0;
-
-		for ( i = 0, l = this.length; i < l; i++ ) {
-			cur = this[i];
-
-			while ( cur ) {
-				if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
-					ret.push( cur );
-					break;
-
-				} else {
-					cur = cur.parentNode;
-					if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
-						break;
-					}
-				}
-			}
-		}
-
-		ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
-
-		return this.pushStack( ret, "closest", selectors );
-	},
-
-	// Determine the position of an element within
-	// the matched set of elements
-	index: function( elem ) {
-
-		// No argument, return index in parent
-		if ( !elem ) {
-			return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
-		}
-
-		// index in selector
-		if ( typeof elem === "string" ) {
-			return jQuery.inArray( this[0], jQuery( elem ) );
-		}
-
-		// Locate the position of the desired element
-		return jQuery.inArray(
-			// If it receives a jQuery object, the first element is used
-			elem.jquery ? elem[0] : elem, this );
-	},
-
-	add: function( selector, context ) {
-		var set = typeof selector === "string" ?
-				jQuery( selector, context ) :
-				jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
-			all = jQuery.merge( this.get(), set );
-
-		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
-			all :
-			jQuery.unique( all ) );
-	},
-
-	andSelf: function() {
-		return this.add( this.prevObject );
-	}
-});
-
-// A painfully simple check to see if an element is disconnected
-// from a document (should be improved, where feasible).
-function isDisconnected( node ) {
-	return !node || !node.parentNode || node.parentNode.nodeType === 11;
-}
-
-jQuery.each({
-	parent: function( elem ) {
-		var parent = elem.parentNode;
-		return parent && parent.nodeType !== 11 ? parent : null;
-	},
-	parents: function( elem ) {
-		return jQuery.dir( elem, "parentNode" );
-	},
-	parentsUntil: function( elem, i, until ) {
-		return jQuery.dir( elem, "parentNode", until );
-	},
-	next: function( elem ) {
-		return jQuery.nth( elem, 2, "nextSibling" );
-	},
-	prev: function( elem ) {
-		return jQuery.nth( elem, 2, "previousSibling" );
-	},
-	nextAll: function( elem ) {
-		return jQuery.dir( elem, "nextSibling" );
-	},
-	prevAll: function( elem ) {
-		return jQuery.dir( elem, "previousSibling" );
-	},
-	nextUntil: function( elem, i, until ) {
-		return jQuery.dir( elem, "nextSibling", until );
-	},
-	prevUntil: function( elem, i, until ) {
-		return jQuery.dir( elem, "previousSibling", until );
-	},
-	siblings: function( elem ) {
-		return jQuery.sibling( elem.parentNode.firstChild, elem );
-	},
-	children: function( elem ) {
-		return jQuery.sibling( elem.firstChild );
-	},
-	contents: function( elem ) {
-		return jQuery.nodeName( elem, "iframe" ) ?
-			elem.contentDocument || elem.contentWindow.document :
-			jQuery.makeArray( elem.childNodes );
-	}
-}, function( name, fn ) {
-	jQuery.fn[ name ] = function( until, selector ) {
-		var ret = jQuery.map( this, fn, until );
-
-		if ( !runtil.test( name ) ) {
-			selector = until;
-		}
-
-		if ( selector && typeof selector === "string" ) {
-			ret = jQuery.filter( selector, ret );
-		}
-
-		ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
-		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
-			ret = ret.reverse();
-		}
-
-		return this.pushStack( ret, name, slice.call( arguments ).join(",") );
-	};
-});
-
-jQuery.extend({
-	filter: function( expr, elems, not ) {
-		if ( not ) {
-			expr = ":not(" + expr + ")";
-		}
-
-		return elems.length === 1 ?
-			jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
-			jQuery.find.matches(expr, elems);
-	},
-
-	dir: function( elem, dir, until ) {
-		var matched = [],
-			cur = elem[ dir ];
-
-		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
-			if ( cur.nodeType === 1 ) {
-				matched.push( cur );
-			}
-			cur = cur[dir];
-		}
-		return matched;
-	},
-
-	nth: function( cur, result, dir, elem ) {
-		result = result || 1;
-		var num = 0;
-
-		for ( ; cur; cur = cur[dir] ) {
-			if ( cur.nodeType === 1 && ++num === result ) {
-				break;
-			}
-		}
-
-		return cur;
-	},
-
-	sibling: function( n, elem ) {
-		var r = [];
-
-		for ( ; n; n = n.nextSibling ) {
-			if ( n.nodeType === 1 && n !== elem ) {
-				r.push( n );
-			}
-		}
-
-		return r;
-	}
-});
-
-// Implement the identical functionality for filter and not
-function winnow( elements, qualifier, keep ) {
-
-	// Can't pass null or undefined to indexOf in Firefox 4
-	// Set to 0 to skip string check
-	qualifier = qualifier || 0;
-
-	if ( jQuery.isFunction( qualifier ) ) {
-		return jQuery.grep(elements, function( elem, i ) {
-			var retVal = !!qualifier.call( elem, i, elem );
-			return retVal === keep;
-		});
-
-	} else if ( qualifier.nodeType ) {
-		return jQuery.grep(elements, function( elem, i ) {
-			return ( elem === qualifier ) === keep;
-		});
-
-	} else if ( typeof qualifier === "string" ) {
-		var filtered = jQuery.grep(elements, function( elem ) {
-			return elem.nodeType === 1;
-		});
-
-		if ( isSimple.test( qualifier ) ) {
-			return jQuery.filter(qualifier, filtered, !keep);
-		} else {
-			qualifier = jQuery.filter( qualifier, filtered );
-		}
-	}
-
-	return jQuery.grep(elements, function( elem, i ) {
-		return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
-	});
-}
-
-
-
-
-function createSafeFragment( document ) {
-	var list = nodeNames.split( "|" ),
-	safeFrag = document.createDocumentFragment();
-
-	if ( safeFrag.createElement ) {
-		while ( list.length ) {
-			safeFrag.createElement(
-				list.pop()
-			);
-		}
-	}
-	return safeFrag;
-}
-
-var nodeNames = "abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|" +
-		"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
-	rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
-	rleadingWhitespace = /^\s+/,
-	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
-	rtagName = /<([\w:]+)/,
-	rtbody = /<tbody/i,
-	rhtml = /<|&#?\w+;/,
-	rnoInnerhtml = /<(?:script|style)/i,
-	rnocache = /<(?:script|object|embed|option|style)/i,
-	rnoshimcache = new RegExp("<(?:" + nodeNames + ")", "i"),
-	// checked="checked" or checked
-	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
-	rscriptType = /\/(java|ecma)script/i,
-	rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
-	wrapMap = {
-		option: [ 1, "<select multiple='multiple'>", "</select>" ],
-		legend: [ 1, "<fieldset>", "</fieldset>" ],
-		thead: [ 1, "<table>", "</table>" ],
-		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
-		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
-		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
-		area: [ 1, "<map>", "</map>" ],
-		_default: [ 0, "", "" ]
-	},
-	safeFragment = createSafeFragment( document );
-
-wrapMap.optgroup = wrapMap.option;
-wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
-wrapMap.th = wrapMap.td;
-
-// IE can't serialize <link> and <script> tags normally
-if ( !jQuery.support.htmlSerialize ) {
-	wrapMap._default = [ 1, "div<div>", "</div>" ];
-}
-
-jQuery.fn.extend({
-	text: function( text ) {
-		if ( jQuery.isFunction(text) ) {
-			return this.each(function(i) {
-				var self = jQuery( this );
-
-				self.text( text.call(this, i, self.text()) );
-			});
-		}
-
-		if ( typeof text !== "object" && text !== undefined ) {
-			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
-		}
-
-		return jQuery.text( this );
-	},
-
-	wrapAll: function( html ) {
-		if ( jQuery.isFunction( html ) ) {
-			return this.each(function(i) {
-				jQuery(this).wrapAll( html.call(this, i) );
-			});
-		}
-
-		if ( this[0] ) {
-			// The elements to wrap the target around
-			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
-
-			if ( this[0].parentNode ) {
-				wrap.insertBefore( this[0] );
-			}
-
-			wrap.map(function() {
-				var elem = this;
-
-				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
-					elem = elem.firstChild;
-				}
-
-				return elem;
-			}).append( this );
-		}
-
-		return this;
-	},
-
-	wrapInner: function( html ) {
-		if ( jQuery.isFunction( html ) ) {
-			return this.each(function(i) {
-				jQuery(this).wrapInner( html.call(this, i) );
-			});
-		}
-
-		return this.each(function() {
-			var self = jQuery( this ),
-				contents = self.contents();
-
-			if ( contents.length ) {
-				contents.wrapAll( html );
-
-			} else {
-				self.append( html );
-			}
-		});
-	},
-
-	wrap: function( html ) {
-		var isFunction = jQuery.isFunction( html );
-
-		return this.each(function(i) {
-			jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
-		});
-	},
-
-	unwrap: function() {
-		return this.parent().each(function() {
-			if ( !jQuery.nodeName( this, "body" ) ) {
-				jQuery( this ).replaceWith( this.childNodes );
-			}
-		}).end();
-	},
-
-	append: function() {
-		return this.domManip(arguments, true, function( elem ) {
-			if ( this.nodeType === 1 ) {
-				this.appendChild( elem );
-			}
-		});
-	},
-
-	prepend: function() {
-		return this.domManip(arguments, true, function( elem ) {
-			if ( this.nodeType === 1 ) {
-				this.insertBefore( elem, this.firstChild );
-			}
-		});
-	},
-
-	before: function() {
-		if ( this[0] && this[0].parentNode ) {
-			return this.domManip(arguments, false, function( elem ) {
-				this.parentNode.insertBefore( elem, this );
-			});
-		} else if ( arguments.length ) {
-			var set = jQuery.clean( arguments );
-			set.push.apply( set, this.toArray() );
-			return this.pushStack( set, "before", arguments );
-		}
-	},
-
-	after: function() {
-		if ( this[0] && this[0].parentNode ) {
-			return this.domManip(arguments, false, function( elem ) {
-				this.parentNode.insertBefore( elem, this.nextSibling );
-			});
-		} else if ( arguments.length ) {
-			var set = this.pushStack( this, "after", arguments );
-			set.push.apply( set, jQuery.clean(arguments) );
-			return set;
-		}
-	},
-
-	// keepData is for internal use only--do not document
-	remove: function( selector, keepData ) {
-		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
-			if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
-				if ( !keepData && elem.nodeType === 1 ) {
-					jQuery.cleanData( elem.getElementsByTagName("*") );
-					jQuery.cleanData( [ elem ] );
-				}
-
-				if ( elem.parentNode ) {
-					elem.parentNode.removeChild( elem );
-				}
-			}
-		}
-
-		return this;
-	},
-
-	empty: function() {
-		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
-			// Remove element nodes and prevent memory leaks
-			if ( elem.nodeType === 1 ) {
-				jQuery.cleanData( elem.getElementsByTagName("*") );
-			}
-
-			// Remove any remaining nodes
-			while ( elem.firstChild ) {
-				elem.removeChild( elem.firstChild );
-			}
-		}
-
-		return this;
-	},
-
-	clone: function( dataAndEvents, deepDataAndEvents ) {
-		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
-		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
-
-		return this.map( function () {
-			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
-		});
-	},
-
-	html: function( value ) {
-		if ( value === undefined ) {
-			return this[0] && this[0].nodeType === 1 ?
-				this[0].innerHTML.replace(rinlinejQuery, "") :
-				null;
-
-		// See if we can take a shortcut and just use innerHTML
-		} else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
-			(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
-			!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
-
-			value = value.replace(rxhtmlTag, "<$1></$2>");
-
-			try {
-				for ( var i = 0, l = this.length; i < l; i++ ) {
-					// Remove element nodes and prevent memory leaks
-					if ( this[i].nodeType === 1 ) {
-						jQuery.cleanData( this[i].getElementsByTagName("*") );
-						this[i].innerHTML = value;
-					}
-				}
-
-			// If using innerHTML throws an exception, use the fallback method
-			} catch(e) {
-				this.empty().append( value );
-			}
-
-		} else if ( jQuery.isFunction( value ) ) {
-			this.each(function(i){
-				var self = jQuery( this );
-
-				self.html( value.call(this, i, self.html()) );
-			});
-
-		} else {
-			this.empty().append( value );
-		}
-
-		return this;
-	},
-
-	replaceWith: function( value ) {
-		if ( this[0] && this[0].parentNode ) {
-			// Make sure that the elements are removed from the DOM before they are inserted
-			// this can help fix replacing a parent with child elements
-			if ( jQuery.isFunction( value ) ) {
-				return this.each(function(i) {
-					var self = jQuery(this), old = self.html();
-					self.replaceWith( value.call( this, i, old ) );
-				});
-			}
-
-			if ( typeof value !== "string" ) {
-				value = jQuery( value ).detach();
-			}
-
-			return this.each(function() {
-				var next = this.nextSibling,
-					parent = this.parentNode;
-
-				jQuery( this ).remove();
-
-				if ( next ) {
-					jQuery(next).before( value );
-				} else {
-					jQuery(parent).append( value );
-				}
-			});
-		} else {
-			return this.length ?
-				this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
-				this;
-		}
-	},
-
-	detach: function( selector ) {
-		return this.remove( selector, true );
-	},
-
-	domManip: function( args, table, callback ) {
-		var results, first, fragment, parent,
-			value = args[0],
-			scripts = [];
-
-		// We can't cloneNode fragments that contain checked, in WebKit
-		if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
-			return this.each(function() {
-				jQuery(this).domManip( args, table, callback, true );
-			});
-		}
-
-		if ( jQuery.isFunction(value) ) {
-			return this.each(function(i) {
-				var self = jQuery(this);
-				args[0] = value.call(this, i, table ? self.html() : undefined);
-				self.domManip( args, table, callback );
-			});
-		}
-
-		if ( this[0] ) {
-			parent = value && value.parentNode;
-
-			// If we're in a fragment, just use that instead of building a new one
-			if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
-				results = { fragment: parent };
-
-			} else {
-				results = jQuery.buildFragment( args, this, scripts );
-			}
-
-			fragment = results.fragment;
-
-			if ( fragment.childNodes.length === 1 ) {
-				first = fragment = fragment.firstChild;
-			} else {
-				first = fragment.firstChild;
-			}
-
-			if ( first ) {
-				table = table && jQuery.nodeName( first, "tr" );
-
-				for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
-					callback.call(
-						table ?
-							root(this[i], first) :
-							this[i],
-						// Make sure that we do not leak memory by inadvertently discarding
-						// the original fragment (which might have attached data) instead of
-						// using it; in addition, use the original fragment object for the last
-						// item instead of first because it can end up being emptied incorrectly
-						// in certain situations (Bug #8070).
-						// Fragments from the fragment cache must always be cloned and never used
-						// in place.
-						results.cacheable || ( l > 1 && i < lastIndex ) ?
-							jQuery.clone( fragment, true, true ) :
-							fragment
-					);
-				}
-			}
-
-			if ( scripts.length ) {
-				jQuery.each( scripts, evalScript );
-			}
-		}
-
-		return this;
-	}
-});
-
-function root( elem, cur ) {
-	return jQuery.nodeName(elem, "table") ?
-		(elem.getElementsByTagName("tbody")[0] ||
-		elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
-		elem;
-}
-
-function cloneCopyEvent( src, dest ) {
-
-	if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
-		return;
-	}
-
-	var type, i, l,
-		oldData = jQuery._data( src ),
-		curData = jQuery._data( dest, oldData ),
-		events = oldData.events;
-
-	if ( events ) {
-		delete curData.handle;
-		curData.events = {};
-
-		for ( type in events ) {
-			for ( i = 0, l = events[ type ].length; i < l; i++ ) {
-				jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
-			}
-		}
-	}
-
-	// make the cloned public data object a copy from the original
-	if ( curData.data ) {
-		curData.data = jQuery.extend( {}, curData.data );
-	}
-}
-
-function cloneFixAttributes( src, dest ) {
-	var nodeName;
-
-	// We do not need to do anything for non-Elements
-	if ( dest.nodeType !== 1 ) {
-		return;
-	}
-
-	// clearAttributes removes the attributes, which we don't want,
-	// but also removes the attachEvent events, which we *do* want
-	if ( dest.clearAttributes ) {
-		dest.clearAttributes();
-	}
-
-	// mergeAttributes, in contrast, only merges back on the
-	// original attributes, not the events
-	if ( dest.mergeAttributes ) {
-		dest.mergeAttributes( src );
-	}
-
-	nodeName = dest.nodeName.toLowerCase();
-
-	// IE6-8 fail to clone children inside object elements that use
-	// the proprietary classid attribute value (rather than the type
-	// attribute) to identify the type of content to display
-	if ( nodeName === "object" ) {
-		dest.outerHTML = src.outerHTML;
-
-	} else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
-		// IE6-8 fails to persist the checked state of a cloned checkbox
-		// or radio button. Worse, IE6-7 fail to give the cloned element
-		// a checked appearance if the defaultChecked value isn't also set
-		if ( src.checked ) {
-			dest.defaultChecked = dest.checked = src.checked;
-		}
-
-		// IE6-7 get confused and end up setting the value of a cloned
-		// checkbox/radio button to an empty string instead of "on"
-		if ( dest.value !== src.value ) {
-			dest.value = src.value;
-		}
-
-	// IE6-8 fails to return the selected option to the default selected
-	// state when cloning options
-	} else if ( nodeName === "option" ) {
-		dest.selected = src.defaultSelected;
-
-	// IE6-8 fails to set the defaultValue to the correct value when
-	// cloning other types of input fields
-	} else if ( nodeName === "input" || nodeName === "textarea" ) {
-		dest.defaultValue = src.defaultValue;
-	}
-
-	// Event data gets referenced instead of copied if the expando
-	// gets copied too
-	dest.removeAttribute( jQuery.expando );
-}
-
-jQuery.buildFragment = function( args, nodes, scripts ) {
-	var fragment, cacheable, cacheresults, doc,
-	first = args[ 0 ];
-
-	// nodes may contain either an explicit document object,
-	// a jQuery collection or context object.
-	// If nodes[0] contains a valid object to assign to doc
-	if ( nodes && nodes[0] ) {
-		doc = nodes[0].ownerDocument || nodes[0];
-	}
-
-	// Ensure that an attr object doesn't incorrectly stand in as a document object
-	// Chrome and Firefox seem to allow this to occur and will throw exception
-	// Fixes #8950
-	if ( !doc.createDocumentFragment ) {
-		doc = document;
-	}
-
-	// Only cache "small" (1/2 KB) HTML strings that are associated with the main document
-	// Cloning options loses the selected state, so don't cache them
-	// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
-	// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
-	// Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
-	if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
-		first.charAt(0) === "<" && !rnocache.test( first ) &&
-		(jQuery.support.checkClone || !rchecked.test( first )) &&
-		(jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
-
-		cacheable = true;
-
-		cacheresults = jQuery.fragments[ first ];
-		if ( cacheresults && cacheresults !== 1 ) {
-			fragment = cacheresults;
-		}
-	}
-
-	if ( !fragment ) {
-		fragment = doc.createDocumentFragment();
-		jQuery.clean( args, doc, fragment, scripts );
-	}
-
-	if ( cacheable ) {
-		jQuery.fragments[ first ] = cacheresults ? fragment : 1;
-	}
-
-	return { fragment: fragment, cacheable: cacheable };
-};
-
-jQuery.fragments = {};
-
-jQuery.each({
-	appendTo: "append",
-	prependTo: "prepend",
-	insertBefore: "before",
-	insertAfter: "after",
-	replaceAll: "replaceWith"
-}, function( name, original ) {
-	jQuery.fn[ name ] = function( selector ) {
-		var ret = [],
-			insert = jQuery( selector ),
-			parent = this.length === 1 && this[0].parentNode;
-
-		if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
-			insert[ original ]( this[0] );
-			return this;
-
-		} else {
-			for ( var i = 0, l = insert.length; i < l; i++ ) {
-				var elems = ( i > 0 ? this.clone(true) : this ).get();
-				jQuery( insert[i] )[ original ]( elems );
-				ret = ret.concat( elems );
-			}
-
-			return this.pushStack( ret, name, insert.selector );
-		}
-	};
-});
-
-function getAll( elem ) {
-	if ( typeof elem.getElementsByTagName !== "undefined" ) {
-		return elem.getElementsByTagName( "*" );
-
-	} else if ( typeof elem.querySelectorAll !== "undefined" ) {
-		return elem.querySelectorAll( "*" );
-
-	} else {
-		return [];
-	}
-}
-
-// Used in clean, fixes the defaultChecked property
-function fixDefaultChecked( elem ) {
-	if ( elem.type === "checkbox" || elem.type === "radio" ) {
-		elem.defaultChecked = elem.checked;
-	}
-}
-// Finds all inputs and passes them to fixDefaultChecked
-function findInputs( elem ) {
-	var nodeName = ( elem.nodeName || "" ).toLowerCase();
-	if ( nodeName === "input" ) {
-		fixDefaultChecked( elem );
-	// Skip scripts, get other children
-	} else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) {
-		jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
-	}
-}
-
-// Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js
-function shimCloneNode( elem ) {
-	var div = document.createElement( "div" );
-	safeFragment.appendChild( div );
-
-	div.innerHTML = elem.outerHTML;
-	return div.firstChild;
-}
-
-jQuery.extend({
-	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
-		var srcElements,
-			destElements,
-			i,
-			// IE<=8 does not properly clone detached, unknown element nodes
-			clone = jQuery.support.html5Clone || !rnoshimcache.test( "<" + elem.nodeName ) ?
-				elem.cloneNode( true ) :
-				shimCloneNode( elem );
-
-		if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
-				(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
-			// IE copies events bound via attachEvent when using cloneNode.
-			// Calling detachEvent on the clone will also remove the events
-			// from the original. In order to get around this, we use some
-			// proprietary methods to clear the events. Thanks to MooTools
-			// guys for this hotness.
-
-			cloneFixAttributes( elem, clone );
-
-			// Using Sizzle here is crazy slow, so we use getElementsByTagName instead
-			srcElements = getAll( elem );
-			destElements = getAll( clone );
-
-			// Weird iteration because IE will replace the length property
-			// with an element if you are cloning the body and one of the
-			// elements on the page has a name or id of "length"
-			for ( i = 0; srcElements[i]; ++i ) {
-				// Ensure that the destination node is not null; Fixes #9587
-				if ( destElements[i] ) {
-					cloneFixAttributes( srcElements[i], destElements[i] );
-				}
-			}
-		}
-
-		// Copy the events from the original to the clone
-		if ( dataAndEvents ) {
-			cloneCopyEvent( elem, clone );
-
-			if ( deepDataAndEvents ) {
-				srcElements = getAll( elem );
-				destElements = getAll( clone );
-
-				for ( i = 0; srcElements[i]; ++i ) {
-					cloneCopyEvent( srcElements[i], destElements[i] );
-				}
-			}
-		}
-
-		srcElements = destElements = null;
-
-		// Return the cloned set
-		return clone;
-	},
-
-	clean: function( elems, context, fragment, scripts ) {
-		var checkScriptType;
-
-		context = context || document;
-
-		// !context.createElement fails in IE with an error but returns typeof 'object'
-		if ( typeof context.createElement === "undefined" ) {
-			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
-		}
-
-		var ret = [], j;
-
-		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
-			if ( typeof elem === "number" ) {
-				elem += "";
-			}
-
-			if ( !elem ) {
-				continue;
-			}
-
-			// Convert html string into DOM nodes
-			if ( typeof elem === "string" ) {
-				if ( !rhtml.test( elem ) ) {
-					elem = context.createTextNode( elem );
-				} else {
-					// Fix "XHTML"-style tags in all browsers
-					elem = elem.replace(rxhtmlTag, "<$1></$2>");
-
-					// Trim whitespace, otherwise indexOf won't work as expected
-					var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
-						wrap = wrapMap[ tag ] || wrapMap._default,
-						depth = wrap[0],
-						div = context.createElement("div");
-
-					// Append wrapper element to unknown element safe doc fragment
-					if ( context === document ) {
-						// Use the fragment we've already created for this document
-						safeFragment.appendChild( div );
-					} else {
-						// Use a fragment created with the owner document
-						createSafeFragment( context ).appendChild( div );
-					}
-
-					// Go to html and back, then peel off extra wrappers
-					div.innerHTML = wrap[1] + elem + wrap[2];
-
-					// Move to the right depth
-					while ( depth-- ) {
-						div = div.lastChild;
-					}
-
-					// Remove IE's autoinserted <tbody> from table fragments
-					if ( !jQuery.support.tbody ) {
-
-						// String was a <table>, *may* have spurious <tbody>
-						var hasBody = rtbody.test(elem),
-							tbody = tag === "table" && !hasBody ?
-								div.firstChild && div.firstChild.childNodes :
-
-								// String was a bare <thead> or <tfoot>
-								wrap[1] === "<table>" && !hasBody ?
-									div.childNodes :
-									[];
-
-						for ( j = tbody.length - 1; j >= 0 ; --j ) {
-							if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
-								tbody[ j ].parentNode.removeChild( tbody[ j ] );
-							}
-						}
-					}
-
-					// IE completely kills leading whitespace when innerHTML is used
-					if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
-						div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
-					}
-
-					elem = div.childNodes;
-				}
-			}
-
-			// Resets defaultChecked for any radios and checkboxes
-			// about to be appended to the DOM in IE 6/7 (#8060)
-			var len;
-			if ( !jQuery.support.appendChecked ) {
-				if ( elem[0] && typeof (len = elem.length) === "number" ) {
-					for ( j = 0; j < len; j++ ) {
-						findInputs( elem[j] );
-					}
-				} else {
-					findInputs( elem );
-				}
-			}
-
-			if ( elem.nodeType ) {
-				ret.push( elem );
-			} else {
-				ret = jQuery.merge( ret, elem );
-			}
-		}
-
-		if ( fragment ) {
-			checkScriptType = function( elem ) {
-				return !elem.type || rscriptType.test( elem.type );
-			};
-			for ( i = 0; ret[i]; i++ ) {
-				if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
-					scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
-
-				} else {
-					if ( ret[i].nodeType === 1 ) {
-						var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );
-
-						ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
-					}
-					fragment.appendChild( ret[i] );
-				}
-			}
-		}
-
-		return ret;
-	},
-
-	cleanData: function( elems ) {
-		var data, id,
-			cache = jQuery.cache,
-			special = jQuery.event.special,
-			deleteExpando = jQuery.support.deleteExpando;
-
-		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
-			if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
-				continue;
-			}
-
-			id = elem[ jQuery.expando ];
-
-			if ( id ) {
-				data = cache[ id ];
-
-				if ( data && data.events ) {
-					for ( var type in data.events ) {
-						if ( special[ type ] ) {
-							jQuery.event.remove( elem, type );
-
-						// This is a shortcut to avoid jQuery.event.remove's overhead
-						} else {
-							jQuery.removeEvent( elem, type, data.handle );
-						}
-					}
-
-					// Null the DOM reference to avoid IE6/7/8 leak (#7054)
-					if ( data.handle ) {
-						data.handle.elem = null;
-					}
-				}
-
-				if ( deleteExpando ) {
-					delete elem[ jQuery.expando ];
-
-				} else if ( elem.removeAttribute ) {
-					elem.removeAttribute( jQuery.expando );
-				}
-
-				delete cache[ id ];
-			}
-		}
-	}
-});
-
-function evalScript( i, elem ) {
-	if ( elem.src ) {
-		jQuery.ajax({
-			url: elem.src,
-			async: false,
-			dataType: "script"
-		});
-	} else {
-		jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
-	}
-
-	if ( elem.parentNode ) {
-		elem.parentNode.removeChild( elem );
-	}
-}
-
-
-
-
-var ralpha = /alpha\([^)]*\)/i,
-	ropacity = /opacity=([^)]*)/,
-	// fixed for IE9, see #8346
-	rupper = /([A-Z]|^ms)/g,
-	rnumpx = /^-?\d+(?:px)?$/i,
-	rnum = /^-?\d/,
-	rrelNum = /^([\-+])=([\-+.\de]+)/,
-
-	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
-	cssWidth = [ "Left", "Right" ],
-	cssHeight = [ "Top", "Bottom" ],
-	curCSS,
-
-	getComputedStyle,
-	currentStyle;
-
-jQuery.fn.css = function( name, value ) {
-	// Setting 'undefined' is a no-op
-	if ( arguments.length === 2 && value === undefined ) {
-		return this;
-	}
-
-	return jQuery.access( this, name, value, true, function( elem, name, value ) {
-		return value !== undefined ?
-			jQuery.style( elem, name, value ) :
-			jQuery.css( elem, name );
-	});
-};
-
-jQuery.extend({
-	// Add in style property hooks for overriding the default
-	// behavior of getting and setting a style property
-	cssHooks: {
-		opacity: {
-			get: function( elem, computed ) {
-				if ( computed ) {
-					// We should always get a number back from opacity
-					var ret = curCSS( elem, "opacity", "opacity" );
-					return ret === "" ? "1" : ret;
-
-				} else {
-					return elem.style.opacity;
-				}
-			}
-		}
-	},
-
-	// Exclude the following css properties to add px
-	cssNumber: {
-		"fillOpacity": true,
-		"fontWeight": true,
-		"lineHeight": true,
-		"opacity": true,
-		"orphans": true,
-		"widows": true,
-		"zIndex": true,
-		"zoom": true
-	},
-
-	// Add in properties whose names you wish to fix before
-	// setting or getting the value
-	cssProps: {
-		// normalize float css property
-		"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
-	},
-
-	// Get and set the style property on a DOM Node
-	style: function( elem, name, value, extra ) {
-		// Don't set styles on text and comment nodes
-		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
-			return;
-		}
-
-		// Make sure that we're working with the right name
-		var ret, type, origName = jQuery.camelCase( name ),
-			style = elem.style, hooks = jQuery.cssHooks[ origName ];
-
-		name = jQuery.cssProps[ origName ] || origName;
-
-		// Check if we're setting a value
-		if ( value !== undefined ) {
-			type = typeof value;
-
-			// convert relative number strings (+= or -=) to relative numbers. #7345
-			if ( type === "string" && (ret = rrelNum.exec( value )) ) {
-				value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
-				// Fixes bug #9237
-				type = "number";
-			}
-
-			// Make sure that NaN and null values aren't set. See: #7116
-			if ( value == null || type === "number" && isNaN( value ) ) {
-				return;
-			}
-
-			// If a number was passed in, add 'px' to the (except for certain CSS properties)
-			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
-				value += "px";
-			}
-
-			// If a hook was provided, use that value, otherwise just set the specified value
-			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
-				// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
-				// Fixes bug #5509
-				try {
-					style[ name ] = value;
-				} catch(e) {}
-			}
-
-		} else {
-			// If a hook was provided get the non-computed value from there
-			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
-				return ret;
-			}
-
-			// Otherwise just get the value from the style object
-			return style[ name ];
-		}
-	},
-
-	css: function( elem, name, extra ) {
-		var ret, hooks;
-
-		// Make sure that we're working with the right name
-		name = jQuery.camelCase( name );
-		hooks = jQuery.cssHooks[ name ];
-		name = jQuery.cssProps[ name ] || name;
-
-		// cssFloat needs a special treatment
-		if ( name === "cssFloat" ) {
-			name = "float";
-		}
-
-		// If a hook was provided get the computed value from there
-		if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
-			return ret;
-
-		// Otherwise, if a way to get the computed value exists, use that
-		} else if ( curCSS ) {
-			return curCSS( elem, name );
-		}
-	},
-
-	// A method for quickly swapping in/out CSS properties to get correct calculations
-	swap: function( elem, options, callback ) {
-		var old = {};
-
-		// Remember the old values, and insert the new ones
-		for ( var name in options ) {
-			old[ name ] = elem.style[ name ];
-			elem.style[ name ] = options[ name ];
-		}
-
-		callback.call( elem );
-
-		// Revert the old values
-		for ( name in options ) {
-			elem.style[ name ] = old[ name ];
-		}
-	}
-});
-
-// DEPRECATED, Use jQuery.css() instead
-jQuery.curCSS = jQuery.css;
-
-jQuery.each(["height", "width"], function( i, name ) {
-	jQuery.cssHooks[ name ] = {
-		get: function( elem, computed, extra ) {
-			var val;
-
-			if ( computed ) {
-				if ( elem.offsetWidth !== 0 ) {
-					return getWH( elem, name, extra );
-				} else {
-					jQuery.swap( elem, cssShow, function() {
-						val = getWH( elem, name, extra );
-					});
-				}
-
-				return val;
-			}
-		},
-
-		set: function( elem, value ) {
-			if ( rnumpx.test( value ) ) {
-				// ignore negative width and height values #1599
-				value = parseFloat( value );
-
-				if ( value >= 0 ) {
-					return value + "px";
-				}
-
-			} else {
-				return value;
-			}
-		}
-	};
-});
-
-if ( !jQuery.support.opacity ) {
-	jQuery.cssHooks.opacity = {
-		get: function( elem, computed ) {
-			// IE uses filters for opacity
-			return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
-				( parseFloat( RegExp.$1 ) / 100 ) + "" :
-				computed ? "1" : "";
-		},
-
-		set: function( elem, value ) {
-			var style = elem.style,
-				currentStyle = elem.currentStyle,
-				opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
-				filter = currentStyle && currentStyle.filter || style.filter || "";
-
-			// IE has trouble with opacity if it does not have layout
-			// Force it by setting the zoom level
-			style.zoom = 1;
-
-			// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
-			if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
-
-				// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
-				// if "filter:" is present at all, clearType is disabled, we want to avoid this
-				// style.removeAttribute is IE Only, but so apparently is this code path...
-				style.removeAttribute( "filter" );
-
-				// if there there is no filter style applied in a css rule, we are done
-				if ( currentStyle && !currentStyle.filter ) {
-					return;
-				}
-			}
-
-			// otherwise, set new filter values
-			style.filter = ralpha.test( filter ) ?
-				filter.replace( ralpha, opacity ) :
-				filter + " " + opacity;
-		}
-	};
-}
-
-jQuery(function() {
-	// This hook cannot be added until DOM ready because the support test
-	// for it is not run until after DOM ready
-	if ( !jQuery.support.reliableMarginRight ) {
-		jQuery.cssHooks.marginRight = {
-			get: function( elem, computed ) {
-				// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
-				// Work around by temporarily setting element display to inline-block
-				var ret;
-				jQuery.swap( elem, { "display": "inline-block" }, function() {
-					if ( computed ) {
-						ret = curCSS( elem, "margin-right", "marginRight" );
-					} else {
-						ret = elem.style.marginRight;
-					}
-				});
-				return ret;
-			}
-		};
-	}
-});
-
-if ( document.defaultView && document.defaultView.getComputedStyle ) {
-	getComputedStyle = function( elem, name ) {
-		var ret, defaultView, computedStyle;
-
-		name = name.replace( rupper, "-$1" ).toLowerCase();
-
-		if ( (defaultView = elem.ownerDocument.defaultView) &&
-				(computedStyle = defaultView.getComputedStyle( elem, null )) ) {
-			ret = computedStyle.getPropertyValue( name );
-			if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
-				ret = jQuery.style( elem, name );
-			}
-		}
-
-		return ret;
-	};
-}
-
-if ( document.documentElement.currentStyle ) {
-	currentStyle = function( elem, name ) {
-		var left, rsLeft, uncomputed,
-			ret = elem.currentStyle && elem.currentStyle[ name ],
-			style = elem.style;
-
-		// Avoid setting ret to empty string here
-		// so we don't default to auto
-		if ( ret === null && style && (uncomputed = style[ name ]) ) {
-			ret = uncomputed;
-		}
-
-		// From the awesome hack by Dean Edwards
-		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
-
-		// If we're not dealing with a regular pixel number
-		// but a number that has a weird ending, we need to convert it to pixels
-		if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
-
-			// Remember the original values
-			left = style.left;
-			rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
-
-			// Put in the new values to get a computed value out
-			if ( rsLeft ) {
-				elem.runtimeStyle.left = elem.currentStyle.left;
-			}
-			style.left = name === "fontSize" ? "1em" : ( ret || 0 );
-			ret = style.pixelLeft + "px";
-
-			// Revert the changed values
-			style.left = left;
-			if ( rsLeft ) {
-				elem.runtimeStyle.left = rsLeft;
-			}
-		}
-
-		return ret === "" ? "auto" : ret;
-	};
-}
-
-curCSS = getComputedStyle || currentStyle;
-
-function getWH( elem, name, extra ) {
-
-	// Start with offset property
-	var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
-		which = name === "width" ? cssWidth : cssHeight,
-		i = 0,
-		len = which.length;
-
-	if ( val > 0 ) {
-		if ( extra !== "border" ) {
-			for ( ; i < len; i++ ) {
-				if ( !extra ) {
-					val -= parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
-				}
-				if ( extra === "margin" ) {
-					val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
-				} else {
-					val -= parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
-				}
-			}
-		}
-
-		return val + "px";
-	}
-
-	// Fall back to computed then uncomputed css if necessary
-	val = curCSS( elem, name, name );
-	if ( val < 0 || val == null ) {
-		val = elem.style[ name ] || 0;
-	}
-	// Normalize "", auto, and prepare for extra
-	val = parseFloat( val ) || 0;
-
-	// Add padding, border, margin
-	if ( extra ) {
-		for ( ; i < len; i++ ) {
-			val += parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
-			if ( extra !== "padding" ) {
-				val += parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
-			}
-			if ( extra === "margin" ) {
-				val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
-			}
-		}
-	}
-
-	return val + "px";
-}
-
-if ( jQuery.expr && jQuery.expr.filters ) {
-	jQuery.expr.filters.hidden = function( elem ) {
-		var width = elem.offsetWidth,
-			height = elem.offsetHeight;
-
-		return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
-	};
-
-	jQuery.expr.filters.visible = function( elem ) {
-		return !jQuery.expr.filters.hidden( elem );
-	};
-}
-
-
-
-
-var r20 = /%20/g,
-	rbracket = /\[\]$/,
-	rCRLF = /\r?\n/g,
-	rhash = /#.*$/,
-	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
-	rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
-	// #7653, #8125, #8152: local protocol detection
-	rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
-	rnoContent = /^(?:GET|HEAD)$/,
-	rprotocol = /^\/\//,
-	rquery = /\?/,
-	rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
-	rselectTextarea = /^(?:select|textarea)/i,
-	rspacesAjax = /\s+/,
-	rts = /([?&])_=[^&]*/,
-	rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
-
-	// Keep a copy of the old load method
-	_load = jQuery.fn.load,
-
-	/* Prefilters
-	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
-	 * 2) These are called:
-	 *    - BEFORE asking for a transport
-	 *    - AFTER param serialization (s.data is a string if s.processData is true)
-	 * 3) key is the dataType
-	 * 4) the catchall symbol "*" can be used
-	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
-	 */
-	prefilters = {},
-
-	/* Transports bindings
-	 * 1) key is the dataType
-	 * 2) the catchall symbol "*" can be used
-	 * 3) selection will start with transport dataType and THEN go to "*" if needed
-	 */
-	transports = {},
-
-	// Document location
-	ajaxLocation,
-
-	// Document location segments
-	ajaxLocParts,
-
-	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
-	allTypes = ["*/"] + ["*"];
-
-// #8138, IE may throw an exception when accessing
-// a field from window.location if document.domain has been set
-try {
-	ajaxLocation = location.href;
-} catch( e ) {
-	// Use the href attribute of an A element
-	// since IE will modify it given document.location
-	ajaxLocation = document.createElement( "a" );
-	ajaxLocation.href = "";
-	ajaxLocation = ajaxLocation.href;
-}
-
-// Segment location into parts
-ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
-
-// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
-function addToPrefiltersOrTransports( structure ) {
-
-	// dataTypeExpression is optional and defaults to "*"
-	return function( dataTypeExpression, func ) {
-
-		if ( typeof dataTypeExpression !== "string" ) {
-			func = dataTypeExpression;
-			dataTypeExpression = "*";
-		}
-
-		if ( jQuery.isFunction( func ) ) {
-			var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
-				i = 0,
-				length = dataTypes.length,
-				dataType,
-				list,
-				placeBefore;
-
-			// For each dataType in the dataTypeExpression
-			for ( ; i < length; i++ ) {
-				dataType = dataTypes[ i ];
-				// We control if we're asked to add before
-				// any existing element
-				placeBefore = /^\+/.test( dataType );
-				if ( placeBefore ) {
-					dataType = dataType.substr( 1 ) || "*";
-				}
-				list = structure[ dataType ] = structure[ dataType ] || [];
-				// then we add to the structure accordingly
-				list[ placeBefore ? "unshift" : "push" ]( func );
-			}
-		}
-	};
-}
-
-// Base inspection function for prefilters and transports
-function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
-		dataType /* internal */, inspected /* internal */ ) {
-
-	dataType = dataType || options.dataTypes[ 0 ];
-	inspected = inspected || {};
-
-	inspected[ dataType ] = true;
-
-	var list = structure[ dataType ],
-		i = 0,
-		length = list ? list.length : 0,
-		executeOnly = ( structure === prefilters ),
-		selection;
-
-	for ( ; i < length && ( executeOnly || !selection ); i++ ) {
-		selection = list[ i ]( options, originalOptions, jqXHR );
-		// If we got redirected to another dataType
-		// we try there if executing only and not done already
-		if ( typeof selection === "string" ) {
-			if ( !executeOnly || inspected[ selection ] ) {
-				selection = undefined;
-			} else {
-				options.dataTypes.unshift( selection );
-				selection = inspectPrefiltersOrTransports(
-						structure, options, originalOptions, jqXHR, selection, inspected );
-			}
-		}
-	}
-	// If we're only executing or nothing was selected
-	// we try the catchall dataType if not done already
-	if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
-		selection = inspectPrefiltersOrTransports(
-				structure, options, originalOptions, jqXHR, "*", inspected );
-	}
-	// unnecessary when only executing (prefilters)
-	// but it'll be ignored by the caller in that case
-	return selection;
-}
-
-// A special extend for ajax options
-// that takes "flat" options (not to be deep extended)
-// Fixes #9887
-function ajaxExtend( target, src ) {
-	var key, deep,
-		flatOptions = jQuery.ajaxSettings.flatOptions || {};
-	for ( key in src ) {
-		if ( src[ key ] !== undefined ) {
-			( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
-		}
-	}
-	if ( deep ) {
-		jQuery.extend( true, target, deep );
-	}
-}
-
-jQuery.fn.extend({
-	load: function( url, params, callback ) {
-		if ( typeof url !== "string" && _load ) {
-			return _load.apply( this, arguments );
-
-		// Don't do a request if no elements are being requested
-		} else if ( !this.length ) {
-			return this;
-		}
-
-		var off = url.indexOf( " " );
-		if ( off >= 0 ) {
-			var selector = url.slice( off, url.length );
-			url = url.slice( 0, off );
-		}
-
-		// Default to a GET request
-		var type = "GET";
-
-		// If the second parameter was provided
-		if ( params ) {
-			// If it's a function
-			if ( jQuery.isFunction( params ) ) {
-				// We assume that it's the callback
-				callback = params;
-				params = undefined;
-
-			// Otherwise, build a param string
-			} else if ( typeof params === "object" ) {
-				params = jQuery.param( params, jQuery.ajaxSettings.traditional );
-				type = "POST";
-			}
-		}
-
-		var self = this;
-
-		// Request the remote document
-		jQuery.ajax({
-			url: url,
-			type: type,
-			dataType: "html",
-			data: params,
-			// Complete callback (responseText is used internally)
-			complete: function( jqXHR, status, responseText ) {
-				// Store the response as specified by the jqXHR object
-				responseText = jqXHR.responseText;
-				// If successful, inject the HTML into all the matched elements
-				if ( jqXHR.isResolved() ) {
-					// #4825: Get the actual response in case
-					// a dataFilter is present in ajaxSettings
-					jqXHR.done(function( r ) {
-						responseText = r;
-					});
-					// See if a selector was specified
-					self.html( selector ?
-						// Create a dummy div to hold the results
-						jQuery("<div>")
-							// inject the contents of the document in, removing the scripts
-							// to avoid any 'Permission Denied' errors in IE
-							.append(responseText.replace(rscript, ""))
-
-							// Locate the specified elements
-							.find(selector) :
-
-						// If not, just inject the full result
-						responseText );
-				}
-
-				if ( callback ) {
-					self.each( callback, [ responseText, status, jqXHR ] );
-				}
-			}
-		});
-
-		return this;
-	},
-
-	serialize: function() {
-		return jQuery.param( this.serializeArray() );
-	},
-
-	serializeArray: function() {
-		return this.map(function(){
-			return this.elements ? jQuery.makeArray( this.elements ) : this;
-		})
-		.filter(function(){
-			return this.name && !this.disabled &&
-				( this.checked || rselectTextarea.test( this.nodeName ) ||
-					rinput.test( this.type ) );
-		})
-		.map(function( i, elem ){
-			var val = jQuery( this ).val();
-
-			return val == null ?
-				null :
-				jQuery.isArray( val ) ?
-					jQuery.map( val, function( val, i ){
-						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
-					}) :
-					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
-		}).get();
-	}
-});
-
-// Attach a bunch of functions for handling util AJAX events
-jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
-	jQuery.fn[ o ] = function( f ){
-		return this.on( o, f );
-	};
-});
-
-jQuery.each( [ "get", "post" ], function( i, method ) {
-	jQuery[ method ] = function( url, data, callback, type ) {
-		// shift arguments if data argument was omitted
-		if ( jQuery.isFunction( data ) ) {
-			type = type || callback;
-			callback = data;
-			data = undefined;
-		}
-
-		return jQuery.ajax({
-			type: method,
-			url: url,
-			data: data,
-			success: callback,
-			dataType: type
-		});
-	};
-});
-
-jQuery.extend({
-
-	getScript: function( url, callback ) {
-		return jQuery.get( url, undefined, callback, "script" );
-	},
-
-	getJSON: function( url, data, callback ) {
-		return jQuery.get( url, data, callback, "json" );
-	},
-
-	// Creates a full fledged settings object into target
-	// with both ajaxSettings and settings fields.
-	// If target is omitted, writes into ajaxSettings.
-	ajaxSetup: function( target, settings ) {
-		if ( settings ) {
-			// Building a settings object
-			ajaxExtend( target, jQuery.ajaxSettings );
-		} else {
-			// Extending ajaxSettings
-			settings = target;
-			target = jQuery.ajaxSettings;
-		}
-		ajaxExtend( target, settings );
-		return target;
-	},
-
-	ajaxSettings: {
-		url: ajaxLocation,
-		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
-		global: true,
-		type: "GET",
-		contentType: "application/x-www-form-urlencoded",
-		processData: true,
-		async: true,
-		/*
-		timeout: 0,
-		data: null,
-		dataType: null,
-		username: null,
-		password: null,
-		cache: null,
-		traditional: false,
-		headers: {},
-		*/
-
-		accepts: {
-			xml: "application/xml, text/xml",
-			html: "text/html",
-			text: "text/plain",
-			json: "application/json, text/javascript",
-			"*": allTypes
-		},
-
-		contents: {
-			xml: /xml/,
-			html: /html/,
-			json: /json/
-		},
-
-		responseFields: {
-			xml: "responseXML",
-			text: "responseText"
-		},
-
-		// List of data converters
-		// 1) key format is "source_type destination_type" (a single space in-between)
-		// 2) the catchall symbol "*" can be used for source_type
-		converters: {
-
-			// Convert anything to text
-			"* text": window.String,
-
-			// Text to html (true = no transformation)
-			"text html": true,
-
-			// Evaluate text as a json expression
-			"text json": jQuery.parseJSON,
-
-			// Parse text as xml
-			"text xml": jQuery.parseXML
-		},
-
-		// For options that shouldn't be deep extended:
-		// you can add your own custom options here if
-		// and when you create one that shouldn't be
-		// deep extended (see ajaxExtend)
-		flatOptions: {
-			context: true,
-			url: true
-		}
-	},
-
-	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
-	ajaxTransport: addToPrefiltersOrTransports( transports ),
-
-	// Main method
-	ajax: function( url, options ) {
-
-		// If url is an object, simulate pre-1.5 signature
-		if ( typeof url === "object" ) {
-			options = url;
-			url = undefined;
-		}
-
-		// Force options to be an object
-		options = options || {};
-
-		var // Create the final options object
-			s = jQuery.ajaxSetup( {}, options ),
-			// Callbacks context
-			callbackContext = s.context || s,
-			// Context for global events
-			// It's the callbackContext if one was provided in the options
-			// and if it's a DOM node or a jQuery collection
-			globalEventContext = callbackContext !== s &&
-				( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
-						jQuery( callbackContext ) : jQuery.event,
-			// Deferreds
-			deferred = jQuery.Deferred(),
-			completeDeferred = jQuery.Callbacks( "once memory" ),
-			// Status-dependent callbacks
-			statusCode = s.statusCode || {},
-			// ifModified key
-			ifModifiedKey,
-			// Headers (they are sent all at once)
-			requestHeaders = {},
-			requestHeadersNames = {},
-			// Response headers
-			responseHeadersString,
-			responseHeaders,
-			// transport
-			transport,
-			// timeout handle
-			timeoutTimer,
-			// Cross-domain detection vars
-			parts,
-			// The jqXHR state
-			state = 0,
-			// To know if global events are to be dispatched
-			fireGlobals,
-			// Loop variable
-			i,
-			// Fake xhr
-			jqXHR = {
-
-				readyState: 0,
-
-				// Caches the header
-				setRequestHeader: function( name, value ) {
-					if ( !state ) {
-						var lname = name.toLowerCase();
-						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
-						requestHeaders[ name ] = value;
-					}
-					return this;
-				},
-
-				// Raw string
-				getAllResponseHeaders: function() {
-					return state === 2 ? responseHeadersString : null;
-				},
-
-				// Builds headers hashtable if needed
-				getResponseHeader: function( key ) {
-					var match;
-					if ( state === 2 ) {
-						if ( !responseHeaders ) {
-							responseHeaders = {};
-							while( ( match = rheaders.exec( responseHeadersString ) ) ) {
-								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
-							}
-						}
-						match = responseHeaders[ key.toLowerCase() ];
-					}
-					return match === undefined ? null : match;
-				},
-
-				// Overrides response content-type header
-				overrideMimeType: function( type ) {
-					if ( !state ) {
-						s.mimeType = type;
-					}
-					return this;
-				},
-
-				// Cancel the request
-				abort: function( statusText ) {
-					statusText = statusText || "abort";
-					if ( transport ) {
-						transport.abort( statusText );
-					}
-					done( 0, statusText );
-					return this;
-				}
-			};
-
-		// Callback for when everything is done
-		// It is defined here because jslint complains if it is declared
-		// at the end of the function (which would be more logical and readable)
-		function done( status, nativeStatusText, responses, headers ) {
-
-			// Called once
-			if ( state === 2 ) {
-				return;
-			}
-
-			// State is "done" now
-			state = 2;
-
-			// Clear timeout if it exists
-			if ( timeoutTimer ) {
-				clearTimeout( timeoutTimer );
-			}
-
-			// Dereference transport for early garbage collection
-			// (no matter how long the jqXHR object will be used)
-			transport = undefined;
-
-			// Cache response headers
-			responseHeadersString = headers || "";
-
-			// Set readyState
-			jqXHR.readyState = status > 0 ? 4 : 0;
-
-			var isSuccess,
-				success,
-				error,
-				statusText = nativeStatusText,
-				response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
-				lastModified,
-				etag;
-
-			// If successful, handle type chaining
-			if ( status >= 200 && status < 300 || status === 304 ) {
-
-				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
-				if ( s.ifModified ) {
-
-					if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
-						jQuery.lastModified[ ifModifiedKey ] = lastModified;
-					}
-					if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
-						jQuery.etag[ ifModifiedKey ] = etag;
-					}
-				}
-
-				// If not modified
-				if ( status === 304 ) {
-
-					statusText = "notmodified";
-					isSuccess = true;
-
-				// If we have data
-				} else {
-
-					try {
-						success = ajaxConvert( s, response );
-						statusText = "success";
-						isSuccess = true;
-					} catch(e) {
-						// We have a parsererror
-						statusText = "parsererror";
-						error = e;
-					}
-				}
-			} else {
-				// We extract error from statusText
-				// then normalize statusText and status for non-aborts
-				error = statusText;
-				if ( !statusText || status ) {
-					statusText = "error";
-					if ( status < 0 ) {
-						status = 0;
-					}
-				}
-			}
-
-			// Set data for the fake xhr object
-			jqXHR.status = status;
-			jqXHR.statusText = "" + ( nativeStatusText || statusText );
-
-			// Success/Error
-			if ( isSuccess ) {
-				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
-			} else {
-				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
-			}
-
-			// Status-dependent callbacks
-			jqXHR.statusCode( statusCode );
-			statusCode = undefined;
-
-			if ( fireGlobals ) {
-				globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
-						[ jqXHR, s, isSuccess ? success : error ] );
-			}
-
-			// Complete
-			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
-
-			if ( fireGlobals ) {
-				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
-				// Handle the global AJAX counter
-				if ( !( --jQuery.active ) ) {
-					jQuery.event.trigger( "ajaxStop" );
-				}
-			}
-		}
-
-		// Attach deferreds
-		deferred.promise( jqXHR );
-		jqXHR.success = jqXHR.done;
-		jqXHR.error = jqXHR.fail;
-		jqXHR.complete = completeDeferred.add;
-
-		// Status-dependent callbacks
-		jqXHR.statusCode = function( map ) {
-			if ( map ) {
-				var tmp;
-				if ( state < 2 ) {
-					for ( tmp in map ) {
-						statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
-					}
-				} else {
-					tmp = map[ jqXHR.status ];
-					jqXHR.then( tmp, tmp );
-				}
-			}
-			return this;
-		};
-
-		// Remove hash character (#7531: and string promotion)
-		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
-		// We also use the url parameter if available
-		s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
-
-		// Extract dataTypes list
-		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
-
-		// Determine if a cross-domain request is in order
-		if ( s.crossDomain == null ) {
-			parts = rurl.exec( s.url.toLowerCase() );
-			s.crossDomain = !!( parts &&
-				( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
-					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
-						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
-			);
-		}
-
-		// Convert data if not already a string
-		if ( s.data && s.processData && typeof s.data !== "string" ) {
-			s.data = jQuery.param( s.data, s.traditional );
-		}
-
-		// Apply prefilters
-		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
-
-		// If request was aborted inside a prefiler, stop there
-		if ( state === 2 ) {
-			return false;
-		}
-
-		// We can fire global events as of now if asked to
-		fireGlobals = s.global;
-
-		// Uppercase the type
-		s.type = s.type.toUpperCase();
-
-		// Determine if request has content
-		s.hasContent = !rnoContent.test( s.type );
-
-		// Watch for a new set of requests
-		if ( fireGlobals && jQuery.active++ === 0 ) {
-			jQuery.event.trigger( "ajaxStart" );
-		}
-
-		// More options handling for requests with no content
-		if ( !s.hasContent ) {
-
-			// If data is available, append data to url
-			if ( s.data ) {
-				s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
-				// #9682: remove data so that it's not used in an eventual retry
-				delete s.data;
-			}
-
-			// Get ifModifiedKey before adding the anti-cache parameter
-			ifModifiedKey = s.url;
-
-			// Add anti-cache in url if needed
-			if ( s.cache === false ) {
-
-				var ts = jQuery.now(),
-					// try replacing _= if it is there
-					ret = s.url.replace( rts, "$1_=" + ts );
-
-				// if nothing was replaced, add timestamp to the end
-				s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
-			}
-		}
-
-		// Set the correct header, if data is being sent
-		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
-			jqXHR.setRequestHeader( "Content-Type", s.contentType );
-		}
-
-		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
-		if ( s.ifModified ) {
-			ifModifiedKey = ifModifiedKey || s.url;
-			if ( jQuery.lastModified[ ifModifiedKey ] ) {
-				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
-			}
-			if ( jQuery.etag[ ifModifiedKey ] ) {
-				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
-			}
-		}
-
-		// Set the Accepts header for the server, depending on the dataType
-		jqXHR.setRequestHeader(
-			"Accept",
-			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
-				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
-				s.accepts[ "*" ]
-		);
-
-		// Check for headers option
-		for ( i in s.headers ) {
-			jqXHR.setRequestHeader( i, s.headers[ i ] );
-		}
-
-		// Allow custom headers/mimetypes and early abort
-		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
-				// Abort if not done already
-				jqXHR.abort();
-				return false;
-
-		}
-
-		// Install callbacks on deferreds
-		for ( i in { success: 1, error: 1, complete: 1 } ) {
-			jqXHR[ i ]( s[ i ] );
-		}
-
-		// Get transport
-		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
-
-		// If no transport, we auto-abort
-		if ( !transport ) {
-			done( -1, "No Transport" );
-		} else {
-			jqXHR.readyState = 1;
-			// Send global event
-			if ( fireGlobals ) {
-				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
-			}
-			// Timeout
-			if ( s.async && s.timeout > 0 ) {
-				timeoutTimer = setTimeout( function(){
-					jqXHR.abort( "timeout" );
-				}, s.timeout );
-			}
-
-			try {
-				state = 1;
-				transport.send( requestHeaders, done );
-			} catch (e) {
-				// Propagate exception as error if not done
-				if ( state < 2 ) {
-					done( -1, e );
-				// Simply rethrow otherwise
-				} else {
-					throw e;
-				}
-			}
-		}
-
-		return jqXHR;
-	},
-
-	// Serialize an array of form elements or a set of
-	// key/values into a query string
-	param: function( a, traditional ) {
-		var s = [],
-			add = function( key, value ) {
-				// If value is a function, invoke it and return its value
-				value = jQuery.isFunction( value ) ? value() : value;
-				s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
-			};
-
-		// Set traditional to true for jQuery <= 1.3.2 behavior.
-		if ( traditional === undefined ) {
-			traditional = jQuery.ajaxSettings.traditional;
-		}
-
-		// If an array was passed in, assume that it is an array of form elements.
-		if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
-			// Serialize the form elements
-			jQuery.each( a, function() {
-				add( this.name, this.value );
-			});
-
-		} else {
-			// If traditional, encode the "old" way (the way 1.3.2 or older
-			// did it), otherwise encode params recursively.
-			for ( var prefix in a ) {
-				buildParams( prefix, a[ prefix ], traditional, add );
-			}
-		}
-
-		// Return the resulting serialization
-		return s.join( "&" ).replace( r20, "+" );
-	}
-});
-
-function buildParams( prefix, obj, traditional, add ) {
-	if ( jQuery.isArray( obj ) ) {
-		// Serialize array item.
-		jQuery.each( obj, function( i, v ) {
-			if ( traditional || rbracket.test( prefix ) ) {
-				// Treat each array item as a scalar.
-				add( prefix, v );
-
-			} else {
-				// If array item is non-scalar (array or object), encode its
-				// numeric index to resolve deserialization ambiguity issues.
-				// Note that rack (as of 1.0.0) can't currently deserialize
-				// nested arrays properly, and attempting to do so may cause
-				// a server error. Possible fixes are to modify rack's
-				// deserialization algorithm or to provide an option or flag
-				// to force array serialization to be shallow.
-				buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
-			}
-		});
-
-	} else if ( !traditional && obj != null && typeof obj === "object" ) {
-		// Serialize object item.
-		for ( var name in obj ) {
-			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
-		}
-
-	} else {
-		// Serialize scalar item.
-		add( prefix, obj );
-	}
-}
-
-// This is still on the jQuery object... for now
-// Want to move this to jQuery.ajax some day
-jQuery.extend({
-
-	// Counter for holding the number of active queries
-	active: 0,
-
-	// Last-Modified header cache for next request
-	lastModified: {},
-	etag: {}
-
-});
-
-/* Handles responses to an ajax request:
- * - sets all responseXXX fields accordingly
- * - finds the right dataType (mediates between content-type and expected dataType)
- * - returns the corresponding response
- */
-function ajaxHandleResponses( s, jqXHR, responses ) {
-
-	var contents = s.contents,
-		dataTypes = s.dataTypes,
-		responseFields = s.responseFields,
-		ct,
-		type,
-		finalDataType,
-		firstDataType;
-
-	// Fill responseXXX fields
-	for ( type in responseFields ) {
-		if ( type in responses ) {
-			jqXHR[ responseFields[type] ] = responses[ type ];
-		}
-	}
-
-	// Remove auto dataType and get content-type in the process
-	while( dataTypes[ 0 ] === "*" ) {
-		dataTypes.shift();
-		if ( ct === undefined ) {
-			ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
-		}
-	}
-
-	// Check if we're dealing with a known content-type
-	if ( ct ) {
-		for ( type in contents ) {
-			if ( contents[ type ] && contents[ type ].test( ct ) ) {
-				dataTypes.unshift( type );
-				break;
-			}
-		}
-	}
-
-	// Check to see if we have a response for the expected dataType
-	if ( dataTypes[ 0 ] in responses ) {
-		finalDataType = dataTypes[ 0 ];
-	} else {
-		// Try convertible dataTypes
-		for ( type in responses ) {
-			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
-				finalDataType = type;
-				break;
-			}
-			if ( !firstDataType ) {
-				firstDataType = type;
-			}
-		}
-		// Or just use first one
-		finalDataType = finalDataType || firstDataType;
-	}
-
-	// If we found a dataType
-	// We add the dataType to the list if needed
-	// and return the corresponding response
-	if ( finalDataType ) {
-		if ( finalDataType !== dataTypes[ 0 ] ) {
-			dataTypes.unshift( finalDataType );
-		}
-		return responses[ finalDataType ];
-	}
-}
-
-// Chain conversions given the request and the original response
-function ajaxConvert( s, response ) {
-
-	// Apply the dataFilter if provided
-	if ( s.dataFilter ) {
-		response = s.dataFilter( response, s.dataType );
-	}
-
-	var dataTypes = s.dataTypes,
-		converters = {},
-		i,
-		key,
-		length = dataTypes.length,
-		tmp,
-		// Current and previous dataTypes
-		current = dataTypes[ 0 ],
-		prev,
-		// Conversion expression
-		conversion,
-		// Conversion function
-		conv,
-		// Conversion functions (transitive conversion)
-		conv1,
-		conv2;
-
-	// For each dataType in the chain
-	for ( i = 1; i < length; i++ ) {
-
-		// Create converters map
-		// with lowercased keys
-		if ( i === 1 ) {
-			for ( key in s.converters ) {
-				if ( typeof key === "string" ) {
-					converters[ key.toLowerCase() ] = s.converters[ key ];
-				}
-			}
-		}
-
-		// Get the dataTypes
-		prev = current;
-		current = dataTypes[ i ];
-
-		// If current is auto dataType, update it to prev
-		if ( current === "*" ) {
-			current = prev;
-		// If no auto and dataTypes are actually different
-		} else if ( prev !== "*" && prev !== current ) {
-
-			// Get the converter
-			conversion = prev + " " + current;
-			conv = converters[ conversion ] || converters[ "* " + current ];
-
-			// If there is no direct converter, search transitively
-			if ( !conv ) {
-				conv2 = undefined;
-				for ( conv1 in converters ) {
-					tmp = conv1.split( " " );
-					if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
-						conv2 = converters[ tmp[1] + " " + current ];
-						if ( conv2 ) {
-							conv1 = converters[ conv1 ];
-							if ( conv1 === true ) {
-								conv = conv2;
-							} else if ( conv2 === true ) {
-								conv = conv1;
-							}
-							break;
-						}
-					}
-				}
-			}
-			// If we found no converter, dispatch an error
-			if ( !( conv || conv2 ) ) {
-				jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
-			}
-			// If found converter is not an equivalence
-			if ( conv !== true ) {
-				// Convert with 1 or 2 converters accordingly
-				response = conv ? conv( response ) : conv2( conv1(response) );
-			}
-		}
-	}
-	return response;
-}
-
-
-
-
-var jsc = jQuery.now(),
-	jsre = /(\=)\?(&|$)|\?\?/i;
-
-// Default jsonp settings
-jQuery.ajaxSetup({
-	jsonp: "callback",
-	jsonpCallback: function() {
-		return jQuery.expando + "_" + ( jsc++ );
-	}
-});
-
-// Detect, normalize options and install callbacks for jsonp requests
-jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
-
-	var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
-		( typeof s.data === "string" );
-
-	if ( s.dataTypes[ 0 ] === "jsonp" ||
-		s.jsonp !== false && ( jsre.test( s.url ) ||
-				inspectData && jsre.test( s.data ) ) ) {
-
-		var responseContainer,
-			jsonpCallback = s.jsonpCallback =
-				jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
-			previous = window[ jsonpCallback ],
-			url = s.url,
-			data = s.data,
-			replace = "$1" + jsonpCallback + "$2";
-
-		if ( s.jsonp !== false ) {
-			url = url.replace( jsre, replace );
-			if ( s.url === url ) {
-				if ( inspectData ) {
-					data = data.replace( jsre, replace );
-				}
-				if ( s.data === data ) {
-					// Add callback manually
-					url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
-				}
-			}
-		}
-
-		s.url = url;
-		s.data = data;
-
-		// Install callback
-		window[ jsonpCallback ] = function( response ) {
-			responseContainer = [ response ];
-		};
-
-		// Clean-up function
-		jqXHR.always(function() {
-			// Set callback back to previous value
-			window[ jsonpCallback ] = previous;
-			// Call if it was a function and we have a response
-			if ( responseContainer && jQuery.isFunction( previous ) ) {
-				window[ jsonpCallback ]( responseContainer[ 0 ] );
-			}
-		});
-
-		// Use data converter to retrieve json after script execution
-		s.converters["script json"] = function() {
-			if ( !responseContainer ) {
-				jQuery.error( jsonpCallback + " was not called" );
-			}
-			return responseContainer[ 0 ];
-		};
-
-		// force json dataType
-		s.dataTypes[ 0 ] = "json";
-
-		// Delegate to script
-		return "script";
-	}
-});
-
-
-
-
-// Install script dataType
-jQuery.ajaxSetup({
-	accepts: {
-		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
-	},
-	contents: {
-		script: /javascript|ecmascript/
-	},
-	converters: {
-		"text script": function( text ) {
-			jQuery.globalEval( text );
-			return text;
-		}
-	}
-});
-
-// Handle cache's special case and global
-jQuery.ajaxPrefilter( "script", function( s ) {
-	if ( s.cache === undefined ) {
-		s.cache = false;
-	}
-	if ( s.crossDomain ) {
-		s.type = "GET";
-		s.global = false;
-	}
-});
-
-// Bind script tag hack transport
-jQuery.ajaxTransport( "script", function(s) {
-
-	// This transport only deals with cross domain requests
-	if ( s.crossDomain ) {
-
-		var script,
-			head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
-
-		return {
-
-			send: function( _, callback ) {
-
-				script = document.createElement( "script" );
-
-				script.async = "async";
-
-				if ( s.scriptCharset ) {
-					script.charset = s.scriptCharset;
-				}
-
-				script.src = s.url;
-
-				// Attach handlers for all browsers
-				script.onload = script.onreadystatechange = function( _, isAbort ) {
-
-					if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
-
-						// Handle memory leak in IE
-						script.onload = script.onreadystatechange = null;
-
-						// Remove the script
-						if ( head && script.parentNode ) {
-							head.removeChild( script );
-						}
-
-						// Dereference the script
-						script = undefined;
-
-						// Callback if not abort
-						if ( !isAbort ) {
-							callback( 200, "success" );
-						}
-					}
-				};
-				// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
-				// This arises when a base node is used (#2709 and #4378).
-				head.insertBefore( script, head.firstChild );
-			},
-
-			abort: function() {
-				if ( script ) {
-					script.onload( 0, 1 );
-				}
-			}
-		};
-	}
-});
-
-
-
-
-var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
-	xhrOnUnloadAbort = window.ActiveXObject ? function() {
-		// Abort all pending requests
-		for ( var key in xhrCallbacks ) {
-			xhrCallbacks[ key ]( 0, 1 );
-		}
-	} : false,
-	xhrId = 0,
-	xhrCallbacks;
-
-// Functions to create xhrs
-function createStandardXHR() {
-	try {
-		return new window.XMLHttpRequest();
-	} catch( e ) {}
-}
-
-function createActiveXHR() {
-	try {
-		return new window.ActiveXObject( "Microsoft.XMLHTTP" );
-	} catch( e ) {}
-}
-
-// Create the request object
-// (This is still attached to ajaxSettings for backward compatibility)
-jQuery.ajaxSettings.xhr = window.ActiveXObject ?
-	/* Microsoft failed to properly
-	 * implement the XMLHttpRequest in IE7 (can't request local files),
-	 * so we use the ActiveXObject when it is available
-	 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
-	 * we need a fallback.
-	 */
-	function() {
-		return !this.isLocal && createStandardXHR() || createActiveXHR();
-	} :
-	// For all other browsers, use the standard XMLHttpRequest object
-	createStandardXHR;
-
-// Determine support properties
-(function( xhr ) {
-	jQuery.extend( jQuery.support, {
-		ajax: !!xhr,
-		cors: !!xhr && ( "withCredentials" in xhr )
-	});
-})( jQuery.ajaxSettings.xhr() );
-
-// Create transport if the browser can provide an xhr
-if ( jQuery.support.ajax ) {
-
-	jQuery.ajaxTransport(function( s ) {
-		// Cross domain only allowed if supported through XMLHttpRequest
-		if ( !s.crossDomain || jQuery.support.cors ) {
-
-			var callback;
-
-			return {
-				send: function( headers, complete ) {
-
-					// Get a new xhr
-					var xhr = s.xhr(),
-						handle,
-						i;
-
-					// Open the socket
-					// Passing null username, generates a login popup on Opera (#2865)
-					if ( s.username ) {
-						xhr.open( s.type, s.url, s.async, s.username, s.password );
-					} else {
-						xhr.open( s.type, s.url, s.async );
-					}
-
-					// Apply custom fields if provided
-					if ( s.xhrFields ) {
-						for ( i in s.xhrFields ) {
-							xhr[ i ] = s.xhrFields[ i ];
-						}
-					}
-
-					// Override mime type if needed
-					if ( s.mimeType && xhr.overrideMimeType ) {
-						xhr.overrideMimeType( s.mimeType );
-					}
-
-					// X-Requested-With header
-					// For cross-domain requests, seeing as conditions for a preflight are
-					// akin to a jigsaw puzzle, we simply never set it to be sure.
-					// (it can always be set on a per-request basis or even using ajaxSetup)
-					// For same-domain requests, won't change header if already provided.
-					if ( !s.crossDomain && !headers["X-Requested-With"] ) {
-						headers[ "X-Requested-With" ] = "XMLHttpRequest";
-					}
-
-					// Need an extra try/catch for cross domain requests in Firefox 3
-					try {
-						for ( i in headers ) {
-							xhr.setRequestHeader( i, headers[ i ] );
-						}
-					} catch( _ ) {}
-
-					// Do send the request
-					// This may raise an exception which is actually
-					// handled in jQuery.ajax (so no try/catch here)
-					xhr.send( ( s.hasContent && s.data ) || null );
-
-					// Listener
-					callback = function( _, isAbort ) {
-
-						var status,
-							statusText,
-							responseHeaders,
-							responses,
-							xml;
-
-						// Firefox throws exceptions when accessing properties
-						// of an xhr when a network error occured
-						// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
-						try {
-
-							// Was never called and is aborted or complete
-							if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
-
-								// Only called once
-								callback = undefined;
-
-								// Do not keep as active anymore
-								if ( handle ) {
-									xhr.onreadystatechange = jQuery.noop;
-									if ( xhrOnUnloadAbort ) {
-										delete xhrCallbacks[ handle ];
-									}
-								}
-
-								// If it's an abort
-								if ( isAbort ) {
-									// Abort it manually if needed
-									if ( xhr.readyState !== 4 ) {
-										xhr.abort();
-									}
-								} else {
-									status = xhr.status;
-									responseHeaders = xhr.getAllResponseHeaders();
-									responses = {};
-									xml = xhr.responseXML;
-
-									// Construct response list
-									if ( xml && xml.documentElement /* #4958 */ ) {
-										responses.xml = xml;
-									}
-									responses.text = xhr.responseText;
-
-									// Firefox throws an exception when accessing
-									// statusText for faulty cross-domain requests
-									try {
-										statusText = xhr.statusText;
-									} catch( e ) {
-										// We normalize with Webkit giving an empty statusText
-										statusText = "";
-									}
-
-									// Filter status for non standard behaviors
-
-									// If the request is local and we have data: assume a success
-									// (success with no data won't get notified, that's the best we
-									// can do given current implementations)
-									if ( !status && s.isLocal && !s.crossDomain ) {
-										status = responses.text ? 200 : 404;
-									// IE - #1450: sometimes returns 1223 when it should be 204
-									} else if ( status === 1223 ) {
-										status = 204;
-									}
-								}
-							}
-						} catch( firefoxAccessException ) {
-							if ( !isAbort ) {
-								complete( -1, firefoxAccessException );
-							}
-						}
-
-						// Call complete if needed
-						if ( responses ) {
-							complete( status, statusText, responses, responseHeaders );
-						}
-					};
-
-					// if we're in sync mode or it's in cache
-					// and has been retrieved directly (IE6 & IE7)
-					// we need to manually fire the callback
-					if ( !s.async || xhr.readyState === 4 ) {
-						callback();
-					} else {
-						handle = ++xhrId;
-						if ( xhrOnUnloadAbort ) {
-							// Create the active xhrs callbacks list if needed
-							// and attach the unload handler
-							if ( !xhrCallbacks ) {
-								xhrCallbacks = {};
-								jQuery( window ).unload( xhrOnUnloadAbort );
-							}
-							// Add to list of active xhrs callbacks
-							xhrCallbacks[ handle ] = callback;
-						}
-						xhr.onreadystatechange = callback;
-					}
-				},
-
-				abort: function() {
-					if ( callback ) {
-						callback(0,1);
-					}
-				}
-			};
-		}
-	});
-}
-
-
-
-
-var elemdisplay = {},
-	iframe, iframeDoc,
-	rfxtypes = /^(?:toggle|show|hide)$/,
-	rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
-	timerId,
-	fxAttrs = [
-		// height animations
-		[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
-		// width animations
-		[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
-		// opacity animations
-		[ "opacity" ]
-	],
-	fxNow;
-
-jQuery.fn.extend({
-	show: function( speed, easing, callback ) {
-		var elem, display;
-
-		if ( speed || speed === 0 ) {
-			return this.animate( genFx("show", 3), speed, easing, callback );
-
-		} else {
-			for ( var i = 0, j = this.length; i < j; i++ ) {
-				elem = this[ i ];
-
-				if ( elem.style ) {
-					display = elem.style.display;
-
-					// Reset the inline display of this element to learn if it is
-					// being hidden by cascaded rules or not
-					if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
-						display = elem.style.display = "";
-					}
-
-					// Set elements which have been overridden with display: none
-					// in a stylesheet to whatever the default browser style is
-					// for such an element
-					if ( display === "" && jQuery.css(elem, "display") === "none" ) {
-						jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
-					}
-				}
-			}
-
-			// Set the display of most of the elements in a second loop
-			// to avoid the constant reflow
-			for ( i = 0; i < j; i++ ) {
-				elem = this[ i ];
-
-				if ( elem.style ) {
-					display = elem.style.display;
-
-					if ( display === "" || display === "none" ) {
-						elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
-					}
-				}
-			}
-
-			return this;
-		}
-	},
-
-	hide: function( speed, easing, callback ) {
-		if ( speed || speed === 0 ) {
-			return this.animate( genFx("hide", 3), speed, easing, callback);
-
-		} else {
-			var elem, display,
-				i = 0,
-				j = this.length;
-
-			for ( ; i < j; i++ ) {
-				elem = this[i];
-				if ( elem.style ) {
-					display = jQuery.css( elem, "display" );
-
-					if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
-						jQuery._data( elem, "olddisplay", display );
-					}
-				}
-			}
-
-			// Set the display of the elements in a second loop
-			// to avoid the constant reflow
-			for ( i = 0; i < j; i++ ) {
-				if ( this[i].style ) {
-					this[i].style.display = "none";
-				}
-			}
-
-			return this;
-		}
-	},
-
-	// Save the old toggle function
-	_toggle: jQuery.fn.toggle,
-
-	toggle: function( fn, fn2, callback ) {
-		var bool = typeof fn === "boolean";
-
-		if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
-			this._toggle.apply( this, arguments );
-
-		} else if ( fn == null || bool ) {
-			this.each(function() {
-				var state = bool ? fn : jQuery(this).is(":hidden");
-				jQuery(this)[ state ? "show" : "hide" ]();
-			});
-
-		} else {
-			this.animate(genFx("toggle", 3), fn, fn2, callback);
-		}
-
-		return this;
-	},
-
-	fadeTo: function( speed, to, easing, callback ) {
-		return this.filter(":hidden").css("opacity", 0).show().end()
-					.animate({opacity: to}, speed, easing, callback);
-	},
-
-	animate: function( prop, speed, easing, callback ) {
-		var optall = jQuery.speed( speed, easing, callback );
-
-		if ( jQuery.isEmptyObject( prop ) ) {
-			return this.each( optall.complete, [ false ] );
-		}
-
-		// Do not change referenced properties as per-property easing will be lost
-		prop = jQuery.extend( {}, prop );
-
-		function doAnimation() {
-			// XXX 'this' does not always have a nodeName when running the
-			// test suite
-
-			if ( optall.queue === false ) {
-				jQuery._mark( this );
-			}
-
-			var opt = jQuery.extend( {}, optall ),
-				isElement = this.nodeType === 1,
-				hidden = isElement && jQuery(this).is(":hidden"),
-				name, val, p, e,
-				parts, start, end, unit,
-				method;
-
-			// will store per property easing and be used to determine when an animation is complete
-			opt.animatedProperties = {};
-
-			for ( p in prop ) {
-
-				// property name normalization
-				name = jQuery.camelCase( p );
-				if ( p !== name ) {
-					prop[ name ] = prop[ p ];
-					delete prop[ p ];
-				}
-
-				val = prop[ name ];
-
-				// easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
-				if ( jQuery.isArray( val ) ) {
-					opt.animatedProperties[ name ] = val[ 1 ];
-					val = prop[ name ] = val[ 0 ];
-				} else {
-					opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
-				}
-
-				if ( val === "hide" && hidden || val === "show" && !hidden ) {
-					return opt.complete.call( this );
-				}
-
-				if ( isElement && ( name === "height" || name === "width" ) ) {
-					// Make sure that nothing sneaks out
-					// Record all 3 overflow attributes because IE does not
-					// change the overflow attribute when overflowX and
-					// overflowY are set to the same value
-					opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
-
-					// Set display property to inline-block for height/width
-					// animations on inline elements that are having width/height animated
-					if ( jQuery.css( this, "display" ) === "inline" &&
-							jQuery.css( this, "float" ) === "none" ) {
-
-						// inline-level elements accept inline-block;
-						// block-level elements need to be inline with layout
-						if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
-							this.style.display = "inline-block";
-
-						} else {
-							this.style.zoom = 1;
-						}
-					}
-				}
-			}
-
-			if ( opt.overflow != null ) {
-				this.style.overflow = "hidden";
-			}
-
-			for ( p in prop ) {
-				e = new jQuery.fx( this, opt, p );
-				val = prop[ p ];
-
-				if ( rfxtypes.test( val ) ) {
-
-					// Tracks whether to show or hide based on private
-					// data attached to the element
-					method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
-					if ( method ) {
-						jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
-						e[ method ]();
-					} else {
-						e[ val ]();
-					}
-
-				} else {
-					parts = rfxnum.exec( val );
-					start = e.cur();
-
-					if ( parts ) {
-						end = parseFloat( parts[2] );
-						unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
-
-						// We need to compute starting value
-						if ( unit !== "px" ) {
-							jQuery.style( this, p, (end || 1) + unit);
-							start = ( (end || 1) / e.cur() ) * start;
-							jQuery.style( this, p, start + unit);
-						}
-
-						// If a +=/-= token was provided, we're doing a relative animation
-						if ( parts[1] ) {
-							end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
-						}
-
-						e.custom( start, end, unit );
-
-					} else {
-						e.custom( start, val, "" );
-					}
-				}
-			}
-
-			// For JS strict compliance
-			return true;
-		}
-
-		return optall.queue === false ?
-			this.each( doAnimation ) :
-			this.queue( optall.queue, doAnimation );
-	},
-
-	stop: function( type, clearQueue, gotoEnd ) {
-		if ( typeof type !== "string" ) {
-			gotoEnd = clearQueue;
-			clearQueue = type;
-			type = undefined;
-		}
-		if ( clearQueue && type !== false ) {
-			this.queue( type || "fx", [] );
-		}
-
-		return this.each(function() {
-			var index,
-				hadTimers = false,
-				timers = jQuery.timers,
-				data = jQuery._data( this );
-
-			// clear marker counters if we know they won't be
-			if ( !gotoEnd ) {
-				jQuery._unmark( true, this );
-			}
-
-			function stopQueue( elem, data, index ) {
-				var hooks = data[ index ];
-				jQuery.removeData( elem, index, true );
-				hooks.stop( gotoEnd );
-			}
-
-			if ( type == null ) {
-				for ( index in data ) {
-					if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) {
-						stopQueue( this, data, index );
-					}
-				}
-			} else if ( data[ index = type + ".run" ] && data[ index ].stop ){
-				stopQueue( this, data, index );
-			}
-
-			for ( index = timers.length; index--; ) {
-				if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
-					if ( gotoEnd ) {
-
-						// force the next step to be the last
-						timers[ index ]( true );
-					} else {
-						timers[ index ].saveState();
-					}
-					hadTimers = true;
-					timers.splice( index, 1 );
-				}
-			}
-
-			// start the next in the queue if the last step wasn't forced
-			// timers currently will call their complete callbacks, which will dequeue
-			// but only if they were gotoEnd
-			if ( !( gotoEnd && hadTimers ) ) {
-				jQuery.dequeue( this, type );
-			}
-		});
-	}
-
-});
-
-// Animations created synchronously will run synchronously
-function createFxNow() {
-	setTimeout( clearFxNow, 0 );
-	return ( fxNow = jQuery.now() );
-}
-
-function clearFxNow() {
-	fxNow = undefined;
-}
-
-// Generate parameters to create a standard animation
-function genFx( type, num ) {
-	var obj = {};
-
-	jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
-		obj[ this ] = type;
-	});
-
-	return obj;
-}
-
-// Generate shortcuts for custom animations
-jQuery.each({
-	slideDown: genFx( "show", 1 ),
-	slideUp: genFx( "hide", 1 ),
-	slideToggle: genFx( "toggle", 1 ),
-	fadeIn: { opacity: "show" },
-	fadeOut: { opacity: "hide" },
-	fadeToggle: { opacity: "toggle" }
-}, function( name, props ) {
-	jQuery.fn[ name ] = function( speed, easing, callback ) {
-		return this.animate( props, speed, easing, callback );
-	};
-});
-
-jQuery.extend({
-	speed: function( speed, easing, fn ) {
-		var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
-			complete: fn || !fn && easing ||
-				jQuery.isFunction( speed ) && speed,
-			duration: speed,
-			easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
-		};
-
-		opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
-			opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
-
-		// normalize opt.queue - true/undefined/null -> "fx"
-		if ( opt.queue == null || opt.queue === true ) {
-			opt.queue = "fx";
-		}
-
-		// Queueing
-		opt.old = opt.complete;
-
-		opt.complete = function( noUnmark ) {
-			if ( jQuery.isFunction( opt.old ) ) {
-				opt.old.call( this );
-			}
-
-			if ( opt.queue ) {
-				jQuery.dequeue( this, opt.queue );
-			} else if ( noUnmark !== false ) {
-				jQuery._unmark( this );
-			}
-		};
-
-		return opt;
-	},
-
-	easing: {
-		linear: function( p, n, firstNum, diff ) {
-			return firstNum + diff * p;
-		},
-		swing: function( p, n, firstNum, diff ) {
-			return ( ( -Math.cos( p*Math.PI ) / 2 ) + 0.5 ) * diff + firstNum;
-		}
-	},
-
-	timers: [],
-
-	fx: function( elem, options, prop ) {
-		this.options = options;
-		this.elem = elem;
-		this.prop = prop;
-
-		options.orig = options.orig || {};
-	}
-
-});
-
-jQuery.fx.prototype = {
-	// Simple function for setting a style value
-	update: function() {
-		if ( this.options.step ) {
-			this.options.step.call( this.elem, this.now, this );
-		}
-
-		( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
-	},
-
-	// Get the current size
-	cur: function() {
-		if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
-			return this.elem[ this.prop ];
-		}
-
-		var parsed,
-			r = jQuery.css( this.elem, this.prop );
-		// Empty strings, null, undefined and "auto" are converted to 0,
-		// complex values such as "rotate(1rad)" are returned as is,
-		// simple values such as "10px" are parsed to Float.
-		return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
-	},
-
-	// Start an animation from one number to another
-	custom: function( from, to, unit ) {
-		var self = this,
-			fx = jQuery.fx;
-
-		this.startTime = fxNow || createFxNow();
-		this.end = to;
-		this.now = this.start = from;
-		this.pos = this.state = 0;
-		this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
-
-		function t( gotoEnd ) {
-			return self.step( gotoEnd );
-		}
-
-		t.queue = this.options.queue;
-		t.elem = this.elem;
-		t.saveState = function() {
-			if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
-				jQuery._data( self.elem, "fxshow" + self.prop, self.start );
-			}
-		};
-
-		if ( t() && jQuery.timers.push(t) && !timerId ) {
-			timerId = setInterval( fx.tick, fx.interval );
-		}
-	},
-
-	// Simple 'show' function
-	show: function() {
-		var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
-
-		// Remember where we started, so that we can go back to it later
-		this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
-		this.options.show = true;
-
-		// Begin the animation
-		// Make sure that we start at a small width/height to avoid any flash of content
-		if ( dataShow !== undefined ) {
-			// This show is picking up where a previous hide or show left off
-			this.custom( this.cur(), dataShow );
-		} else {
-			this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
-		}
-
-		// Start by showing the element
-		jQuery( this.elem ).show();
-	},
-
-	// Simple 'hide' function
-	hide: function() {
-		// Remember where we started, so that we can go back to it later
-		this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
-		this.options.hide = true;
-
-		// Begin the animation
-		this.custom( this.cur(), 0 );
-	},
-
-	// Each step of an animation
-	step: function( gotoEnd ) {
-		var p, n, complete,
-			t = fxNow || createFxNow(),
-			done = true,
-			elem = this.elem,
-			options = this.options;
-
-		if ( gotoEnd || t >= options.duration + this.startTime ) {
-			this.now = this.end;
-			this.pos = this.state = 1;
-			this.update();
-
-			options.animatedProperties[ this.prop ] = true;
-
-			for ( p in options.animatedProperties ) {
-				if ( options.animatedProperties[ p ] !== true ) {
-					done = false;
-				}
-			}
-
-			if ( done ) {
-				// Reset the overflow
-				if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
-
-					jQuery.each( [ "", "X", "Y" ], function( index, value ) {
-						elem.style[ "overflow" + value ] = options.overflow[ index ];
-					});
-				}
-
-				// Hide the element if the "hide" operation was done
-				if ( options.hide ) {
-					jQuery( elem ).hide();
-				}
-
-				// Reset the properties, if the item has been hidden or shown
-				if ( options.hide || options.show ) {
-					for ( p in options.animatedProperties ) {
-						jQuery.style( elem, p, options.orig[ p ] );
-						jQuery.removeData( elem, "fxshow" + p, true );
-						// Toggle data is no longer needed
-						jQuery.removeData( elem, "toggle" + p, true );
-					}
-				}
-
-				// Execute the complete function
-				// in the event that the complete function throws an exception
-				// we must ensure it won't be called twice. #5684
-
-				complete = options.complete;
-				if ( complete ) {
-
-					options.complete = false;
-					complete.call( elem );
-				}
-			}
-
-			return false;
-
-		} else {
-			// classical easing cannot be used with an Infinity duration
-			if ( options.duration == Infinity ) {
-				this.now = t;
-			} else {
-				n = t - this.startTime;
-				this.state = n / options.duration;
-
-				// Perform the easing function, defaults to swing
-				this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
-				this.now = this.start + ( (this.end - this.start) * this.pos );
-			}
-			// Perform the next step of the animation
-			this.update();
-		}
-
-		return true;
-	}
-};
-
-jQuery.extend( jQuery.fx, {
-	tick: function() {
-		var timer,
-			timers = jQuery.timers,
-			i = 0;
-
-		for ( ; i < timers.length; i++ ) {
-			timer = timers[ i ];
-			// Checks the timer has not already been removed
-			if ( !timer() && timers[ i ] === timer ) {
-				timers.splice( i--, 1 );
-			}
-		}
-
-		if ( !timers.length ) {
-			jQuery.fx.stop();
-		}
-	},
-
-	interval: 13,
-
-	stop: function() {
-		clearInterval( timerId );
-		timerId = null;
-	},
-
-	speeds: {
-		slow: 600,
-		fast: 200,
-		// Default speed
-		_default: 400
-	},
-
-	step: {
-		opacity: function( fx ) {
-			jQuery.style( fx.elem, "opacity", fx.now );
-		},
-
-		_default: function( fx ) {
-			if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
-				fx.elem.style[ fx.prop ] = fx.now + fx.unit;
-			} else {
-				fx.elem[ fx.prop ] = fx.now;
-			}
-		}
-	}
-});
-
-// Adds width/height step functions
-// Do not set anything below 0
-jQuery.each([ "width", "height" ], function( i, prop ) {
-	jQuery.fx.step[ prop ] = function( fx ) {
-		jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
-	};
-});
-
-if ( jQuery.expr && jQuery.expr.filters ) {
-	jQuery.expr.filters.animated = function( elem ) {
-		return jQuery.grep(jQuery.timers, function( fn ) {
-			return elem === fn.elem;
-		}).length;
-	};
-}
-
-// Try to restore the default display value of an element
-function defaultDisplay( nodeName ) {
-
-	if ( !elemdisplay[ nodeName ] ) {
-
-		var body = document.body,
-			elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
-			display = elem.css( "display" );
-		elem.remove();
-
-		// If the simple way fails,
-		// get element's real default display by attaching it to a temp iframe
-		if ( display === "none" || display === "" ) {
-			// No iframe to use yet, so create it
-			if ( !iframe ) {
-				iframe = document.createElement( "iframe" );
-				iframe.frameBorder = iframe.width = iframe.height = 0;
-			}
-
-			body.appendChild( iframe );
-
-			// Create a cacheable copy of the iframe document on first call.
-			// IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
-			// document to it; WebKit & Firefox won't allow reusing the iframe document.
-			if ( !iframeDoc || !iframe.createElement ) {
-				iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
-				iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "<!doctype html>" : "" ) + "<html><body>" );
-				iframeDoc.close();
-			}
-
-			elem = iframeDoc.createElement( nodeName );
-
-			iframeDoc.body.appendChild( elem );
-
-			display = jQuery.css( elem, "display" );
-			body.removeChild( iframe );
-		}
-
-		// Store the correct default display
-		elemdisplay[ nodeName ] = display;
-	}
-
-	return elemdisplay[ nodeName ];
-}
-
-
-
-
-var rtable = /^t(?:able|d|h)$/i,
-	rroot = /^(?:body|html)$/i;
-
-if ( "getBoundingClientRect" in document.documentElement ) {
-	jQuery.fn.offset = function( options ) {
-		var elem = this[0], box;
-
-		if ( options ) {
-			return this.each(function( i ) {
-				jQuery.offset.setOffset( this, options, i );
-			});
-		}
-
-		if ( !elem || !elem.ownerDocument ) {
-			return null;
-		}
-
-		if ( elem === elem.ownerDocument.body ) {
-			return jQuery.offset.bodyOffset( elem );
-		}
-
-		try {
-			box = elem.getBoundingClientRect();
-		} catch(e) {}
-
-		var doc = elem.ownerDocument,
-			docElem = doc.documentElement;
-
-		// Make sure we're not dealing with a disconnected DOM node
-		if ( !box || !jQuery.contains( docElem, elem ) ) {
-			return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
-		}
-
-		var body = doc.body,
-			win = getWindow(doc),
-			clientTop  = docElem.clientTop  || body.clientTop  || 0,
-			clientLeft = docElem.clientLeft || body.clientLeft || 0,
-			scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,
-			scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
-			top  = box.top  + scrollTop  - clientTop,
-			left = box.left + scrollLeft - clientLeft;
-
-		return { top: top, left: left };
-	};
-
-} else {
-	jQuery.fn.offset = function( options ) {
-		var elem = this[0];
-
-		if ( options ) {
-			return this.each(function( i ) {
-				jQuery.offset.setOffset( this, options, i );
-			});
-		}
-
-		if ( !elem || !elem.ownerDocument ) {
-			return null;
-		}
-
-		if ( elem === elem.ownerDocument.body ) {
-			return jQuery.offset.bodyOffset( elem );
-		}
-
-		var computedStyle,
-			offsetParent = elem.offsetParent,
-			prevOffsetParent = elem,
-			doc = elem.ownerDocument,
-			docElem = doc.documentElement,
-			body = doc.body,
-			defaultView = doc.defaultView,
-			prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
-			top = elem.offsetTop,
-			left = elem.offsetLeft;
-
-		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
-			if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
-				break;
-			}
-
-			computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
-			top  -= elem.scrollTop;
-			left -= elem.scrollLeft;
-
-			if ( elem === offsetParent ) {
-				top  += elem.offsetTop;
-				left += elem.offsetLeft;
-
-				if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
-					top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
-					left += parseFloat( computedStyle.borderLeftWidth ) || 0;
-				}
-
-				prevOffsetParent = offsetParent;
-				offsetParent = elem.offsetParent;
-			}
-
-			if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
-				top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
-				left += parseFloat( computedStyle.borderLeftWidth ) || 0;
-			}
-
-			prevComputedStyle = computedStyle;
-		}
-
-		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
-			top  += body.offsetTop;
-			left += body.offsetLeft;
-		}
-
-		if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
-			top  += Math.max( docElem.scrollTop, body.scrollTop );
-			left += Math.max( docElem.scrollLeft, body.scrollLeft );
-		}
-
-		return { top: top, left: left };
-	};
-}
-
-jQuery.offset = {
-
-	bodyOffset: function( body ) {
-		var top = body.offsetTop,
-			left = body.offsetLeft;
-
-		if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
-			top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
-			left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
-		}
-
-		return { top: top, left: left };
-	},
-
-	setOffset: function( elem, options, i ) {
-		var position = jQuery.css( elem, "position" );
-
-		// set position first, in-case top/left are set even on static elem
-		if ( position === "static" ) {
-			elem.style.position = "relative";
-		}
-
-		var curElem = jQuery( elem ),
-			curOffset = curElem.offset(),
-			curCSSTop = jQuery.css( elem, "top" ),
-			curCSSLeft = jQuery.css( elem, "left" ),
-			calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
-			props = {}, curPosition = {}, curTop, curLeft;
-
-		// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
-		if ( calculatePosition ) {
-			curPosition = curElem.position();
-			curTop = curPosition.top;
-			curLeft = curPosition.left;
-		} else {
-			curTop = parseFloat( curCSSTop ) || 0;
-			curLeft = parseFloat( curCSSLeft ) || 0;
-		}
-
-		if ( jQuery.isFunction( options ) ) {
-			options = options.call( elem, i, curOffset );
-		}
-
-		if ( options.top != null ) {
-			props.top = ( options.top - curOffset.top ) + curTop;
-		}
-		if ( options.left != null ) {
-			props.left = ( options.left - curOffset.left ) + curLeft;
-		}
-
-		if ( "using" in options ) {
-			options.using.call( elem, props );
-		} else {
-			curElem.css( props );
-		}
-	}
-};
-
-
-jQuery.fn.extend({
-
-	position: function() {
-		if ( !this[0] ) {
-			return null;
-		}
-
-		var elem = this[0],
-
-		// Get *real* offsetParent
-		offsetParent = this.offsetParent(),
-
-		// Get correct offsets
-		offset       = this.offset(),
-		parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
-
-		// Subtract element margins
-		// note: when an element has margin: auto the offsetLeft and marginLeft
-		// are the same in Safari causing offset.left to incorrectly be 0
-		offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
-		offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
-
-		// Add offsetParent borders
-		parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
-		parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
-
-		// Subtract the two offsets
-		return {
-			top:  offset.top  - parentOffset.top,
-			left: offset.left - parentOffset.left
-		};
-	},
-
-	offsetParent: function() {
-		return this.map(function() {
-			var offsetParent = this.offsetParent || document.body;
-			while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
-				offsetParent = offsetParent.offsetParent;
-			}
-			return offsetParent;
-		});
-	}
-});
-
-
-// Create scrollLeft and scrollTop methods
-jQuery.each( ["Left", "Top"], function( i, name ) {
-	var method = "scroll" + name;
-
-	jQuery.fn[ method ] = function( val ) {
-		var elem, win;
-
-		if ( val === undefined ) {
-			elem = this[ 0 ];
-
-			if ( !elem ) {
-				return null;
-			}
-
-			win = getWindow( elem );
-
-			// Return the scroll offset
-			return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
-				jQuery.support.boxModel && win.document.documentElement[ method ] ||
-					win.document.body[ method ] :
-				elem[ method ];
-		}
-
-		// Set the scroll offset
-		return this.each(function() {
-			win = getWindow( this );
-
-			if ( win ) {
-				win.scrollTo(
-					!i ? val : jQuery( win ).scrollLeft(),
-					 i ? val : jQuery( win ).scrollTop()
-				);
-
-			} else {
-				this[ method ] = val;
-			}
-		});
-	};
-});
-
-function getWindow( elem ) {
-	return jQuery.isWindow( elem ) ?
-		elem :
-		elem.nodeType === 9 ?
-			elem.defaultView || elem.parentWindow :
-			false;
-}
-
-
-
-
-// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
-jQuery.each([ "Height", "Width" ], function( i, name ) {
-
-	var type = name.toLowerCase();
-
-	// innerHeight and innerWidth
-	jQuery.fn[ "inner" + name ] = function() {
-		var elem = this[0];
-		return elem ?
-			elem.style ?
-			parseFloat( jQuery.css( elem, type, "padding" ) ) :
-			this[ type ]() :
-			null;
-	};
-
-	// outerHeight and outerWidth
-	jQuery.fn[ "outer" + name ] = function( margin ) {
-		var elem = this[0];
-		return elem ?
-			elem.style ?
-			parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
-			this[ type ]() :
-			null;
-	};
-
-	jQuery.fn[ type ] = function( size ) {
-		// Get window width or height
-		var elem = this[0];
-		if ( !elem ) {
-			return size == null ? null : this;
-		}
-
-		if ( jQuery.isFunction( size ) ) {
-			return this.each(function( i ) {
-				var self = jQuery( this );
-				self[ type ]( size.call( this, i, self[ type ]() ) );
-			});
-		}
-
-		if ( jQuery.isWindow( elem ) ) {
-			// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
-			// 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
-			var docElemProp = elem.document.documentElement[ "client" + name ],
-				body = elem.document.body;
-			return elem.document.compatMode === "CSS1Compat" && docElemProp ||
-				body && body[ "client" + name ] || docElemProp;
-
-		// Get document width or height
-		} else if ( elem.nodeType === 9 ) {
-			// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
-			return Math.max(
-				elem.documentElement["client" + name],
-				elem.body["scroll" + name], elem.documentElement["scroll" + name],
-				elem.body["offset" + name], elem.documentElement["offset" + name]
-			);
-
-		// Get or set width or height on the element
-		} else if ( size === undefined ) {
-			var orig = jQuery.css( elem, type ),
-				ret = parseFloat( orig );
-
-			return jQuery.isNumeric( ret ) ? ret : orig;
-
-		// Set the width or height on the element (default to pixels if value is unitless)
-		} else {
-			return this.css( type, typeof size === "string" ? size : size + "px" );
-		}
-	};
-
-});
-
-
-
-
-// Expose jQuery to the global object
-window.jQuery = window.$ = jQuery;
-
-// Expose jQuery as an AMD module, but only for AMD loaders that
-// understand the issues with loading multiple versions of jQuery
-// in a page that all might call define(). The loader will indicate
-// they have special allowances for multiple jQuery versions by
-// specifying define.amd.jQuery = true. Register as a named module,
-// since jQuery can be concatenated with other files that may use define,
-// but not use a proper concatenation script that understands anonymous
-// AMD modules. A named AMD is safest and most robust way to register.
-// Lowercase jquery is used because AMD module names are derived from
-// file names, and jQuery is normally delivered in a lowercase file name.
-// Do this after creating the global so that if an AMD module wants to call
-// noConflict to hide this version of jQuery, it will work.
-if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
-	define( "jquery", [], function () { return jQuery; } );
-}
-
-
-
-})( window );

+ 0 - 131
unimall-admin-api/src/main/resources/diagram-viewer/js/jquery/jquery.progressbar.js

@@ -1,131 +0,0 @@
-/*
- * @ Dmitry Farafonov
- */
-
-(function($){
-$.ProgressBar = function(options) {
-	this.element = $(options.boundingBox);
-	if (options.on && options.on.complete){
-		this.onComplete = options.on.complete;
-	}
-	if (options.on && options.on.valueChange){
-		this.onValueChange = options.on.valueChange;
-	}
-	
-	this._create();
-	
-	if (options.label)
-		this.set("label", options.label);
-	if (options.value)
-		this.value(options.value);
-	if (options.max)
-		this.set("max", options.max);
-};
-$.ProgressBar.prototype = {
-	options: {
-		value: 0,
-		max: 100
-	},
-
-	min: 0,
-
-	_create: function() {
-		this.element
-			.addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
-			.attr({
-				role: "progressbar",
-				"aria-valuemin": this.min,
-				"aria-valuemax": this.options.max,
-				"aria-valuenow": this._value()
-			});
-
-		this.valueDiv = $( "<div class='ui-progressbar-label'></div>" )
-			.appendTo( this.element );
-			
-		this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
-			.appendTo( this.element );
-
-		this.oldValue = this._value();
-		this._refreshValue();
-	},
-
-	_destroy: function() {
-		this.element
-			.removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
-			.removeAttr( "role" )
-			.removeAttr( "aria-valuemin" )
-			.removeAttr( "aria-valuemax" )
-			.removeAttr( "aria-valuenow" );
-
-		this.valueDiv.remove();
-	},
-
-	value: function( newValue ) {
-		if ( newValue === undefined ) {
-			return this._value();
-		}
-
-		this._setOption( "value", newValue );
-		return this;
-	},
-
-	_setOption: function( key, value ) {
-		if ( key === "value" ) {
-			//var oldVal = this.options.value;
-			this.options.value = value;
-			this._refreshValue();
-			
-			if (this.onValueChange)
-				this.onValueChange.apply(this, [{oldVal: this.oldValue, newVal: value}]);
-			
-			if ( this._value() === this.options.max ) {
-				//this._trigger( "complete" );
-				if (this.onComplete)
-					this.onComplete.apply(this);
-			}
-		} else if (key === "label") {
-			$(this.element).find(".ui-progressbar-label").html(value);
-		} else if (key === "max") {
-			this.options.max = value;
-		}
-
-		//this._super( key, value );
-	},
-
-	_value: function() {
-		var val = this.options.value;
-		// normalize invalid value
-		if ( typeof val !== "number" ) {
-			val = 0;
-		}
-		return Math.min( this.options.max, Math.max( this.min, val ) );
-	},
-
-	_percentage: function() {
-		return 100 * this._value() / this.options.max;
-	},
-
-	_refreshValue: function() {
-		var value = this.value(),
-			percentage = this._percentage();
-
-		if ( this.oldValue !== value ) {
-			this.oldValue = value;
-			//this._trigger( "change" );
-		}
-
-		this.valueDiv
-			.toggle( value > this.min )
-			.toggleClass( "ui-corner-right", value === this.options.max )
-			.width( percentage.toFixed(0) + "%" );
-		this.element.attr( "aria-valuenow", value );
-		
-		//$(this.element).find(".ui-progressbar-label").html(value + "%");
-	},
-	
-	set: function(key, value){
-		this._setOption(key, value);
-	}
-};
-
-})( jQuery );

+ 0 - 23
unimall-admin-api/src/main/resources/diagram-viewer/js/jstools.js

@@ -1,23 +0,0 @@
-if (typeof(console) == "undefined") {
-  var console = {
-    info: function(){},
-    warn: function(){},
-    error: function(){},
-    log: function(){},
-    time: function(){},
-    timeEnd: function(){}
-  };
-}
-
-if(!Array.isArray) {
-  Array.isArray = function (vArg) {
-    return Object.prototype.toString.call(vArg) === "[object Array]";
-  };
-}
-
-if (!Object.isSVGElement) {
-  Object.isSVGElement = function(vArg) {
-  var str = Object.prototype.toString.call(vArg);
-  return (str.indexOf("[object SVG") == 0);
-  };
-}

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff