├── LICENSE ├── README.md ├── pom.xml ├── rest-api.iml └── src ├── main ├── java │ └── com │ │ └── arccode │ │ ├── core │ │ ├── constant │ │ │ ├── BaseConstant.java │ │ │ ├── EmptyObjectConstant.java │ │ │ └── SymbolConstant.java │ │ ├── entity │ │ │ ├── ArcExceptionResponse.java │ │ │ ├── ArcJacksonObjectMapper.java │ │ │ ├── ArcNotFoundException.java │ │ │ ├── ArcResponse.java │ │ │ ├── DateFormat.java │ │ │ └── Meta.java │ │ ├── feature │ │ │ ├── package-info.java │ │ │ └── test │ │ │ │ └── TestSupport.java │ │ └── util │ │ │ ├── ApplicationUtils.java │ │ │ ├── CookieUtils.java │ │ │ ├── DateUtil.java │ │ │ ├── JsonUtil.java │ │ │ ├── PasswordHash.java │ │ │ └── StringUtil.java │ │ └── web │ │ ├── bean │ │ └── SelectBean.java │ │ ├── controller │ │ ├── api │ │ │ ├── CommonAPI.java │ │ │ └── ProductAPI.java │ │ ├── handler │ │ │ └── global │ │ │ │ └── GlobalExceptionHandler.java │ │ └── package-info.java │ │ ├── enums │ │ └── package-info.java │ │ ├── filter │ │ ├── CorsFilter.java │ │ └── package-info.java │ │ ├── interceptors │ │ └── package-info.java │ │ ├── model │ │ └── Product.java │ │ ├── security │ │ └── package-info.java │ │ ├── service │ │ ├── ProductService.java │ │ └── impl │ │ │ └── ProductServiceImpl.java │ │ └── task │ │ └── package-info.java ├── resources │ ├── log4j.properties │ ├── messages.properties │ ├── spring-mvc.xml │ └── spring-root.xml └── webapp │ ├── META-INF │ └── MANIFEST.MF │ ├── WEB-INF │ └── web.xml │ ├── app │ ├── js │ │ └── product │ │ │ └── product.js │ └── lib │ │ ├── bootstrap │ │ ├── css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap.css │ │ │ └── bootstrap.css.map │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ └── js │ │ │ ├── bootstrap.js │ │ │ └── npm.js │ │ ├── jquery │ │ └── jquery.js │ │ ├── requirejs │ │ ├── require.js │ │ ├── require.min.js │ │ └── text.js │ │ ├── superagent │ │ └── superagent.js │ │ ├── underscore │ │ └── underscore.js │ │ └── vue │ │ └── vue.js │ └── index.html └── test └── java └── com └── arccode └── test ├── regexp └── AntPathMatchTest.java └── util ├── DateUtilTest.java └── UuidTest.java /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 arccode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rest-api 2 | 3 | 设计文档 4 | 5 | ## 开发部署 6 | 7 | 1. 从 GitHub 下载(采用 `git clone`方式, 或直接下载`zip`包) 8 | 9 | $ cd your-directory 10 | $ git clone https://github.com/arccode/rest-api 11 | 12 | 2. 将项目导入Java IDE, 笔者使用`IntelliJ IDEA`进行开发, 但项目是标准的`maven`结构, 相信大家均能正确导入. 13 | 14 | 3. 将项目部署至`tomcat`, 笔者习惯将其部署至根目录, 可以在`url`中少敲几个字符. 15 | 16 | 4. 打开浏览器, 输入`http://localhost:8080/index.html`可看到测试页面; 如果未更改部署目录的话, 那你访问的页面可能是`http://localhost:8080/rest-api/index.html`. 17 | 18 | ## 项目运行截图部分 19 | 20 | ![](http://arccode.net/images/arc/arc_add.png) 21 | 22 | ![](http://arccode.net/images/arc/arc_list.png) 23 | 24 | ![](http://arccode.net/images/arc/arc_exception.png) 25 | 26 | 27 | ## 支持 28 | 29 | [联系方式](http://arccode.net/about/) -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.arccode 5 | rest-api 6 | war 7 | 1.0.0 8 | rest-api 9 | 10 | 11 | 12 | UTF-8 13 | zh_CN 14 | 1.6 15 | 16 | 17 | 18 | 3.1 19 | 20 | 21 | 4.11 22 | 4.1.2.RELEASE 23 | 1.6.6 24 | 1.2.12 25 | 4.1.2 26 | 2.5.0 27 | 7.0.53 28 | 1.2 29 | 1.0 30 | 3.1 31 | 1.3.1 32 | 1.9 33 | 3.3 34 | 1.6.12 35 | 5.1.1.Final 36 | 2.1 37 | 38 | 39 | 40 | 41 | 42 | junit 43 | junit 44 | ${junit.version} 45 | 46 | 47 | 48 | 49 | org.springframework 50 | spring-core 51 | ${spring.version} 52 | 53 | 54 | 55 | org.springframework 56 | spring-web 57 | ${spring.version} 58 | 59 | 60 | 61 | org.springframework 62 | spring-oxm 63 | ${spring.version} 64 | 65 | 66 | 67 | org.springframework 68 | spring-tx 69 | ${spring.version} 70 | 71 | 72 | 73 | org.springframework 74 | spring-jdbc 75 | ${spring.version} 76 | 77 | 78 | 79 | org.springframework 80 | spring-webmvc 81 | ${spring.version} 82 | 83 | 84 | 85 | org.springframework 86 | spring-aop 87 | ${spring.version} 88 | 89 | 90 | 91 | org.springframework 92 | spring-context-support 93 | ${spring.version} 94 | 95 | 96 | 97 | org.springframework 98 | spring-test 99 | ${spring.version} 100 | 101 | 102 | 103 | 104 | 105 | 106 | com.fasterxml.jackson.core 107 | jackson-core 108 | ${jackson.version} 109 | 110 | 111 | 112 | 113 | com.fasterxml.jackson.core 114 | jackson-annotations 115 | ${jackson.version} 116 | 117 | 118 | 119 | 120 | com.fasterxml.jackson.core 121 | jackson-databind 122 | ${jackson.version} 123 | 124 | 125 | 126 | 127 | log4j 128 | log4j 129 | ${log4j.version} 130 | 131 | 132 | org.slf4j 133 | slf4j-api 134 | ${slf4j.version} 135 | 136 | 137 | org.slf4j 138 | slf4j-log4j12 139 | ${slf4j.version} 140 | 141 | 142 | 143 | 144 | 145 | javax.servlet 146 | javax.servlet-api 147 | 3.0.1 148 | provided 149 | 150 | 151 | 152 | 153 | javax.servlet 154 | jstl 155 | ${jstl.version} 156 | 157 | 158 | javax.servlet 159 | jsp-api 160 | 2.0 161 | provided 162 | 163 | 164 | javax.servlet 165 | servlet-api 166 | 2.5 167 | 168 | 169 | 170 | 171 | commons-fileupload 172 | commons-fileupload 173 | ${commons.fileupload.version} 174 | 175 | 176 | 177 | org.apache.httpcomponents 178 | httpclient 179 | ${httpclient.version} 180 | 181 | 182 | 183 | commons-codec 184 | commons-codec 185 | ${commons.codec.version} 186 | 187 | 188 | 189 | commons-net 190 | commons-net 191 | ${commons.net.version} 192 | 193 | 194 | 195 | commons-logging 196 | commons-logging 197 | 1.1.3 198 | 199 | 200 | commons-collections 201 | commons-collections 202 | 3.2.1 203 | 204 | 205 | 206 | 207 | 208 | 209 | com.google.collections 210 | google-collections 211 | ${google.collections.version} 212 | 213 | 214 | 215 | 216 | cglib 217 | cglib-nodep 218 | ${cglib.version} 219 | 220 | 221 | 222 | 223 | org.aspectj 224 | aspectjweaver 225 | ${aspectj.version} 226 | 227 | 228 | org.aspectj 229 | aspectjrt 230 | ${aspectj.version} 231 | 232 | 233 | 234 | 235 | org.hibernate 236 | hibernate-validator 237 | ${hibernate.validator.version} 238 | 239 | 240 | 241 | com.alibaba 242 | fastjson 243 | 1.1.46 244 | 245 | 246 | 247 | com.google.code.gson 248 | gson 249 | 2.3.1 250 | 251 | 252 | 253 | 254 | org.quartz-scheduler 255 | quartz 256 | 2.2.1 257 | 258 | 259 | 260 | 261 | net.coobird 262 | thumbnailator 263 | [0.4, 0.5) 264 | 265 | 266 | 267 | 268 | org.springframework.hateoas 269 | spring-hateoas 270 | 0.17.0.RELEASE 271 | 272 | 273 | org.springframework 274 | spring-expression 275 | ${spring.version} 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | org.apache.maven.plugins 284 | maven-compiler-plugin 285 | ${plugin.maven-compiler} 286 | 287 | ${project.build.jdk} 288 | ${project.build.jdk} 289 | ${project.build.sourceEncoding} 290 | 291 | 292 | 293 | 294 | org.apache.maven.plugins 295 | maven-surefire-plugin 296 | 2.5 297 | 298 | 299 | true 300 | 301 | 302 | 303 | 304 | org.apache.maven.plugins 305 | maven-dependency-plugin 306 | ${maven-dependency-plugin.version} 307 | 308 | 309 | copy-installed 310 | install 311 | 312 | copy 313 | 314 | 315 | 316 | 317 | ${project.groupId} 318 | ${project.artifactId} 319 | ${project.version} 320 | ${project.packaging} 321 | 322 | 323 | 324 | /home/outputpackage/${project.name} 325 | false 326 | true 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | src/main/resources 338 | 339 | **/*.properties 340 | **/*.xml 341 | 342 | true 343 | 344 | 345 | src/main/resources/${confDir} 346 | 347 | **/*.properties 348 | **/*.xml 349 | 350 | true 351 | 352 | 353 | src/main/java 354 | 355 | **/*.properties 356 | **/*.xml 357 | 358 | true 359 | 360 | 361 | 362 | 363 | -------------------------------------------------------------------------------- /rest-api.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | file://$MODULE_DIR$/src/main/resources/spring-mvc.xml 23 | 24 | 25 | file://$MODULE_DIR$/src/main/resources/spring-mvc.xml 26 | file://$MODULE_DIR$/src/main/resources/spring-root.xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/constant/BaseConstant.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.constant; 2 | 3 | /** 4 | * BaseConstant : Base常量, 定义最常用的变量, 可供其它常量或方法调用 5 | * 6 | * @author arccode 7 | * @since 2014-12-11 18:51 8 | */ 9 | public class BaseConstant { 10 | 11 | /** 12 | * 单词间隔常量 " " 13 | */ 14 | public final static String WORD_SEPARATOR = Character.toString((char)32); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/constant/EmptyObjectConstant.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.constant; 2 | 3 | /** 4 | * EmptyObjectConstant : 空对象常量 5 | * 6 | * @author arccode 7 | * @since 2014-12-11 18:41 8 | */ 9 | public class EmptyObjectConstant { 10 | 11 | /** 12 | * 空字符串 13 | */ 14 | public final static String EMPTY_STRING = ""; 15 | 16 | /** 17 | * 空对象 18 | */ 19 | public final static Object EMPTY_OBJECT = new Object(); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/constant/SymbolConstant.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.constant; 2 | 3 | /** 4 | * SymbolConstant : 符号常量 5 | * 6 | * @author arccode 7 | * @since 2014-12-20 11:34 8 | */ 9 | public class SymbolConstant { 10 | 11 | /**,*/ 12 | public final static String COMMA = ","; 13 | 14 | public final static String SLASH = "/"; 15 | public final static String BACK_SLASH = "\\"; 16 | /**:*/ 17 | public final static String COLON = ":"; 18 | 19 | /** ; */ 20 | public final static String SEMICOLON = ";"; 21 | 22 | /**[*/ 23 | public final static String SQUARE_BRACKETS_LEFT = "["; 24 | /**]*/ 25 | public final static String SQUARE_BRACKETS_RIGHT = "]"; 26 | 27 | public final static String CURLY_BRACKETS_LEFT = "{"; 28 | public final static String CURLY_BRACKETS_RIGHT = "}"; 29 | /**(*/ 30 | public final static String PARENTHESES_BRACKETS_LEFT = "("; 31 | /**)*/ 32 | public final static String PARENTHESES_BRACKETS_RIGHT = ")"; 33 | 34 | public final static String QUESTION_SIGN = "?"; 35 | public final static String AND_SIGN = "&"; 36 | /** # */ 37 | public final static String POUND = "#"; 38 | /** * */ 39 | public final static String ASTERISK = "*"; 40 | 41 | /** $ */ 42 | public final static String DOLLAR_SIGN = "$"; 43 | 44 | public final static String ELLIPSIS_THREE = "..."; 45 | public final static String ELLIPSIS_SIX = "......"; 46 | 47 | /** = */ 48 | public final static String EQUAL_SIGN = "="; 49 | /**-*/ 50 | public final static String MINUS_SIGN = "-"; 51 | public final static String PLUS_SIGN= "+"; 52 | public final static String MULTIPLICATION_SIGN = "*"; 53 | public final static String PERCENT = "%"; 54 | 55 | /** 56 | * 二十个等号 57 | */ 58 | public final static String EQUAL_TWENTY = " ==================== "; 59 | 60 | public final static String POUND_TWENTY = " #################### "; 61 | 62 | /** 回车换行 **/ 63 | public final static String BR = "\n"; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/entity/ArcExceptionResponse.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.entity; 2 | 3 | /** 4 | * ArcExceptionResponse : 异常响应, 消息将封装至返回json的meta中 5 | * 6 | * @author http://arccode.net 7 | * @since 2015-04-16 16:16 8 | */ 9 | public class ArcExceptionResponse { 10 | 11 | private Meta meta; 12 | 13 | public ArcExceptionResponse() { 14 | } 15 | 16 | public ArcExceptionResponse(Meta meta) { 17 | this.meta = meta; 18 | } 19 | 20 | public static ArcExceptionResponse create(Integer code, String message) { 21 | 22 | Meta exceptionMeta = new Meta(code, message); 23 | 24 | return new ArcExceptionResponse(exceptionMeta); 25 | } 26 | 27 | public Meta getMeta() { 28 | return meta; 29 | } 30 | 31 | public void setMeta(Meta meta) { 32 | this.meta = meta; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/entity/ArcJacksonObjectMapper.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.fasterxml.jackson.databind.SerializationFeature; 7 | 8 | /** 9 | * ArcJaxbJacksonObjectMapper : 禁用Jackson的FAIL_ON_EMPTY_BEANS 10 | * 11 | * @author http://arccode.net 12 | * @since 2015-04-17 00:27 13 | */ 14 | public class ArcJacksonObjectMapper extends ObjectMapper { 15 | 16 | 17 | private static final long serialVersionUID = -6588193192037263348L; 18 | 19 | public ArcJacksonObjectMapper() { 20 | 21 | this.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) 22 | .setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY) 23 | .setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE) 24 | .setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE) 25 | .setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE); 26 | 27 | // 禁用空对象转换json校验 28 | this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/entity/ArcNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.entity; 2 | 3 | /** 4 | * ArcNotFoundException : 查询时如果未查找到相关数据, 抛出该异常 5 | * 6 | * @author http://arccode.net 7 | * @since 2015-04-16 16:49 8 | */ 9 | public class ArcNotFoundException extends RuntimeException { 10 | 11 | private static final long serialVersionUID = 8096927982277821689L; 12 | 13 | public ArcNotFoundException() { 14 | } 15 | 16 | public ArcNotFoundException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/entity/ArcResponse.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.entity; 2 | 3 | import com.arccode.core.constant.EmptyObjectConstant; 4 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | /** 8 | * ArcResponse : 通用响应对象, 封装数据如下 9 | * 10 | * {"meta":{"code":200,"message":"创建成功"},"data":{"id":"5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9","name":"Apple Watch SPORT","description":"Sport 系列的表壳材料为轻巧的银色及深空灰色阳极氧化铝金属,强化 Ion-X 玻璃材质为显示屏提供保护。搭配高性能 Fluoroelastomer 表带,共有 5 款缤纷色彩。"}} 11 | * 12 | * @author http://arccode.net 13 | * @since 2015-04-16 17:47 14 | */ 15 | public class ArcResponse { 16 | 17 | private Meta meta; 18 | 19 | private T data; 20 | 21 | public ArcResponse() { 22 | 23 | } 24 | 25 | public ArcResponse(Meta meta, T data) { 26 | this.meta = meta; 27 | this.data = data; 28 | } 29 | 30 | public ArcResponse(Integer code, String message) { 31 | this.meta = new Meta(code, message); 32 | this.data = (T)new Object(); 33 | } 34 | 35 | public ArcResponse(Integer code, String message, T data) { 36 | this.meta = new Meta(code, message); 37 | this.data = data; 38 | } 39 | 40 | public Meta getMeta() { 41 | return meta; 42 | } 43 | 44 | public void setMeta(Meta meta) { 45 | this.meta = meta; 46 | } 47 | 48 | public T getData() { 49 | return data; 50 | } 51 | 52 | public void setData(T data) { 53 | this.data = data; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/entity/DateFormat.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.entity; 2 | 3 | /** 4 | * DateFormat : 时间类型 5 | * 6 | * @author arccode 7 | * @since 2014-12-11 18:26 8 | */ 9 | public enum DateFormat { 10 | 11 | Date("yyyy-MM-dd"), DateTime("yyyy-MM-dd HH:mm:ss"), DatePath("yyyy/MM/dd"), DatePathSingle("yyyy/M/d"); 12 | 13 | private final String format; 14 | 15 | private DateFormat(String format) { 16 | this.format = format; 17 | } 18 | 19 | public String getFormat() { 20 | return format; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/entity/Meta.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.entity; 2 | 3 | /** 4 | * Meta : 封装返回给前端的metadata 5 | * 6 | * @author http://arccode.net 7 | * @since 2015-04-16 16:04 8 | */ 9 | public class Meta { 10 | 11 | private Integer code; 12 | 13 | private String message; 14 | 15 | public Meta() { 16 | } 17 | 18 | public Meta(Integer code, String message) { 19 | this.code = code; 20 | this.message = message; 21 | } 22 | 23 | public Integer getCode() { 24 | return code; 25 | } 26 | 27 | public void setCode(Integer code) { 28 | this.code = code; 29 | } 30 | 31 | public String getMessage() { 32 | return message; 33 | } 34 | 35 | public void setMessage(String message) { 36 | this.message = message; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/feature/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 功能层 3 | */ 4 | package com.arccode.core.feature; -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/feature/test/TestSupport.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.feature.test; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.test.context.ContextConfiguration; 6 | import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; 7 | 8 | /** 9 | * TestSupport : Spring测试支持,用于测试由Spring 管理的bean,编写测试类时,继承该类 10 | * 11 | * @author arccode 12 | * @since 2014-11-27 13 | */ 14 | @ContextConfiguration(locations = {"classpath*:spring-root.xml"}) 15 | public class TestSupport extends AbstractJUnit4SpringContextTests { 16 | 17 | /** 18 | * 日志 19 | */ 20 | protected Logger logger = LoggerFactory.getLogger(this.getClass()); 21 | 22 | protected long startTime; 23 | protected long endTime; 24 | 25 | /** 26 | * 记录 开始运行时间 27 | * 28 | * @return 29 | */ 30 | protected long start() { 31 | this.startTime = System.currentTimeMillis(); 32 | return startTime; 33 | } 34 | 35 | /** 36 | * 记录 结束运行时间 37 | * 38 | * @return 39 | */ 40 | protected long end() { 41 | this.endTime = System.currentTimeMillis(); 42 | this.log(); 43 | return endTime; 44 | } 45 | 46 | /** 47 | * 输出记录 48 | */ 49 | protected void log() { 50 | String text = "\n开始时间 : " + this.startTime + "\n结束时间 : " + this.endTime + "\n执行时间 : " + (this.endTime - this.startTime); 51 | logger.info(text); 52 | } 53 | } -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/util/ApplicationUtils.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.util; 2 | 3 | import java.util.UUID; 4 | 5 | import org.apache.commons.codec.digest.DigestUtils; 6 | 7 | /** 8 | * ApplicationUtils : 程序工具类,提供大量的便捷方法 9 | * 10 | * @author arccode 11 | * @since 2014-11-27 12 | */ 13 | public class ApplicationUtils { 14 | 15 | /** 16 | * 产生一个36个字符的UUID 17 | * 18 | * @return UUID 19 | */ 20 | public static String randomUUID() { 21 | return UUID.randomUUID().toString(); 22 | } 23 | 24 | /** 25 | * md5加密 26 | * 27 | * @param value 要加密的值 28 | * @return md5加密后的值 29 | */ 30 | public static String md5Hex(String value) { 31 | return DigestUtils.md5Hex(value); 32 | } 33 | 34 | /** 35 | * sha1加密 36 | * 37 | * @param value 要加密的值 38 | * @return sha1加密后的值 39 | */ 40 | public static String sha1Hex(String value) { 41 | return DigestUtils.sha1Hex(value); 42 | } 43 | 44 | /** 45 | * sha256加密 46 | * 47 | * @param value 要加密的值 48 | * @return sha256加密后的值 49 | */ 50 | public static String sha256Hex(String value) { 51 | return DigestUtils.sha256Hex(value); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/util/CookieUtils.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.util; 2 | 3 | import javax.servlet.http.Cookie; 4 | import javax.servlet.http.HttpServletRequest; 5 | import javax.servlet.http.HttpServletResponse; 6 | import java.io.UnsupportedEncodingException; 7 | import java.net.URLDecoder; 8 | import java.net.URLEncoder; 9 | import java.util.ArrayList; 10 | import java.util.Map; 11 | import java.util.Set; 12 | 13 | /** 14 | * CookieUtils : 针对Http Cookie的工具类 15 | * 16 | * @author arccode 17 | * @since 2014-11-27 18 | */ 19 | public class CookieUtils { 20 | 21 | /** 22 | * 设置 Cookie, 过期时间为30分钟 23 | * 24 | * @param name 名称 25 | * @param value 值 26 | */ 27 | public static Cookie setCookie(HttpServletResponse response, String name, String value, String path) { 28 | return addCookie(response, name, value, path, 60 * 30); 29 | } 30 | 31 | /** 32 | * 设置 Cookie, 过期时间自定义 33 | * 34 | * @param name 名称 35 | * @param value 值 36 | * @param maxAge 过期时间, 单位秒 37 | */ 38 | public static Cookie addCookie(HttpServletResponse response, String name, String value, String path, int maxAge) { 39 | Cookie cookie = null; 40 | try { 41 | cookie = new Cookie(name, URLEncoder.encode(value, "UTF-8")); 42 | cookie.setMaxAge(maxAge); 43 | if (null != path) { 44 | cookie.setPath(path); 45 | } 46 | response.addCookie(cookie); 47 | } catch (UnsupportedEncodingException e) { 48 | e.printStackTrace(); 49 | } 50 | return cookie; 51 | } 52 | 53 | 54 | /** 55 | * 设置 Cookies, 过期时间自定义 56 | * 57 | * @param response 响应对象 58 | * @param values 值 59 | * @param path 路径 60 | * @param maxAge 过期时间, 单位秒 61 | * @return Cookies 62 | */ 63 | public static ArrayList addCookies(HttpServletResponse response, Map values, String path, int maxAge) { 64 | Set> entries = values.entrySet(); 65 | ArrayList cookies = new ArrayList(); 66 | try { 67 | for (Map.Entry entry : entries) { 68 | Cookie cookie = new Cookie(entry.getKey(), URLEncoder.encode(entry.getValue(), "UTF-8")); 69 | cookie.setMaxAge(maxAge); 70 | if (null != path) { 71 | cookie.setPath(path); 72 | } 73 | response.addCookie(cookie); 74 | cookies.add(cookie); 75 | } 76 | } catch (UnsupportedEncodingException e) { 77 | e.printStackTrace(); 78 | } 79 | return cookies; 80 | } 81 | 82 | 83 | /** 84 | * 获得指定Cookie的值 85 | * 86 | * @param name 名称 87 | * @return 值 88 | */ 89 | public static String getCookie(HttpServletRequest request, String name) { 90 | return getCookie(request, null, name, false); 91 | } 92 | 93 | /** 94 | * 获得指定Cookie的值,并删除。 95 | * 96 | * @param name 名称 97 | * @return 值 98 | */ 99 | public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name) { 100 | return getCookie(request, response, name, true); 101 | } 102 | 103 | /** 104 | * 获得指定Cookie的值 105 | * 106 | * @param request 请求对象 107 | * @param response 响应对象 108 | * @param name 名字 109 | * @param isRemoved 是否移除 110 | * @return 值 111 | */ 112 | public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name, boolean isRemoved) { 113 | String value = null; 114 | Cookie[] cookies = request.getCookies(); 115 | if (cookies != null) { 116 | for (Cookie cookie : cookies) { 117 | if (cookie.getName().equals(name)) { 118 | try { 119 | value = URLDecoder.decode(cookie.getValue(), "UTF-8"); 120 | } catch (UnsupportedEncodingException e) { 121 | e.printStackTrace(); 122 | } 123 | if (isRemoved) { 124 | cookie.setMaxAge(0); 125 | response.addCookie(cookie); 126 | } 127 | return value; 128 | } 129 | } 130 | } 131 | return value; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/util/DateUtil.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.util; 2 | 3 | import com.arccode.core.constant.SymbolConstant; 4 | import com.arccode.core.entity.DateFormat; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.text.ParseException; 9 | import java.text.SimpleDateFormat; 10 | import java.util.Calendar; 11 | import java.util.Date; 12 | import java.util.Locale; 13 | 14 | /** 15 | * DateUtil : 日期工具类 16 | * 17 | * @author arccode 18 | * @since 2014-12-11 18:22 19 | */ 20 | public class DateUtil { 21 | 22 | private static final Logger logger = LoggerFactory.getLogger(DateUtil.class); 23 | 24 | /** 25 | * 日期类型转字符串 26 | * @param date java.util.Date 27 | * @param dateFormat 格式化格式, 使用自定义的枚举类封装所有格式化类型 28 | * @return 29 | */ 30 | public static String convertDate2String(Date date, DateFormat dateFormat) { 31 | 32 | if(null == date) { 33 | return ""; 34 | } 35 | SimpleDateFormat sdf = new SimpleDateFormat(dateFormat.getFormat()); 36 | String dateStr = sdf.format(date); 37 | return StringUtil.trim2Empty(dateStr); 38 | } 39 | 40 | /** 41 | * 字符串转日期类型 42 | * @param dateStr 43 | * @param dateFormat 44 | * @return 45 | */ 46 | public static Date convertString2Date(String dateStr, DateFormat dateFormat) { 47 | if(null == dateStr || "".equals(dateStr.trim())) { 48 | return new Date(); 49 | } 50 | 51 | SimpleDateFormat sdf = new SimpleDateFormat(dateFormat.getFormat()); 52 | Date result = new Date(); 53 | try { 54 | result = sdf.parse(dateStr); 55 | } catch (ParseException e) { 56 | logger.warn(SymbolConstant.POUND_TWENTY + "字符串日期不合法" + SymbolConstant.COLON 57 | + dateStr 58 | + SymbolConstant.POUND_TWENTY); 59 | } 60 | 61 | return result; 62 | } 63 | 64 | /** 65 | * 获取指定的date, 参看calendar api 66 | * @param field 67 | * @param amount 68 | * @return 69 | */ 70 | public static Date getDefineTime(int field, int amount) { 71 | Calendar calendar = Calendar.getInstance(); 72 | calendar.add(field, amount); 73 | return calendar.getTime(); 74 | } 75 | 76 | /** 77 | * 获取指定日期的起始值, e.g: 2014-11-11 10:11:22 -> 2014-11-11 00:00:00 78 | * @param date 79 | * @return 80 | */ 81 | public static Date getDateStartByDate(Date date) { 82 | 83 | Calendar calendar = Calendar.getInstance(); 84 | calendar.setTime(date); 85 | calendar.set(Calendar.HOUR_OF_DAY, 0); 86 | calendar.set(Calendar.MINUTE, 0); 87 | calendar.set(Calendar.SECOND, 0); 88 | 89 | return calendar.getTime(); 90 | } 91 | 92 | /** 93 | * 获取指定日期的结束值, e.g: 2014-11-11 10:11:22 -> 2014-11-11 23:59:59 94 | * @param date 95 | * @return 96 | */ 97 | public static Date getDateEndByDate(Date date) { 98 | 99 | Calendar calendar = Calendar.getInstance(); 100 | calendar.setTime(date); 101 | calendar.set(Calendar.HOUR_OF_DAY, 23); 102 | calendar.set(Calendar.MINUTE, 59); 103 | calendar.set(Calendar.SECOND, 59); 104 | 105 | return calendar.getTime(); 106 | } 107 | 108 | /** 109 | * 返回当前日期 110 | * @return 111 | */ 112 | public static Date getNow() { 113 | Calendar calendar = Calendar.getInstance(); 114 | return calendar.getTime(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/util/JsonUtil.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.util; 2 | 3 | import com.google.gson.Gson; 4 | 5 | /** 6 | * JsonUtil : Json工具类 7 | * 8 | * @author arccode 9 | * @since 2014-12-19 12:36 10 | */ 11 | public class JsonUtil { 12 | 13 | /** 14 | * Gson 对象 15 | */ 16 | public static Gson gson = new Gson(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/util/PasswordHash.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.util; 2 | 3 | /* 4 | * Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm). 5 | * Copyright (c) 2013, Taylor Hornby 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * 14 | * 2. Redistributions in binary form must reproduce the above copyright notice, 15 | * this list of conditions and the following disclaimer in the documentation 16 | * and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | * PBKDF2 salted password hashing. Author: havoc AT defuse.ca www:
31 | * http://crackstation.net/hashing-security.htm
32 | */ 33 | 34 | import java.security.SecureRandom; 35 | import javax.crypto.spec.PBEKeySpec; 36 | import javax.crypto.SecretKeyFactory; 37 | import java.math.BigInteger; 38 | import java.security.NoSuchAlgorithmException; 39 | import java.security.spec.InvalidKeySpecException; 40 | 41 | /** 42 | * 密码盐渍算法工具类,生成70个字符的密码hash,可以调整SALT_BYTE_SIZE,HASH_BYTE_SIZE来改变 43 | * 44 | *
45 | * how to use: 46 | * 47 | *
 48 |  * String password = "123456";
 49 |  * boolean success = PasswordHash.validatePassword(password, PasswordHash.createHash(password));
 50 |  * 
51 | **/ 52 | public class PasswordHash { 53 | public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1"; 54 | 55 | // The following constants may be changed without breaking existing hashes. 56 | public static final int SALT_BYTE_SIZE = 16; 57 | public static final int HASH_BYTE_SIZE = 16; 58 | public static final int PBKDF2_ITERATIONS = 1000; 59 | 60 | public static final int ITERATION_INDEX = 0; 61 | public static final int SALT_INDEX = 1; 62 | public static final int PBKDF2_INDEX = 2; 63 | 64 | public static final String SEPARATOR = ":"; 65 | 66 | /** 67 | * 加盐处理密码,返回处理后的hash 68 | * 69 | * @param password 70 | * @return 加盐处理后的hash 71 | * @throws NoSuchAlgorithmException 72 | * @throws InvalidKeySpecException 73 | */ 74 | public static String createHash(String password) throws NoSuchAlgorithmException, InvalidKeySpecException { 75 | return createHash(password.toCharArray()); 76 | } 77 | 78 | /** 79 | * 加盐处理密码,返回处理后的hash 80 | * 81 | * @param password 82 | * @return 加盐处理后的hash 83 | * @throws NoSuchAlgorithmException 84 | * @throws InvalidKeySpecException 85 | */ 86 | public static String createHash(char[] password) throws NoSuchAlgorithmException, InvalidKeySpecException { 87 | // Generate a random salt 88 | SecureRandom random = new SecureRandom(); 89 | byte[] salt = new byte[SALT_BYTE_SIZE]; 90 | random.nextBytes(salt); 91 | 92 | // Hash the password 93 | byte[] hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE); 94 | // format iterations:salt:hash 95 | return PBKDF2_ITERATIONS + SEPARATOR + toHex(salt) + SEPARATOR + toHex(hash); 96 | } 97 | 98 | /** 99 | * 验证密码与 盐渍hash 是否匹配 100 | *

101 | * return true 表示匹配,反之则false 102 | *

103 | * 104 | * @param password 105 | * @param correctHash 106 | * @return 107 | * @throws NoSuchAlgorithmException 108 | * @throws InvalidKeySpecException 109 | */ 110 | public static boolean validatePassword(String password, String correctHash) throws NoSuchAlgorithmException, InvalidKeySpecException { 111 | return validatePassword(password.toCharArray(), correctHash); 112 | } 113 | 114 | /** 115 | * 验证密码与 盐渍hash 是否匹配 116 | *

117 | * return true 表示匹配,反之则false 118 | *

119 | * 120 | * @param password 121 | * @param correctHash 122 | * @return 123 | * @throws NoSuchAlgorithmException 124 | * @throws InvalidKeySpecException 125 | */ 126 | public static boolean validatePassword(char[] password, String correctHash) throws NoSuchAlgorithmException, InvalidKeySpecException { 127 | // Decode the hash into its parameters 128 | String[] params = correctHash.split(SEPARATOR); 129 | int iterations = Integer.parseInt(params[ITERATION_INDEX]); 130 | byte[] salt = fromHex(params[SALT_INDEX]); 131 | byte[] hash = fromHex(params[PBKDF2_INDEX]); 132 | // Compute the hash of the provided password, using the same salt, 133 | // iteration count, and hash length 134 | byte[] testHash = pbkdf2(password, salt, iterations, hash.length); 135 | // Compare the hashes in constant time. The password is correct if 136 | // both hashes match. 137 | return slowEquals(hash, testHash); 138 | } 139 | 140 | /** 141 | * Compares two byte arrays in length-constant time. This comparison method 142 | * is used so that password hashes cannot be extracted from an on-line 143 | * system using a timing attack and then attacked off-line. 144 | * 145 | * @param a 146 | * the first byte array 147 | * @param b 148 | * the second byte array 149 | * @return true if both byte arrays are the same, false if not 150 | */ 151 | private static boolean slowEquals(byte[] a, byte[] b) { 152 | int diff = a.length ^ b.length; 153 | for (int i = 0; i < a.length && i < b.length; i++) 154 | diff |= a[i] ^ b[i]; 155 | return diff == 0; 156 | } 157 | 158 | /** 159 | * Computes the PBKDF2 hash of a password. 160 | * 161 | * @param password 162 | * the password to hash. 163 | * @param salt 164 | * the salt 165 | * @param iterations 166 | * the iteration count (slowness factor) 167 | * @param bytes 168 | * the length of the hash to compute in bytes 169 | * @return the PBDKF2 hash of the password 170 | */ 171 | private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes) throws NoSuchAlgorithmException, InvalidKeySpecException { 172 | PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8); 173 | SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM); 174 | return skf.generateSecret(spec).getEncoded(); 175 | } 176 | 177 | /** 178 | * Converts a string of hexadecimal characters into a byte array. 179 | * 180 | * @param hex 181 | * the hex string 182 | * @return the hex string decoded into a byte array 183 | */ 184 | private static byte[] fromHex(String hex) { 185 | byte[] binary = new byte[hex.length() / 2]; 186 | for (int i = 0; i < binary.length; i++) { 187 | binary[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16); 188 | } 189 | return binary; 190 | } 191 | 192 | /** 193 | * Converts a byte array into a hexadecimal string. 194 | * 195 | * @param array 196 | * the byte array to convert 197 | * @return a length*2 character string encoding the byte array 198 | */ 199 | private static String toHex(byte[] array) { 200 | BigInteger bi = new BigInteger(1, array); 201 | String hex = bi.toString(16); 202 | int paddingLength = (array.length * 2) - hex.length(); 203 | if (paddingLength > 0) 204 | return String.format("%0" + paddingLength + "d", 0) + hex; 205 | else 206 | return hex; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/core/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package com.arccode.core.util; 2 | 3 | 4 | import com.arccode.core.constant.BaseConstant; 5 | 6 | /** 7 | * StringUtil : 字符串工具类 8 | * 9 | * @author arccode 10 | * @since 2014-12-11 18:43 11 | */ 12 | public class StringUtil { 13 | 14 | /** 15 | * 返回去除首尾空格的字符串 16 | * @param str 17 | * @return 18 | */ 19 | public static String trim2Empty(String str) { 20 | if(null == str || str.isEmpty()) { 21 | return ""; 22 | } 23 | if(str.equals(BaseConstant.WORD_SEPARATOR)) { 24 | return str; 25 | } 26 | return str.trim(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/bean/SelectBean.java: -------------------------------------------------------------------------------- 1 | package com.arccode.web.bean; 2 | 3 | /** 4 | * SelectBean : 批量提供Select数据, 为前端Select元素提供数据 5 | * 6 | * @author http://arccode.net 7 | * @since 2015-04-16 11:43 8 | */ 9 | public class SelectBean { 10 | 11 | /** 12 | * Select中的value 13 | */ 14 | private String value; 15 | 16 | /** 17 | * Select中显示的文本 18 | */ 19 | private String text; 20 | 21 | public SelectBean() { 22 | } 23 | 24 | public SelectBean(String value, String text) { 25 | this.value = value; 26 | this.text = text; 27 | } 28 | 29 | public String getValue() { 30 | return value; 31 | } 32 | 33 | public void setValue(String value) { 34 | this.value = value; 35 | } 36 | 37 | public String getText() { 38 | return text; 39 | } 40 | 41 | public void setText(String text) { 42 | this.text = text; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/controller/api/CommonAPI.java: -------------------------------------------------------------------------------- 1 | package com.arccode.web.controller.api; 2 | 3 | import com.arccode.web.bean.SelectBean; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestMethod; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * CommonAPI : 用于地址等数据的下发 14 | * 15 | * @author http://arccode.net 16 | * @since 2015-04-16 11:41 17 | */ 18 | @Controller 19 | @RequestMapping("/api") 20 | public class CommonAPI { 21 | 22 | 23 | @RequestMapping(value = "/selects", method = RequestMethod.GET) 24 | @ResponseBody 25 | public List selects() { 26 | 27 | List selectBeans = new ArrayList(); 28 | SelectBean addBean = new SelectBean("/rest/api/product", "新增商品"); 29 | selectBeans.add(addBean); 30 | SelectBean getBean = new SelectBean("/rest/api/products/5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9", "获取商品详情"); 31 | selectBeans.add(getBean); 32 | SelectBean modifyBean = new SelectBean("/rest/api/products/5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9", "修改商品"); 33 | selectBeans.add(modifyBean); 34 | SelectBean removeBean = new SelectBean("/rest/api/products/5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9", "删除商品"); 35 | selectBeans.add(removeBean); 36 | SelectBean beans = new SelectBean("/rest/api/products", "获取所有商品"); 37 | selectBeans.add(beans); 38 | 39 | SelectBean starBean = new SelectBean("/rest/api/products/5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9/star", "收藏商品"); 40 | selectBeans.add(starBean); 41 | SelectBean unStarBean = new SelectBean("/rest/api/products/5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9/star", "删除收藏商品"); 42 | selectBeans.add(unStarBean); 43 | 44 | return selectBeans; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/controller/api/ProductAPI.java: -------------------------------------------------------------------------------- 1 | package com.arccode.web.controller.api; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.arccode.core.entity.ArcResponse; 5 | import com.arccode.web.model.Product; 6 | import com.arccode.web.service.ProductService; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.web.bind.annotation.*; 12 | 13 | import javax.annotation.Resource; 14 | import java.util.List; 15 | 16 | /** 17 | * ProductAPI : 商品数据api 18 | * 19 | * @author http://arccode.net 20 | * @since 2015-04-16 10:58 21 | */ 22 | @Controller 23 | @RequestMapping("/api") 24 | public class ProductAPI { 25 | 26 | private final Logger logger = LoggerFactory.getLogger(ProductAPI.class); 27 | 28 | @Resource 29 | private ProductService productService; 30 | 31 | 32 | ////////////////////////////////////////// 33 | //商品api数据接口 34 | ////////////////////////////////////////// 35 | 36 | /** 37 | * 新增商品 38 | * @param product 39 | * @return 40 | */ 41 | @RequestMapping(value = "/product", method = RequestMethod.POST) 42 | @ResponseBody 43 | public ArcResponse addProduct(@RequestBody Product product) { 44 | 45 | productService.addModel(product); 46 | 47 | // 包装返回的数据 48 | return new ArcResponse(HttpStatus.CREATED.value(), "创建成功", product); 49 | } 50 | 51 | /** 52 | * 获取单个商品详情 53 | * @param id 54 | * @return 55 | */ 56 | @RequestMapping(value = "/products/{id}", method = RequestMethod.GET) 57 | @ResponseBody 58 | public ArcResponse product(@PathVariable("id") String id) { 59 | 60 | Product product = productService.getModelById(id); 61 | 62 | return new ArcResponse(HttpStatus.OK.value(), "查询成功", product); 63 | } 64 | 65 | /** 66 | * 编辑产品 67 | * @param id 68 | * @param product 69 | * @return 70 | */ 71 | @RequestMapping(value = "/products/{id}", method = RequestMethod.PUT) 72 | @ResponseBody 73 | public ArcResponse modifyProduct(@PathVariable("id") String id, 74 | @RequestBody Product product) { 75 | 76 | product.setId(id); 77 | Product result = productService.modifyModelById(product); 78 | 79 | return new ArcResponse(HttpStatus.OK.value(), "修改成功", result); 80 | } 81 | 82 | /** 83 | * 删除商品 84 | * @param id 85 | * @return 86 | */ 87 | @RequestMapping(value = "/products/{id}", method = RequestMethod.DELETE) 88 | @ResponseBody 89 | public ArcResponse removeProduct(@PathVariable("id") String id) { 90 | 91 | productService.removeModelById(id); 92 | 93 | ArcResponse arc = new ArcResponse(HttpStatus.NO_CONTENT.value(), "删除成功"); 94 | 95 | return arc; 96 | } 97 | 98 | /** 99 | * 获取所有商品 100 | * @return 101 | */ 102 | @RequestMapping(value = "/products", method = RequestMethod.GET) 103 | @ResponseBody 104 | public ArcResponse products() { 105 | 106 | List products = productService.getModels(); 107 | 108 | ArcResponse arc = new ArcResponse(HttpStatus.OK.value(), "获取全部商品成功", products); 109 | 110 | return arc; 111 | } 112 | 113 | ////////////////////////////////////////// 114 | //用户商品关系api数据接口 115 | ////////////////////////////////////////// 116 | 117 | /** 118 | * 收藏商品, 返回收藏列表 119 | * @param id 120 | * @return 121 | */ 122 | @RequestMapping(value = "/products/{id}/star", method = RequestMethod.PUT) 123 | @ResponseBody 124 | public ArcResponse star(@PathVariable("id") String id) { 125 | 126 | List products = productService.starProduct(id); 127 | 128 | ArcResponse arc = new ArcResponse(HttpStatus.OK.value(), "收藏商品[" + id +"]成功", products); 129 | 130 | return arc; 131 | } 132 | 133 | /** 134 | * 删除收藏商品, 返回收藏列表 135 | * @param id 136 | * @return 137 | */ 138 | @RequestMapping(value = "/products/{id}/star", method = RequestMethod.DELETE) 139 | @ResponseBody 140 | public ArcResponse unStar(@PathVariable("id") String id) { 141 | 142 | List products = productService.unStarProduct(id); 143 | 144 | ArcResponse arc = new ArcResponse(HttpStatus.OK.value(), "删除收藏商品[" + id +"]成功", products); 145 | 146 | return arc; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/controller/handler/global/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.arccode.web.controller.handler.global; 2 | 3 | import com.arccode.core.entity.ArcExceptionResponse; 4 | import com.arccode.core.entity.ArcNotFoundException; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.web.HttpRequestMethodNotSupportedException; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.ResponseBody; 10 | import org.springframework.web.bind.annotation.ResponseStatus; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | 14 | /** 15 | * GlobalExceptionHandler : 全局异常处理, 通用的异常在此进行处理, 例如: http method不匹配(405), 用户为未认证(401), 用户未获取到授权(403) 16 | * 所有异常均向上抛, 统一在controller层进行处理 17 | * 18 | * @author http://arccode.net 19 | * @since 2015-04-16 16:21 20 | */ 21 | @ControllerAdvice 22 | public class GlobalExceptionHandler { 23 | 24 | /** 25 | * 处理Http method使用不正确的错误, 例如: 新增产品应该使用POST, 但实际使用了GET 26 | * @param req 27 | * @param ex 28 | * @return 29 | */ 30 | @ExceptionHandler(HttpRequestMethodNotSupportedException.class) 31 | @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) 32 | @ResponseBody 33 | public ArcExceptionResponse handleHttp405Exception(HttpServletRequest req, Exception ex) { 34 | 35 | return ArcExceptionResponse.create(HttpStatus.METHOD_NOT_ALLOWED.value(), ex.getMessage()); 36 | } 37 | 38 | /** 39 | * 处理未发现的异常,比如用户名不存在, 产品不存在等等, 抛出http status 404 40 | * @param req 41 | * @param ex 42 | * @return 43 | */ 44 | @ExceptionHandler(ArcNotFoundException.class) 45 | @ResponseStatus(HttpStatus.NOT_FOUND) 46 | @ResponseBody 47 | public ArcExceptionResponse handleNotFoundException(HttpServletRequest req, Exception ex) { 48 | 49 | return ArcExceptionResponse.create(HttpStatus.NOT_FOUND.value(), ex.getMessage()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/controller/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 控制器层 : controller 3 | * router中存放页面映射, api中提供数据接口, 做路由映射 4 | */ 5 | package com.arccode.web.controller; -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/enums/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 枚举类型层 3 | */ 4 | package com.arccode.web.enums; -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/filter/CorsFilter.java: -------------------------------------------------------------------------------- 1 | package com.arccode.web.filter; 2 | 3 | import org.springframework.context.annotation.ComponentScan; 4 | import org.springframework.stereotype.Component; 5 | 6 | import javax.servlet.*; 7 | import javax.servlet.http.HttpServletResponse; 8 | import java.io.IOException; 9 | 10 | /** 11 | * CrosFilter : 跨域资源共享过滤器, 该过滤器设置response header, 解决跨域ajax请求报错 12 | * 13 | * @author arccode 14 | * @since 2014-12-07 22:04 15 | */ 16 | @Component 17 | public class CorsFilter implements Filter { 18 | 19 | @Override 20 | public void init(FilterConfig filterConfig) throws ServletException { 21 | 22 | } 23 | 24 | @Override 25 | public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 26 | 27 | HttpServletResponse response = (HttpServletResponse)res; 28 | // 允许所有域进行访问 29 | response.setHeader("Access-Control-Allow-Origin", "*"); 30 | // 允许的方法 31 | response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,OPTIONS"); 32 | response.setHeader("Access-Control-Max-Age", "3600"); 33 | response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Cache-Control"); 34 | chain.doFilter(req, res); 35 | } 36 | 37 | @Override 38 | public void destroy() { 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/filter/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 过滤器层 3 | */ 4 | package com.arccode.web.filter; -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/interceptors/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 拦截器层 3 | */ 4 | package com.arccode.web.interceptors; -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/model/Product.java: -------------------------------------------------------------------------------- 1 | package com.arccode.web.model; 2 | 3 | /** 4 | * Product : 商品实体, 主要用于ORM 5 | * 6 | * @author http://arccode.net 7 | * @since 2015-04-16 11:03 8 | */ 9 | public class Product { 10 | 11 | private String id; 12 | private String name; 13 | private String description; 14 | 15 | public Product() { 16 | } 17 | 18 | public String getId() { 19 | return id; 20 | } 21 | 22 | public void setId(String id) { 23 | this.id = id; 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public void setName(String name) { 31 | this.name = name; 32 | } 33 | 34 | public String getDescription() { 35 | return description; 36 | } 37 | 38 | public void setDescription(String description) { 39 | this.description = description; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/security/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 安全层 3 | */ 4 | package com.arccode.web.security; -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.arccode.web.service; 2 | 3 | import com.arccode.web.model.Product; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * ProductService : 商品业务接口 9 | * 10 | * @author http://arccode.net 11 | * @since 2015-04-16 10:59 12 | */ 13 | public interface ProductService { 14 | 15 | /** 16 | * 添加商品 17 | * @param product 18 | * @return 19 | */ 20 | Product addModel(Product product); 21 | 22 | /** 23 | * 查看单个商品详情 24 | * @param id 25 | * @return 26 | */ 27 | Product getModelById(String id); 28 | 29 | /** 30 | * 修改产品 31 | * @param product 32 | * @return 33 | */ 34 | Product modifyModelById(Product product); 35 | 36 | /** 37 | * 删除指定产品 38 | * @param id 39 | */ 40 | void removeModelById(String id); 41 | 42 | /** 43 | * 获取所有商品 44 | * @return 45 | */ 46 | List getModels(); 47 | 48 | /************** 收藏业务 **************/ 49 | 50 | /** 51 | * 收藏商品 52 | * @param id 53 | * @return 54 | */ 55 | List starProduct(String id); 56 | 57 | /** 58 | * 解除收藏商品 59 | * @param id 60 | * @return 61 | */ 62 | List unStarProduct(String id); 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/service/impl/ProductServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.arccode.web.service.impl; 2 | 3 | import com.arccode.core.entity.ArcNotFoundException; 4 | import com.arccode.core.util.ApplicationUtils; 5 | import com.arccode.web.model.Product; 6 | import com.arccode.web.service.ProductService; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * ProductServiceImpl : 商品业务接口实现 16 | * 17 | * @author http://arccode.net 18 | * @since 2015-04-16 11:00 19 | */ 20 | @Service 21 | public class ProductServiceImpl implements ProductService { 22 | 23 | private final Logger logger = LoggerFactory.getLogger(ProductServiceImpl.class); 24 | 25 | // 临时存储商品列表, 模拟db中的表 26 | private List products = new ArrayList(); 27 | 28 | // 收藏的商品, 模拟db中关联查出的收藏商品 29 | private List stars = new ArrayList(); 30 | 31 | @Override 32 | public Product addModel(Product product) { 33 | 34 | // 生成id 35 | String id = ""; 36 | if(products.size() >= 1) { 37 | id = ApplicationUtils.randomUUID(); 38 | } else { 39 | id = "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9"; 40 | } 41 | product.setId(id); 42 | products.add(product); 43 | 44 | return product; 45 | } 46 | 47 | @Override 48 | public Product getModelById(String id) { 49 | 50 | Product product = null; 51 | 52 | for (Product item: products) { 53 | if(item.getId().equals(id)) { 54 | product = item; 55 | break; 56 | } 57 | } 58 | 59 | if(product == null) { 60 | throw new ArcNotFoundException("指定产品不存在"); 61 | } 62 | 63 | return product; 64 | } 65 | 66 | @Override 67 | public Product modifyModelById(Product product) { 68 | 69 | boolean flag = false; 70 | 71 | for (Product item: products) { 72 | if(item.getId().equals(product.getId())) { 73 | item.setName(product.getName()); 74 | item.setDescription(product.getDescription()); 75 | product = item; 76 | flag = true; 77 | } 78 | } 79 | 80 | if (!flag) { 81 | throw new ArcNotFoundException("id为[" + product.getId() +"]的商品不存在"); 82 | } 83 | 84 | return product; 85 | } 86 | 87 | @Override 88 | public void removeModelById(String id) { 89 | 90 | Product toBeRemove = null; 91 | 92 | for (Product item: products) { 93 | if(item.getId().equals(id)) { 94 | toBeRemove = item; 95 | } 96 | } 97 | 98 | if (toBeRemove == null) { 99 | throw new ArcNotFoundException("id为[" + id +"]的商品不存在"); 100 | } 101 | 102 | products.remove(toBeRemove); 103 | 104 | } 105 | 106 | @Override 107 | public List getModels() { 108 | return products; 109 | } 110 | 111 | @Override 112 | public List starProduct(String id) { 113 | 114 | for(Product item: products) { 115 | if (id.equals(item.getId())) { 116 | stars.add(item); 117 | } 118 | } 119 | return stars; 120 | } 121 | 122 | @Override 123 | public List unStarProduct(String id) { 124 | 125 | Product toBeUnStar = null; 126 | 127 | for(Product item: products) { 128 | if (id.equals(item.getId())) { 129 | toBeUnStar = item; 130 | } 131 | } 132 | 133 | if (toBeUnStar == null) { 134 | throw new ArcNotFoundException("id为[" + id +"]的商品不存在"); 135 | } 136 | 137 | stars.remove(toBeUnStar); 138 | 139 | return stars; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/com/arccode/web/task/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * package-info : 定时任务 3 | * 4 | * @author arccode 5 | * @since 2014-12-24 11:18 6 | */ 7 | package com.arccode.web.task; -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # DEBUG,INFO,WARN,ERROR,FATAL 2 | LOG_LEVEL=INFO 3 | 4 | log4j.rootLogger=${LOG_LEVEL},CONSOLE,FILE 5 | 6 | # mybatis日志配置 7 | log4j.logger.com.zd.bop.web.dao=DEBUG 8 | 9 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 10 | log4j.appender.CONSOLE.Encoding=utf-8 11 | log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout 12 | #log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss} %C{8}@(%F:%L):%m%n 13 | log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH\:mm\:ss} %C{1}@(%F\:%L)\:%m%n 14 | 15 | log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender 16 | log4j.appender.FILE.File=/home/ad/logs/qtbop.log 17 | log4j.appender.FILE.Encoding=utf-8 18 | log4j.appender.FILE.DatePattern='.'yyyy-MM-dd 19 | log4j.appender.FILE.layout=org.apache.log4j.PatternLayout 20 | #log4j.appender.FILE.layout=org.apache.log4j.HTMLLayout 21 | log4j.appender.FILE.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH\:mm\:ss} %C{8}@(%F\:%L)\:%m%n 22 | 23 | -------------------------------------------------------------------------------- /src/main/resources/messages.properties: -------------------------------------------------------------------------------- 1 | #user 2 | user.username.null=用户名不能为空 3 | user.password.null=密码不能为空 -------------------------------------------------------------------------------- /src/main/resources/spring-mvc.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | text/plain;charset=UTF-8 26 | application/json;charset=UTF-8 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/main/resources/spring-root.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/webapp/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Class-Path: 3 | 4 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | contextConfigLocation 8 | 9 | classpath*:spring-root.xml 10 | 11 | 12 | 13 | 14 | 15 | org.springframework.web.context.ContextLoaderListener 16 | 17 | 18 | 19 | 20 | corsFilter 21 | com.arccode.web.filter.CorsFilter 22 | 23 | 24 | corsFilter 25 | /* 26 | 27 | 28 | 29 | 30 | dispatcher 31 | org.springframework.web.servlet.DispatcherServlet 32 | 33 | contextConfigLocation 34 | classpath:spring-mvc.xml 35 | 36 | 1 37 | 38 | 39 | dispatcher 40 | 41 | /rest/* 42 | 43 | 44 | 45 | 46 | index.html 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/main/webapp/app/js/product/product.js: -------------------------------------------------------------------------------- 1 | /** 2 | * product.js : 商品操作 3 | * 4 | * @author arccode 5 | * @since 2015-04-16 11:17 6 | */ 7 | $(function () { 8 | 9 | //使用superagent.js 执行AJAX请求 10 | var req = window.superagent; 11 | 12 | /** 13 | * 使用vue.js 执行ViewModel数据双向绑定 14 | * 15 | * el: 绑定的作用域 16 | * events: vue事件, 可使用$emit触发 17 | * methods: dom事件 18 | * 19 | * @type {Vue} 20 | */ 21 | var vm = new Vue({ 22 | el: '#root', 23 | data: { 24 | method: 'POST', 25 | urls: null, 26 | url: null, 27 | request: null, 28 | response: null 29 | }, 30 | ready: function () { 31 | 32 | this.$emit('init'); 33 | }, 34 | events: { 35 | 36 | submit: function() { 37 | 38 | if(vm.method == 'GET') { 39 | 40 | vm.request = null; 41 | vm.response = null; 42 | 43 | req 44 | .get(vm.url) 45 | .end(function (err, res) { 46 | vm.response = res.text; 47 | }) 48 | } else if(vm.method == 'POST') { 49 | 50 | vm.request = null; 51 | vm.response = null; 52 | 53 | var product = {name: 'Apple Watch SPORT', description: 'Sport 系列的表壳材料为轻巧的银色及深空灰色阳极氧化铝金属,强化 Ion-X 玻璃材质为显示屏提供保护。搭配高性能 Fluoroelastomer 表带,共有 5 款缤纷色彩。'} 54 | vm.request = JSON.stringify(product); 55 | req 56 | .post(vm.url) 57 | .set('Content-Type', 'application/json') 58 | .send(JSON.stringify(product)) 59 | .end(function (err, res) { 60 | vm.response = res.text; 61 | }) 62 | } else if(vm.method == 'PUT') { 63 | 64 | vm.request = null; 65 | vm.response = null; 66 | 67 | var product = {name: 'iPhone 6', description: '此次苹果发布会发布了iPhone 6与iPhone 6 Plus,搭载iOS 8,尺寸分别是4.7和5.5英寸。外观设计不再棱角分明,表层玻璃边有一个弧度向下延伸,与阳极氧化铝金属机身边框衔接。机身背部采用三段式设计。机身更薄,续航能力更强。'} 68 | vm.request = JSON.stringify(product); 69 | req 70 | .put(vm.url) 71 | .set('Content-Type', 'application/json') 72 | .send(JSON.stringify(product)) 73 | .end(function (err, res) { 74 | vm.response = res.text; 75 | }) 76 | } else if(vm.method == 'DELETE') { 77 | 78 | vm.request = null; 79 | vm.response = null; 80 | 81 | req 82 | .del(vm.url) 83 | .end(function (err, res) { 84 | vm.response = res.text; 85 | }) 86 | } 87 | 88 | }, 89 | // 初始化数据 90 | init: function() { 91 | req 92 | .get('/rest/api/selects') 93 | .end(function (res) { 94 | var obj = JSON.parse(res.text); 95 | vm.urls = obj; 96 | vm.url = obj[0].value; 97 | }) 98 | } 99 | }, 100 | methods: { 101 | onSubmit: function() { 102 | this.$emit('submit'); 103 | } 104 | } 105 | }) 106 | 107 | }) 108 | 109 | -------------------------------------------------------------------------------- /src/main/webapp/app/lib/bootstrap/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.4 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default, 8 | .btn-primary, 9 | .btn-success, 10 | .btn-info, 11 | .btn-warning, 12 | .btn-danger { 13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 16 | } 17 | .btn-default:active, 18 | .btn-primary:active, 19 | .btn-success:active, 20 | .btn-info:active, 21 | .btn-warning:active, 22 | .btn-danger:active, 23 | .btn-default.active, 24 | .btn-primary.active, 25 | .btn-success.active, 26 | .btn-info.active, 27 | .btn-warning.active, 28 | .btn-danger.active { 29 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 31 | } 32 | .btn-default .badge, 33 | .btn-primary .badge, 34 | .btn-success .badge, 35 | .btn-info .badge, 36 | .btn-warning .badge, 37 | .btn-danger .badge { 38 | text-shadow: none; 39 | } 40 | .btn:active, 41 | .btn.active { 42 | background-image: none; 43 | } 44 | .btn-default { 45 | text-shadow: 0 1px 0 #fff; 46 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 47 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 48 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 49 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 50 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 51 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 52 | background-repeat: repeat-x; 53 | border-color: #dbdbdb; 54 | border-color: #ccc; 55 | } 56 | .btn-default:hover, 57 | .btn-default:focus { 58 | background-color: #e0e0e0; 59 | background-position: 0 -15px; 60 | } 61 | .btn-default:active, 62 | .btn-default.active { 63 | background-color: #e0e0e0; 64 | border-color: #dbdbdb; 65 | } 66 | .btn-default.disabled, 67 | .btn-default:disabled, 68 | .btn-default[disabled] { 69 | background-color: #e0e0e0; 70 | background-image: none; 71 | } 72 | .btn-primary { 73 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); 74 | background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); 75 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); 76 | background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); 77 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); 78 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 79 | background-repeat: repeat-x; 80 | border-color: #245580; 81 | } 82 | .btn-primary:hover, 83 | .btn-primary:focus { 84 | background-color: #265a88; 85 | background-position: 0 -15px; 86 | } 87 | .btn-primary:active, 88 | .btn-primary.active { 89 | background-color: #265a88; 90 | border-color: #245580; 91 | } 92 | .btn-primary.disabled, 93 | .btn-primary:disabled, 94 | .btn-primary[disabled] { 95 | background-color: #265a88; 96 | background-image: none; 97 | } 98 | .btn-success { 99 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 100 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 101 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 102 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 103 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 104 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 105 | background-repeat: repeat-x; 106 | border-color: #3e8f3e; 107 | } 108 | .btn-success:hover, 109 | .btn-success:focus { 110 | background-color: #419641; 111 | background-position: 0 -15px; 112 | } 113 | .btn-success:active, 114 | .btn-success.active { 115 | background-color: #419641; 116 | border-color: #3e8f3e; 117 | } 118 | .btn-success.disabled, 119 | .btn-success:disabled, 120 | .btn-success[disabled] { 121 | background-color: #419641; 122 | background-image: none; 123 | } 124 | .btn-info { 125 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 126 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 127 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 128 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 129 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 130 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 131 | background-repeat: repeat-x; 132 | border-color: #28a4c9; 133 | } 134 | .btn-info:hover, 135 | .btn-info:focus { 136 | background-color: #2aabd2; 137 | background-position: 0 -15px; 138 | } 139 | .btn-info:active, 140 | .btn-info.active { 141 | background-color: #2aabd2; 142 | border-color: #28a4c9; 143 | } 144 | .btn-info.disabled, 145 | .btn-info:disabled, 146 | .btn-info[disabled] { 147 | background-color: #2aabd2; 148 | background-image: none; 149 | } 150 | .btn-warning { 151 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 152 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 153 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 154 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 155 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 156 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 157 | background-repeat: repeat-x; 158 | border-color: #e38d13; 159 | } 160 | .btn-warning:hover, 161 | .btn-warning:focus { 162 | background-color: #eb9316; 163 | background-position: 0 -15px; 164 | } 165 | .btn-warning:active, 166 | .btn-warning.active { 167 | background-color: #eb9316; 168 | border-color: #e38d13; 169 | } 170 | .btn-warning.disabled, 171 | .btn-warning:disabled, 172 | .btn-warning[disabled] { 173 | background-color: #eb9316; 174 | background-image: none; 175 | } 176 | .btn-danger { 177 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 178 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 179 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 180 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 181 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 182 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 183 | background-repeat: repeat-x; 184 | border-color: #b92c28; 185 | } 186 | .btn-danger:hover, 187 | .btn-danger:focus { 188 | background-color: #c12e2a; 189 | background-position: 0 -15px; 190 | } 191 | .btn-danger:active, 192 | .btn-danger.active { 193 | background-color: #c12e2a; 194 | border-color: #b92c28; 195 | } 196 | .btn-danger.disabled, 197 | .btn-danger:disabled, 198 | .btn-danger[disabled] { 199 | background-color: #c12e2a; 200 | background-image: none; 201 | } 202 | .thumbnail, 203 | .img-thumbnail { 204 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 205 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 206 | } 207 | .dropdown-menu > li > a:hover, 208 | .dropdown-menu > li > a:focus { 209 | background-color: #e8e8e8; 210 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 211 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 212 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 213 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 214 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 215 | background-repeat: repeat-x; 216 | } 217 | .dropdown-menu > .active > a, 218 | .dropdown-menu > .active > a:hover, 219 | .dropdown-menu > .active > a:focus { 220 | background-color: #2e6da4; 221 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 222 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 223 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 224 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 225 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 226 | background-repeat: repeat-x; 227 | } 228 | .navbar-default { 229 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 230 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 231 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 232 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 233 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 234 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 235 | background-repeat: repeat-x; 236 | border-radius: 4px; 237 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 238 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 239 | } 240 | .navbar-default .navbar-nav > .open > a, 241 | .navbar-default .navbar-nav > .active > a { 242 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 243 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 244 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); 245 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); 246 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); 247 | background-repeat: repeat-x; 248 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 249 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 250 | } 251 | .navbar-brand, 252 | .navbar-nav > li > a { 253 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 254 | } 255 | .navbar-inverse { 256 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 257 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 258 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 259 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 260 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 261 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 262 | background-repeat: repeat-x; 263 | } 264 | .navbar-inverse .navbar-nav > .open > a, 265 | .navbar-inverse .navbar-nav > .active > a { 266 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); 267 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); 268 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); 269 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); 270 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); 271 | background-repeat: repeat-x; 272 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 273 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 274 | } 275 | .navbar-inverse .navbar-brand, 276 | .navbar-inverse .navbar-nav > li > a { 277 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 278 | } 279 | .navbar-static-top, 280 | .navbar-fixed-top, 281 | .navbar-fixed-bottom { 282 | border-radius: 0; 283 | } 284 | @media (max-width: 767px) { 285 | .navbar .navbar-nav .open .dropdown-menu > .active > a, 286 | .navbar .navbar-nav .open .dropdown-menu > .active > a:hover, 287 | .navbar .navbar-nav .open .dropdown-menu > .active > a:focus { 288 | color: #fff; 289 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 290 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 291 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 292 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 293 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 294 | background-repeat: repeat-x; 295 | } 296 | } 297 | .alert { 298 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 299 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 300 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 301 | } 302 | .alert-success { 303 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 304 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 305 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 306 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 307 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 308 | background-repeat: repeat-x; 309 | border-color: #b2dba1; 310 | } 311 | .alert-info { 312 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 313 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 314 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 315 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 316 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 317 | background-repeat: repeat-x; 318 | border-color: #9acfea; 319 | } 320 | .alert-warning { 321 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 322 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 323 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 324 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 325 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 326 | background-repeat: repeat-x; 327 | border-color: #f5e79e; 328 | } 329 | .alert-danger { 330 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 331 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 332 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 333 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 334 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 335 | background-repeat: repeat-x; 336 | border-color: #dca7a7; 337 | } 338 | .progress { 339 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 340 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 341 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 342 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 343 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 344 | background-repeat: repeat-x; 345 | } 346 | .progress-bar { 347 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); 348 | background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); 349 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); 350 | background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); 351 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); 352 | background-repeat: repeat-x; 353 | } 354 | .progress-bar-success { 355 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 356 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 357 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 358 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 359 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 360 | background-repeat: repeat-x; 361 | } 362 | .progress-bar-info { 363 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 364 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 365 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 366 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 367 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 368 | background-repeat: repeat-x; 369 | } 370 | .progress-bar-warning { 371 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 372 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 373 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 374 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 375 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 376 | background-repeat: repeat-x; 377 | } 378 | .progress-bar-danger { 379 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 380 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 381 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 382 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 383 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 384 | background-repeat: repeat-x; 385 | } 386 | .progress-bar-striped { 387 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 388 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 389 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 390 | } 391 | .list-group { 392 | border-radius: 4px; 393 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 394 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 395 | } 396 | .list-group-item.active, 397 | .list-group-item.active:hover, 398 | .list-group-item.active:focus { 399 | text-shadow: 0 -1px 0 #286090; 400 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); 401 | background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); 402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); 403 | background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); 404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); 405 | background-repeat: repeat-x; 406 | border-color: #2b669a; 407 | } 408 | .list-group-item.active .badge, 409 | .list-group-item.active:hover .badge, 410 | .list-group-item.active:focus .badge { 411 | text-shadow: none; 412 | } 413 | .panel { 414 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 415 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 416 | } 417 | .panel-default > .panel-heading { 418 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 419 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 420 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 421 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 422 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 423 | background-repeat: repeat-x; 424 | } 425 | .panel-primary > .panel-heading { 426 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 427 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 428 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 429 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 430 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 431 | background-repeat: repeat-x; 432 | } 433 | .panel-success > .panel-heading { 434 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 435 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 436 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 437 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 438 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 439 | background-repeat: repeat-x; 440 | } 441 | .panel-info > .panel-heading { 442 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 443 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 444 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 445 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 446 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 447 | background-repeat: repeat-x; 448 | } 449 | .panel-warning > .panel-heading { 450 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 451 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 452 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 453 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 454 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 455 | background-repeat: repeat-x; 456 | } 457 | .panel-danger > .panel-heading { 458 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 459 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 460 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 461 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 462 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 463 | background-repeat: repeat-x; 464 | } 465 | .well { 466 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 467 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 468 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 469 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 470 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 471 | background-repeat: repeat-x; 472 | border-color: #dcdcdc; 473 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 474 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 475 | } 476 | /*# sourceMappingURL=bootstrap-theme.css.map */ 477 | -------------------------------------------------------------------------------- /src/main/webapp/app/lib/bootstrap/css/bootstrap-theme.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","bootstrap-theme.css","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAcA;;;;;;EAME,0CAAA;ECgDA,6FAAA;EACQ,qFAAA;EC5DT;AFgBC;;;;;;;;;;;;EC2CA,0DAAA;EACQ,kDAAA;EC7CT;AFVD;;;;;;EAiBI,mBAAA;EECH;AFiCC;;EAEE,wBAAA;EE/BH;AFoCD;EGnDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EAgC2C,2BAAA;EAA2B,oBAAA;EEzBvE;AFLC;;EAEE,2BAAA;EACA,8BAAA;EEOH;AFJC;;EAEE,2BAAA;EACA,uBAAA;EEMH;AFHC;;;EAGE,2BAAA;EACA,wBAAA;EEKH;AFUD;EGpDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EEgCD;AF9BC;;EAEE,2BAAA;EACA,8BAAA;EEgCH;AF7BC;;EAEE,2BAAA;EACA,uBAAA;EE+BH;AF5BC;;;EAGE,2BAAA;EACA,wBAAA;EE8BH;AFdD;EGrDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EEyDD;AFvDC;;EAEE,2BAAA;EACA,8BAAA;EEyDH;AFtDC;;EAEE,2BAAA;EACA,uBAAA;EEwDH;AFrDC;;;EAGE,2BAAA;EACA,wBAAA;EEuDH;AFtCD;EGtDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EEkFD;AFhFC;;EAEE,2BAAA;EACA,8BAAA;EEkFH;AF/EC;;EAEE,2BAAA;EACA,uBAAA;EEiFH;AF9EC;;;EAGE,2BAAA;EACA,wBAAA;EEgFH;AF9DD;EGvDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EE2GD;AFzGC;;EAEE,2BAAA;EACA,8BAAA;EE2GH;AFxGC;;EAEE,2BAAA;EACA,uBAAA;EE0GH;AFvGC;;;EAGE,2BAAA;EACA,wBAAA;EEyGH;AFtFD;EGxDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EEoID;AFlIC;;EAEE,2BAAA;EACA,8BAAA;EEoIH;AFjIC;;EAEE,2BAAA;EACA,uBAAA;EEmIH;AFhIC;;;EAGE,2BAAA;EACA,wBAAA;EEkIH;AFxGD;;EChBE,oDAAA;EACQ,4CAAA;EC4HT;AFnGD;;EGzEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHwEF,2BAAA;EEyGD;AFvGD;;;EG9EI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8EF,2BAAA;EE6GD;AFpGD;EG3FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EJ6GA,oBAAA;EC/CA,6FAAA;EACQ,qFAAA;EC0JT;AF/GD;;EG3FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,0DAAA;EACQ,kDAAA;ECoKT;AF5GD;;EAEE,gDAAA;EE8GD;AF1GD;EG9GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EF+OD;AFlHD;;EG9GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,yDAAA;EACQ,iDAAA;EC0LT;AF5HD;;EAYI,2CAAA;EEoHH;AF/GD;;;EAGE,kBAAA;EEiHD;AF5FD;EAfI;;;IAGE,aAAA;IG3IF,0EAAA;IACA,qEAAA;IACA,+FAAA;IAAA,wEAAA;IACA,6BAAA;IACA,wHAAA;ID0PD;EACF;AFxGD;EACE,+CAAA;ECzGA,4FAAA;EACQ,oFAAA;ECoNT;AFhGD;EGpKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH4JF,uBAAA;EE4GD;AFvGD;EGrKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH4JF,uBAAA;EEoHD;AF9GD;EGtKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH4JF,uBAAA;EE4HD;AFrHD;EGvKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH4JF,uBAAA;EEoID;AFrHD;EG/KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDuSH;AFlHD;EGzLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED8SH;AFxHD;EG1LI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDqTH;AF9HD;EG3LI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED4TH;AFpID;EG5LI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDmUH;AF1ID;EG7LI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED0UH;AF7ID;EGhKI,+MAAA;EACA,0MAAA;EACA,uMAAA;EDgTH;AFzID;EACE,oBAAA;EC5JA,oDAAA;EACQ,4CAAA;ECwST;AF1ID;;;EAGE,+BAAA;EGjNE,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH+MF,uBAAA;EEgJD;AFrJD;;;EAQI,mBAAA;EEkJH;AFxID;ECjLE,mDAAA;EACQ,2CAAA;EC4TT;AFlID;EG1OI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED+WH;AFxID;EG3OI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDsXH;AF9ID;EG5OI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED6XH;AFpJD;EG7OI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDoYH;AF1JD;EG9OI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED2YH;AFhKD;EG/OI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDkZH;AFhKD;EGtPI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHoPF,uBAAA;ECzMA,2FAAA;EACQ,mFAAA;ECgXT","file":"bootstrap-theme.css","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &:disabled,\n &[disabled] {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n",".btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n text-shadow: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n}\n.btn-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #dbdbdb;\n text-shadow: 0 1px 0 #fff;\n border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n background-color: #e0e0e0;\n background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n background-color: #e0e0e0;\n border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default:disabled,\n.btn-default[disabled] {\n background-color: #e0e0e0;\n background-image: none;\n}\n.btn-primary {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n background-color: #265a88;\n background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n background-color: #265a88;\n border-color: #245580;\n}\n.btn-primary.disabled,\n.btn-primary:disabled,\n.btn-primary[disabled] {\n background-color: #265a88;\n background-image: none;\n}\n.btn-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n background-color: #419641;\n background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n background-color: #419641;\n border-color: #3e8f3e;\n}\n.btn-success.disabled,\n.btn-success:disabled,\n.btn-success[disabled] {\n background-color: #419641;\n background-image: none;\n}\n.btn-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n background-color: #2aabd2;\n background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n background-color: #2aabd2;\n border-color: #28a4c9;\n}\n.btn-info.disabled,\n.btn-info:disabled,\n.btn-info[disabled] {\n background-color: #2aabd2;\n background-image: none;\n}\n.btn-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n background-color: #eb9316;\n background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n background-color: #eb9316;\n border-color: #e38d13;\n}\n.btn-warning.disabled,\n.btn-warning:disabled,\n.btn-warning[disabled] {\n background-color: #eb9316;\n background-image: none;\n}\n.btn-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n background-color: #c12e2a;\n background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n background-color: #c12e2a;\n border-color: #b92c28;\n}\n.btn-danger.disabled,\n.btn-danger:disabled,\n.btn-danger[disabled] {\n background-color: #c12e2a;\n background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-color: #2e6da4;\n}\n.navbar-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: -o-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n@media (max-width: 767px) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n }\n}\n.alert {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n border-color: #b2dba1;\n}\n.alert-info {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n border-color: #9acfea;\n}\n.alert-warning {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n border-color: #f5e79e;\n}\n.alert-danger {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n border-color: #dca7a7;\n}\n.progress {\n background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n}\n.progress-bar {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n}\n.progress-bar-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n}\n.progress-bar-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n}\n.progress-bar-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n}\n.progress-bar-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n}\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 #286090;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n text-shadow: none;\n}\n.panel {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n}\n.panel-primary > .panel-heading {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n}\n.panel-success > .panel-heading {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n}\n.panel-info > .panel-heading {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n}\n.panel-warning > .panel-heading {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n}\n.panel-danger > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n}\n.well {\n background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n border-color: #dcdcdc;\n -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} -------------------------------------------------------------------------------- /src/main/webapp/app/lib/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arccode/rest-api/cb9ec6d2abe64b6016c1615c3a895396e0e32845/src/main/webapp/app/lib/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /src/main/webapp/app/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arccode/rest-api/cb9ec6d2abe64b6016c1615c3a895396e0e32845/src/main/webapp/app/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/main/webapp/app/lib/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arccode/rest-api/cb9ec6d2abe64b6016c1615c3a895396e0e32845/src/main/webapp/app/lib/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /src/main/webapp/app/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arccode/rest-api/cb9ec6d2abe64b6016c1615c3a895396e0e32845/src/main/webapp/app/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/main/webapp/app/lib/bootstrap/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /src/main/webapp/app/lib/requirejs/require.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | RequireJS 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. 3 | Available via the MIT or new BSD license. 4 | see: http://github.com/jrburke/requirejs for details 5 | */ 6 | var requirejs,require,define; 7 | (function(ba){function G(b){return"[object Function]"===K.call(b)}function H(b){return"[object Array]"===K.call(b)}function v(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(G(l)){if(this.events.error&&this.map.isDefine||g.onError!==ca)try{f=i.execCb(c,l,b,f)}catch(d){a=d}else f=i.execCb(c,l,b,f);this.map.isDefine&&void 0===f&&((b=this.module)?f=b.exports:this.usingExports&& 19 | (f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=l;this.exports=f;if(this.map.isDefine&&!this.ignore&&(r[c]=f,g.onResourceLoad))g.onResourceLoad(i,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a= 20 | this.map,b=a.id,d=p(a.prefix);this.depMaps.push(d);q(d,"defined",u(this,function(f){var l,d;d=m(aa,this.map.id);var e=this.map.name,P=this.map.parentMap?this.map.parentMap.name:null,n=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(e=f.normalize(e,function(a){return c(a,P,!0)})||""),f=p(a.prefix+"!"+e,this.map.parentMap),q(f,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(h,f.id)){this.depMaps.push(f); 21 | if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else d?(this.map.url=i.nameToUrl(d),this.load()):(l=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),l.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(h,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),l.fromText=u(this,function(f,c){var d=a.name,e=p(d),P=M;c&&(f=c);P&&(M=!1);s(e);t(j.config,b)&&(j.config[d]=j.config[b]);try{g.exec(f)}catch(h){return w(C("fromtexteval", 22 | "fromText eval for "+b+" failed: "+h,h,[b]))}P&&(M=!0);this.depMaps.push(e);i.completeLoad(d);n([d],l)}),f.load(a.name,n,l,j))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,u(this,function(a,b){var c,f;if("string"===typeof a){a=p(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(L,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;q(a,"defined",u(this,function(a){this.defineDep(b, 23 | a);this.check()}));this.errback&&q(a,"error",u(this,this.errback))}c=a.id;f=h[c];!t(L,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,u(this,function(a){var b=m(h,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:j,contextName:b,registry:h,defined:r,urlFetched:S,defQueue:A,Module:Z,makeModuleMap:p, 24 | nextTick:g.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=j.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(j[b]||(j[b]={}),U(j[b],a,!0,!0)):j[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(aa[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);b[c]=a}),j.shim=b);a.packages&&v(a.packages,function(a){var b, 25 | a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(j.paths[b]=a.location);j.pkgs[b]=a.name+"/"+(a.main||"main").replace(ia,"").replace(Q,"")});B(h,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=p(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,e){function j(c,d,m){var n,q;e.enableBuildCallback&&(d&&G(d))&&(d.__requireJsBuild= 26 | !0);if("string"===typeof c){if(G(d))return w(C("requireargs","Invalid require call"),m);if(a&&t(L,c))return L[c](h[a.id]);if(g.get)return g.get(i,c,a,j);n=p(c,a,!1,!0);n=n.id;return!t(r,n)?w(C("notloaded",'Module name "'+n+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[n]}J();i.nextTick(function(){J();q=s(p(null,a));q.skipMap=e.skipMap;q.init(c,d,m,{enabled:!0});D()});return j}e=e||{};U(j,{isBrowser:z,toUrl:function(b){var d,e=b.lastIndexOf("."),k=b.split("/")[0];if(-1!== 27 | e&&(!("."===k||".."===k)||1e.attachEvent.toString().indexOf("[native code"))&&!Y?(M=!0,e.attachEvent("onreadystatechange",b.onScriptLoad)): 34 | (e.addEventListener("load",b.onScriptLoad,!1),e.addEventListener("error",b.onScriptError,!1)),e.src=d,J=e,D?y.insertBefore(e,D):y.appendChild(e),J=null,e;if(ea)try{importScripts(d),b.completeLoad(c)}catch(m){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,m,[c]))}};z&&!q.skipDataMain&&T(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(I=b.getAttribute("data-main"))return s=I,q.baseUrl||(E=s.split("/"),s=E.pop(),O=E.length?E.join("/")+"/":"./",q.baseUrl= 35 | O),s=s.replace(Q,""),g.jsExtRegExp.test(s)&&(s=I),q.deps=q.deps?q.deps.concat(s):[s],!0});define=function(b,c,d){var e,g;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(ka,"").replace(la,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(M){if(!(e=J))N&&"interactive"===N.readyState||T(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return N=b}),e=N;e&&(b|| 36 | (b=e.getAttribute("data-requiremodule")),g=F[e.getAttribute("data-requirecontext")])}(g?g.defQueue:R).push([b,c,d])};define.amd={jQuery:!0};g.exec=function(b){return eval(b)};g(q)}})(this); 37 | -------------------------------------------------------------------------------- /src/main/webapp/app/lib/requirejs/text.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license RequireJS text 2.0.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. 3 | * Available via the MIT or new BSD license. 4 | * see: http://github.com/requirejs/text for details 5 | */ 6 | /*jslint regexp: true */ 7 | /*global require, XMLHttpRequest, ActiveXObject, 8 | define, window, process, Packages, 9 | java, location, Components, FileUtils */ 10 | 11 | define(['module'], function (module) { 12 | 'use strict'; 13 | 14 | var text, fs, Cc, Ci, xpcIsWindows, 15 | progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], 16 | xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, 17 | bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im, 18 | hasLocation = typeof location !== 'undefined' && location.href, 19 | defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), 20 | defaultHostName = hasLocation && location.hostname, 21 | defaultPort = hasLocation && (location.port || undefined), 22 | buildMap = {}, 23 | masterConfig = (module.config && module.config()) || {}; 24 | 25 | text = { 26 | version: '2.0.12', 27 | 28 | strip: function (content) { 29 | //Strips declarations so that external SVG and XML 30 | //documents can be added to a document without worry. Also, if the string 31 | //is an HTML document, only the part inside the body tag is returned. 32 | if (content) { 33 | content = content.replace(xmlRegExp, ""); 34 | var matches = content.match(bodyRegExp); 35 | if (matches) { 36 | content = matches[1]; 37 | } 38 | } else { 39 | content = ""; 40 | } 41 | return content; 42 | }, 43 | 44 | jsEscape: function (content) { 45 | return content.replace(/(['\\])/g, '\\$1') 46 | .replace(/[\f]/g, "\\f") 47 | .replace(/[\b]/g, "\\b") 48 | .replace(/[\n]/g, "\\n") 49 | .replace(/[\t]/g, "\\t") 50 | .replace(/[\r]/g, "\\r") 51 | .replace(/[\u2028]/g, "\\u2028") 52 | .replace(/[\u2029]/g, "\\u2029"); 53 | }, 54 | 55 | createXhr: masterConfig.createXhr || function () { 56 | //Would love to dump the ActiveX crap in here. Need IE 6 to die first. 57 | var xhr, i, progId; 58 | if (typeof XMLHttpRequest !== "undefined") { 59 | return new XMLHttpRequest(); 60 | } else if (typeof ActiveXObject !== "undefined") { 61 | for (i = 0; i < 3; i += 1) { 62 | progId = progIds[i]; 63 | try { 64 | xhr = new ActiveXObject(progId); 65 | } catch (e) {} 66 | 67 | if (xhr) { 68 | progIds = [progId]; // so faster next time 69 | break; 70 | } 71 | } 72 | } 73 | 74 | return xhr; 75 | }, 76 | 77 | /** 78 | * Parses a resource name into its component parts. Resource names 79 | * look like: module/name.ext!strip, where the !strip part is 80 | * optional. 81 | * @param {String} name the resource name 82 | * @returns {Object} with properties "moduleName", "ext" and "strip" 83 | * where strip is a boolean. 84 | */ 85 | parseName: function (name) { 86 | var modName, ext, temp, 87 | strip = false, 88 | index = name.indexOf("."), 89 | isRelative = name.indexOf('./') === 0 || 90 | name.indexOf('../') === 0; 91 | 92 | if (index !== -1 && (!isRelative || index > 1)) { 93 | modName = name.substring(0, index); 94 | ext = name.substring(index + 1, name.length); 95 | } else { 96 | modName = name; 97 | } 98 | 99 | temp = ext || modName; 100 | index = temp.indexOf("!"); 101 | if (index !== -1) { 102 | //Pull off the strip arg. 103 | strip = temp.substring(index + 1) === "strip"; 104 | temp = temp.substring(0, index); 105 | if (ext) { 106 | ext = temp; 107 | } else { 108 | modName = temp; 109 | } 110 | } 111 | 112 | return { 113 | moduleName: modName, 114 | ext: ext, 115 | strip: strip 116 | }; 117 | }, 118 | 119 | xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, 120 | 121 | /** 122 | * Is an URL on another domain. Only works for browser use, returns 123 | * false in non-browser environments. Only used to know if an 124 | * optimized .js version of a text resource should be loaded 125 | * instead. 126 | * @param {String} url 127 | * @returns Boolean 128 | */ 129 | useXhr: function (url, protocol, hostname, port) { 130 | var uProtocol, uHostName, uPort, 131 | match = text.xdRegExp.exec(url); 132 | if (!match) { 133 | return true; 134 | } 135 | uProtocol = match[2]; 136 | uHostName = match[3]; 137 | 138 | uHostName = uHostName.split(':'); 139 | uPort = uHostName[1]; 140 | uHostName = uHostName[0]; 141 | 142 | return (!uProtocol || uProtocol === protocol) && 143 | (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && 144 | ((!uPort && !uHostName) || uPort === port); 145 | }, 146 | 147 | finishLoad: function (name, strip, content, onLoad) { 148 | content = strip ? text.strip(content) : content; 149 | if (masterConfig.isBuild) { 150 | buildMap[name] = content; 151 | } 152 | onLoad(content); 153 | }, 154 | 155 | load: function (name, req, onLoad, config) { 156 | //Name has format: some.module.filext!strip 157 | //The strip part is optional. 158 | //if strip is present, then that means only get the string contents 159 | //inside a body tag in an HTML string. For XML/SVG content it means 160 | //removing the declarations so the content can be inserted 161 | //into the current doc without problems. 162 | 163 | // Do not bother with the work if a build and text will 164 | // not be inlined. 165 | if (config && config.isBuild && !config.inlineText) { 166 | onLoad(); 167 | return; 168 | } 169 | 170 | masterConfig.isBuild = config && config.isBuild; 171 | 172 | var parsed = text.parseName(name), 173 | nonStripName = parsed.moduleName + 174 | (parsed.ext ? '.' + parsed.ext : ''), 175 | url = req.toUrl(nonStripName), 176 | useXhr = (masterConfig.useXhr) || 177 | text.useXhr; 178 | 179 | // Do not load if it is an empty: url 180 | if (url.indexOf('empty:') === 0) { 181 | onLoad(); 182 | return; 183 | } 184 | 185 | //Load the text. Use XHR if possible and in a browser. 186 | if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { 187 | text.get(url, function (content) { 188 | text.finishLoad(name, parsed.strip, content, onLoad); 189 | }, function (err) { 190 | if (onLoad.error) { 191 | onLoad.error(err); 192 | } 193 | }); 194 | } else { 195 | //Need to fetch the resource across domains. Assume 196 | //the resource has been optimized into a JS module. Fetch 197 | //by the module name + extension, but do not include the 198 | //!strip part to avoid file system issues. 199 | req([nonStripName], function (content) { 200 | text.finishLoad(parsed.moduleName + '.' + parsed.ext, 201 | parsed.strip, content, onLoad); 202 | }); 203 | } 204 | }, 205 | 206 | write: function (pluginName, moduleName, write, config) { 207 | if (buildMap.hasOwnProperty(moduleName)) { 208 | var content = text.jsEscape(buildMap[moduleName]); 209 | write.asModule(pluginName + "!" + moduleName, 210 | "define(function () { return '" + 211 | content + 212 | "';});\n"); 213 | } 214 | }, 215 | 216 | writeFile: function (pluginName, moduleName, req, write, config) { 217 | var parsed = text.parseName(moduleName), 218 | extPart = parsed.ext ? '.' + parsed.ext : '', 219 | nonStripName = parsed.moduleName + extPart, 220 | //Use a '.js' file name so that it indicates it is a 221 | //script that can be loaded across domains. 222 | fileName = req.toUrl(parsed.moduleName + extPart) + '.js'; 223 | 224 | //Leverage own load() method to load plugin value, but only 225 | //write out values that do not have the strip argument, 226 | //to avoid any potential issues with ! in file names. 227 | text.load(nonStripName, req, function (value) { 228 | //Use own write() method to construct full module value. 229 | //But need to create shell that translates writeFile's 230 | //write() to the right interface. 231 | var textWrite = function (contents) { 232 | return write(fileName, contents); 233 | }; 234 | textWrite.asModule = function (moduleName, contents) { 235 | return write.asModule(moduleName, fileName, contents); 236 | }; 237 | 238 | text.write(pluginName, nonStripName, textWrite, config); 239 | }, config); 240 | } 241 | }; 242 | 243 | if (masterConfig.env === 'node' || (!masterConfig.env && 244 | typeof process !== "undefined" && 245 | process.versions && 246 | !!process.versions.node && 247 | !process.versions['node-webkit'])) { 248 | //Using special require.nodeRequire, something added by r.js. 249 | fs = require.nodeRequire('fs'); 250 | 251 | text.get = function (url, callback, errback) { 252 | try { 253 | var file = fs.readFileSync(url, 'utf8'); 254 | //Remove BOM (Byte Mark Order) from utf8 files if it is there. 255 | if (file.indexOf('\uFEFF') === 0) { 256 | file = file.substring(1); 257 | } 258 | callback(file); 259 | } catch (e) { 260 | if (errback) { 261 | errback(e); 262 | } 263 | } 264 | }; 265 | } else if (masterConfig.env === 'xhr' || (!masterConfig.env && 266 | text.createXhr())) { 267 | text.get = function (url, callback, errback, headers) { 268 | var xhr = text.createXhr(), header; 269 | xhr.open('GET', url, true); 270 | 271 | //Allow plugins direct access to xhr headers 272 | if (headers) { 273 | for (header in headers) { 274 | if (headers.hasOwnProperty(header)) { 275 | xhr.setRequestHeader(header.toLowerCase(), headers[header]); 276 | } 277 | } 278 | } 279 | 280 | //Allow overrides specified in config 281 | if (masterConfig.onXhr) { 282 | masterConfig.onXhr(xhr, url); 283 | } 284 | 285 | xhr.onreadystatechange = function (evt) { 286 | var status, err; 287 | //Do not explicitly handle errors, those should be 288 | //visible via console output in the browser. 289 | if (xhr.readyState === 4) { 290 | status = xhr.status || 0; 291 | if (status > 399 && status < 600) { 292 | //An http 4xx or 5xx error. Signal an error. 293 | err = new Error(url + ' HTTP status: ' + status); 294 | err.xhr = xhr; 295 | if (errback) { 296 | errback(err); 297 | } 298 | } else { 299 | callback(xhr.responseText); 300 | } 301 | 302 | if (masterConfig.onXhrComplete) { 303 | masterConfig.onXhrComplete(xhr, url); 304 | } 305 | } 306 | }; 307 | xhr.send(null); 308 | }; 309 | } else if (masterConfig.env === 'rhino' || (!masterConfig.env && 310 | typeof Packages !== 'undefined' && typeof java !== 'undefined')) { 311 | //Why Java, why is this so awkward? 312 | text.get = function (url, callback) { 313 | var stringBuffer, line, 314 | encoding = "utf-8", 315 | file = new java.io.File(url), 316 | lineSeparator = java.lang.System.getProperty("line.separator"), 317 | input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), 318 | content = ''; 319 | try { 320 | stringBuffer = new java.lang.StringBuffer(); 321 | line = input.readLine(); 322 | 323 | // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 324 | // http://www.unicode.org/faq/utf_bom.html 325 | 326 | // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: 327 | // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 328 | if (line && line.length() && line.charAt(0) === 0xfeff) { 329 | // Eat the BOM, since we've already found the encoding on this file, 330 | // and we plan to concatenating this buffer with others; the BOM should 331 | // only appear at the top of a file. 332 | line = line.substring(1); 333 | } 334 | 335 | if (line !== null) { 336 | stringBuffer.append(line); 337 | } 338 | 339 | while ((line = input.readLine()) !== null) { 340 | stringBuffer.append(lineSeparator); 341 | stringBuffer.append(line); 342 | } 343 | //Make sure we return a JavaScript string and not a Java string. 344 | content = String(stringBuffer.toString()); //String 345 | } finally { 346 | input.close(); 347 | } 348 | callback(content); 349 | }; 350 | } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env && 351 | typeof Components !== 'undefined' && Components.classes && 352 | Components.interfaces)) { 353 | //Avert your gaze! 354 | Cc = Components.classes; 355 | Ci = Components.interfaces; 356 | Components.utils['import']('resource://gre/modules/FileUtils.jsm'); 357 | xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); 358 | 359 | text.get = function (url, callback) { 360 | var inStream, convertStream, fileObj, 361 | readData = {}; 362 | 363 | if (xpcIsWindows) { 364 | url = url.replace(/\//g, '\\'); 365 | } 366 | 367 | fileObj = new FileUtils.File(url); 368 | 369 | //XPCOM, you so crazy 370 | try { 371 | inStream = Cc['@mozilla.org/network/file-input-stream;1'] 372 | .createInstance(Ci.nsIFileInputStream); 373 | inStream.init(fileObj, 1, 0, false); 374 | 375 | convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] 376 | .createInstance(Ci.nsIConverterInputStream); 377 | convertStream.init(inStream, "utf-8", inStream.available(), 378 | Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); 379 | 380 | convertStream.readString(inStream.available(), readData); 381 | convertStream.close(); 382 | inStream.close(); 383 | callback(readData.value); 384 | } catch (e) { 385 | throw new Error((fileObj && fileObj.path || '') + ': ' + e); 386 | } 387 | }; 388 | } 389 | return text; 390 | }); 391 | -------------------------------------------------------------------------------- /src/main/webapp/app/lib/superagent/superagent.js: -------------------------------------------------------------------------------- 1 | ;(function(){ 2 | 3 | /** 4 | * Require the given path. 5 | * 6 | * @param {String} path 7 | * @return {Object} exports 8 | * @api public 9 | */ 10 | 11 | function require(path, parent, orig) { 12 | var resolved = require.resolve(path); 13 | 14 | // lookup failed 15 | if (null == resolved) { 16 | orig = orig || path; 17 | parent = parent || 'root'; 18 | var err = new Error('Failed to require "' + orig + '" from "' + parent + '"'); 19 | err.path = orig; 20 | err.parent = parent; 21 | err.require = true; 22 | throw err; 23 | } 24 | 25 | var module = require.modules[resolved]; 26 | 27 | // perform real require() 28 | // by invoking the module's 29 | // registered function 30 | if (!module._resolving && !module.exports) { 31 | var mod = {}; 32 | mod.exports = {}; 33 | mod.client = mod.component = true; 34 | module._resolving = true; 35 | module.call(this, mod.exports, require.relative(resolved), mod); 36 | delete module._resolving; 37 | module.exports = mod.exports; 38 | } 39 | 40 | return module.exports; 41 | } 42 | 43 | /** 44 | * Registered modules. 45 | */ 46 | 47 | require.modules = {}; 48 | 49 | /** 50 | * Registered aliases. 51 | */ 52 | 53 | require.aliases = {}; 54 | 55 | /** 56 | * Resolve `path`. 57 | * 58 | * Lookup: 59 | * 60 | * - PATH/index.js 61 | * - PATH.js 62 | * - PATH 63 | * 64 | * @param {String} path 65 | * @return {String} path or null 66 | * @api private 67 | */ 68 | 69 | require.resolve = function(path) { 70 | if (path.charAt(0) === '/') path = path.slice(1); 71 | 72 | var paths = [ 73 | path, 74 | path + '.js', 75 | path + '.json', 76 | path + '/index.js', 77 | path + '/index.json' 78 | ]; 79 | 80 | for (var i = 0; i < paths.length; i++) { 81 | var path = paths[i]; 82 | if (require.modules.hasOwnProperty(path)) return path; 83 | if (require.aliases.hasOwnProperty(path)) return require.aliases[path]; 84 | } 85 | }; 86 | 87 | /** 88 | * Normalize `path` relative to the current path. 89 | * 90 | * @param {String} curr 91 | * @param {String} path 92 | * @return {String} 93 | * @api private 94 | */ 95 | 96 | require.normalize = function(curr, path) { 97 | var segs = []; 98 | 99 | if ('.' != path.charAt(0)) return path; 100 | 101 | curr = curr.split('/'); 102 | path = path.split('/'); 103 | 104 | for (var i = 0; i < path.length; ++i) { 105 | if ('..' == path[i]) { 106 | curr.pop(); 107 | } else if ('.' != path[i] && '' != path[i]) { 108 | segs.push(path[i]); 109 | } 110 | } 111 | 112 | return curr.concat(segs).join('/'); 113 | }; 114 | 115 | /** 116 | * Register module at `path` with callback `definition`. 117 | * 118 | * @param {String} path 119 | * @param {Function} definition 120 | * @api private 121 | */ 122 | 123 | require.register = function(path, definition) { 124 | require.modules[path] = definition; 125 | }; 126 | 127 | /** 128 | * Alias a module definition. 129 | * 130 | * @param {String} from 131 | * @param {String} to 132 | * @api private 133 | */ 134 | 135 | require.alias = function(from, to) { 136 | if (!require.modules.hasOwnProperty(from)) { 137 | throw new Error('Failed to alias "' + from + '", it does not exist'); 138 | } 139 | require.aliases[to] = from; 140 | }; 141 | 142 | /** 143 | * Return a require function relative to the `parent` path. 144 | * 145 | * @param {String} parent 146 | * @return {Function} 147 | * @api private 148 | */ 149 | 150 | require.relative = function(parent) { 151 | var p = require.normalize(parent, '..'); 152 | 153 | /** 154 | * lastIndexOf helper. 155 | */ 156 | 157 | function lastIndexOf(arr, obj) { 158 | var i = arr.length; 159 | while (i--) { 160 | if (arr[i] === obj) return i; 161 | } 162 | return -1; 163 | } 164 | 165 | /** 166 | * The relative require() itself. 167 | */ 168 | 169 | function localRequire(path) { 170 | var resolved = localRequire.resolve(path); 171 | return require(resolved, parent, path); 172 | } 173 | 174 | /** 175 | * Resolve relative to the parent. 176 | */ 177 | 178 | localRequire.resolve = function(path) { 179 | var c = path.charAt(0); 180 | if ('/' == c) return path.slice(1); 181 | if ('.' == c) return require.normalize(p, path); 182 | 183 | // resolve deps by returning 184 | // the dep in the nearest "deps" 185 | // directory 186 | var segs = parent.split('/'); 187 | var i = lastIndexOf(segs, 'deps') + 1; 188 | if (!i) i = 0; 189 | path = segs.slice(0, i + 1).join('/') + '/deps/' + path; 190 | return path; 191 | }; 192 | 193 | /** 194 | * Check if module is defined at `path`. 195 | */ 196 | 197 | localRequire.exists = function(path) { 198 | return require.modules.hasOwnProperty(localRequire.resolve(path)); 199 | }; 200 | 201 | return localRequire; 202 | }; 203 | require.register("component-emitter/index.js", function(exports, require, module){ 204 | 205 | /** 206 | * Expose `Emitter`. 207 | */ 208 | 209 | module.exports = Emitter; 210 | 211 | /** 212 | * Initialize a new `Emitter`. 213 | * 214 | * @api public 215 | */ 216 | 217 | function Emitter(obj) { 218 | if (obj) return mixin(obj); 219 | }; 220 | 221 | /** 222 | * Mixin the emitter properties. 223 | * 224 | * @param {Object} obj 225 | * @return {Object} 226 | * @api private 227 | */ 228 | 229 | function mixin(obj) { 230 | for (var key in Emitter.prototype) { 231 | obj[key] = Emitter.prototype[key]; 232 | } 233 | return obj; 234 | } 235 | 236 | /** 237 | * Listen on the given `event` with `fn`. 238 | * 239 | * @param {String} event 240 | * @param {Function} fn 241 | * @return {Emitter} 242 | * @api public 243 | */ 244 | 245 | Emitter.prototype.on = 246 | Emitter.prototype.addEventListener = function(event, fn){ 247 | this._callbacks = this._callbacks || {}; 248 | (this._callbacks[event] = this._callbacks[event] || []) 249 | .push(fn); 250 | return this; 251 | }; 252 | 253 | /** 254 | * Adds an `event` listener that will be invoked a single 255 | * time then automatically removed. 256 | * 257 | * @param {String} event 258 | * @param {Function} fn 259 | * @return {Emitter} 260 | * @api public 261 | */ 262 | 263 | Emitter.prototype.once = function(event, fn){ 264 | var self = this; 265 | this._callbacks = this._callbacks || {}; 266 | 267 | function on() { 268 | self.off(event, on); 269 | fn.apply(this, arguments); 270 | } 271 | 272 | on.fn = fn; 273 | this.on(event, on); 274 | return this; 275 | }; 276 | 277 | /** 278 | * Remove the given callback for `event` or all 279 | * registered callbacks. 280 | * 281 | * @param {String} event 282 | * @param {Function} fn 283 | * @return {Emitter} 284 | * @api public 285 | */ 286 | 287 | Emitter.prototype.off = 288 | Emitter.prototype.removeListener = 289 | Emitter.prototype.removeAllListeners = 290 | Emitter.prototype.removeEventListener = function(event, fn){ 291 | this._callbacks = this._callbacks || {}; 292 | 293 | // all 294 | if (0 == arguments.length) { 295 | this._callbacks = {}; 296 | return this; 297 | } 298 | 299 | // specific event 300 | var callbacks = this._callbacks[event]; 301 | if (!callbacks) return this; 302 | 303 | // remove all handlers 304 | if (1 == arguments.length) { 305 | delete this._callbacks[event]; 306 | return this; 307 | } 308 | 309 | // remove specific handler 310 | var cb; 311 | for (var i = 0; i < callbacks.length; i++) { 312 | cb = callbacks[i]; 313 | if (cb === fn || cb.fn === fn) { 314 | callbacks.splice(i, 1); 315 | break; 316 | } 317 | } 318 | return this; 319 | }; 320 | 321 | /** 322 | * Emit `event` with the given args. 323 | * 324 | * @param {String} event 325 | * @param {Mixed} ... 326 | * @return {Emitter} 327 | */ 328 | 329 | Emitter.prototype.emit = function(event){ 330 | this._callbacks = this._callbacks || {}; 331 | var args = [].slice.call(arguments, 1) 332 | , callbacks = this._callbacks[event]; 333 | 334 | if (callbacks) { 335 | callbacks = callbacks.slice(0); 336 | for (var i = 0, len = callbacks.length; i < len; ++i) { 337 | callbacks[i].apply(this, args); 338 | } 339 | } 340 | 341 | return this; 342 | }; 343 | 344 | /** 345 | * Return array of callbacks for `event`. 346 | * 347 | * @param {String} event 348 | * @return {Array} 349 | * @api public 350 | */ 351 | 352 | Emitter.prototype.listeners = function(event){ 353 | this._callbacks = this._callbacks || {}; 354 | return this._callbacks[event] || []; 355 | }; 356 | 357 | /** 358 | * Check if this emitter has `event` handlers. 359 | * 360 | * @param {String} event 361 | * @return {Boolean} 362 | * @api public 363 | */ 364 | 365 | Emitter.prototype.hasListeners = function(event){ 366 | return !! this.listeners(event).length; 367 | }; 368 | 369 | }); 370 | require.register("component-reduce/index.js", function(exports, require, module){ 371 | 372 | /** 373 | * Reduce `arr` with `fn`. 374 | * 375 | * @param {Array} arr 376 | * @param {Function} fn 377 | * @param {Mixed} initial 378 | * 379 | * TODO: combatible error handling? 380 | */ 381 | 382 | module.exports = function(arr, fn, initial){ 383 | var idx = 0; 384 | var len = arr.length; 385 | var curr = arguments.length == 3 386 | ? initial 387 | : arr[idx++]; 388 | 389 | while (idx < len) { 390 | curr = fn.call(null, curr, arr[idx], ++idx, arr); 391 | } 392 | 393 | return curr; 394 | }; 395 | }); 396 | require.register("superagent/lib/client.js", function(exports, require, module){ 397 | /** 398 | * Module dependencies. 399 | */ 400 | 401 | var Emitter = require('emitter'); 402 | var reduce = require('reduce'); 403 | 404 | /** 405 | * Root reference for iframes. 406 | */ 407 | 408 | var root = 'undefined' == typeof window 409 | ? this 410 | : window; 411 | 412 | /** 413 | * Noop. 414 | */ 415 | 416 | function noop(){}; 417 | 418 | /** 419 | * Check if `obj` is a host object, 420 | * we don't want to serialize these :) 421 | * 422 | * TODO: future proof, move to compoent land 423 | * 424 | * @param {Object} obj 425 | * @return {Boolean} 426 | * @api private 427 | */ 428 | 429 | function isHost(obj) { 430 | var str = {}.toString.call(obj); 431 | 432 | switch (str) { 433 | case '[object File]': 434 | case '[object Blob]': 435 | case '[object FormData]': 436 | return true; 437 | default: 438 | return false; 439 | } 440 | } 441 | 442 | /** 443 | * Determine XHR. 444 | */ 445 | 446 | function getXHR() { 447 | if (root.XMLHttpRequest 448 | && ('file:' != root.location.protocol || !root.ActiveXObject)) { 449 | return new XMLHttpRequest; 450 | } else { 451 | try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} 452 | try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {} 453 | try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {} 454 | try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {} 455 | } 456 | return false; 457 | } 458 | 459 | /** 460 | * Removes leading and trailing whitespace, added to support IE. 461 | * 462 | * @param {String} s 463 | * @return {String} 464 | * @api private 465 | */ 466 | 467 | var trim = ''.trim 468 | ? function(s) { return s.trim(); } 469 | : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); }; 470 | 471 | /** 472 | * Check if `obj` is an object. 473 | * 474 | * @param {Object} obj 475 | * @return {Boolean} 476 | * @api private 477 | */ 478 | 479 | function isObject(obj) { 480 | return obj === Object(obj); 481 | } 482 | 483 | /** 484 | * Serialize the given `obj`. 485 | * 486 | * @param {Object} obj 487 | * @return {String} 488 | * @api private 489 | */ 490 | 491 | function serialize(obj) { 492 | if (!isObject(obj)) return obj; 493 | var pairs = []; 494 | for (var key in obj) { 495 | if (null != obj[key]) { 496 | pairs.push(encodeURIComponent(key) 497 | + '=' + encodeURIComponent(obj[key])); 498 | } 499 | } 500 | return pairs.join('&'); 501 | } 502 | 503 | /** 504 | * Expose serialization method. 505 | */ 506 | 507 | request.serializeObject = serialize; 508 | 509 | /** 510 | * Parse the given x-www-form-urlencoded `str`. 511 | * 512 | * @param {String} str 513 | * @return {Object} 514 | * @api private 515 | */ 516 | 517 | function parseString(str) { 518 | var obj = {}; 519 | var pairs = str.split('&'); 520 | var parts; 521 | var pair; 522 | 523 | for (var i = 0, len = pairs.length; i < len; ++i) { 524 | pair = pairs[i]; 525 | parts = pair.split('='); 526 | obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); 527 | } 528 | 529 | return obj; 530 | } 531 | 532 | /** 533 | * Expose parser. 534 | */ 535 | 536 | request.parseString = parseString; 537 | 538 | /** 539 | * Default MIME type map. 540 | * 541 | * superagent.types.xml = 'application/xml'; 542 | * 543 | */ 544 | 545 | request.types = { 546 | html: 'text/html', 547 | json: 'application/json', 548 | xml: 'application/xml', 549 | urlencoded: 'application/x-www-form-urlencoded', 550 | 'form': 'application/x-www-form-urlencoded', 551 | 'form-data': 'application/x-www-form-urlencoded' 552 | }; 553 | 554 | /** 555 | * Default serialization map. 556 | * 557 | * superagent.serialize['application/xml'] = function(obj){ 558 | * return 'generated xml here'; 559 | * }; 560 | * 561 | */ 562 | 563 | request.serialize = { 564 | 'application/x-www-form-urlencoded': serialize, 565 | 'application/json': JSON.stringify 566 | }; 567 | 568 | /** 569 | * Default parsers. 570 | * 571 | * superagent.parse['application/xml'] = function(str){ 572 | * return { object parsed from str }; 573 | * }; 574 | * 575 | */ 576 | 577 | request.parse = { 578 | 'application/x-www-form-urlencoded': parseString, 579 | 'application/json': JSON.parse 580 | }; 581 | 582 | /** 583 | * Parse the given header `str` into 584 | * an object containing the mapped fields. 585 | * 586 | * @param {String} str 587 | * @return {Object} 588 | * @api private 589 | */ 590 | 591 | function parseHeader(str) { 592 | var lines = str.split(/\r?\n/); 593 | var fields = {}; 594 | var index; 595 | var line; 596 | var field; 597 | var val; 598 | 599 | lines.pop(); // trailing CRLF 600 | 601 | for (var i = 0, len = lines.length; i < len; ++i) { 602 | line = lines[i]; 603 | index = line.indexOf(':'); 604 | field = line.slice(0, index).toLowerCase(); 605 | val = trim(line.slice(index + 1)); 606 | fields[field] = val; 607 | } 608 | 609 | return fields; 610 | } 611 | 612 | /** 613 | * Return the mime type for the given `str`. 614 | * 615 | * @param {String} str 616 | * @return {String} 617 | * @api private 618 | */ 619 | 620 | function type(str){ 621 | return str.split(/ *; */).shift(); 622 | }; 623 | 624 | /** 625 | * Return header field parameters. 626 | * 627 | * @param {String} str 628 | * @return {Object} 629 | * @api private 630 | */ 631 | 632 | function params(str){ 633 | return reduce(str.split(/ *; */), function(obj, str){ 634 | var parts = str.split(/ *= */) 635 | , key = parts.shift() 636 | , val = parts.shift(); 637 | 638 | if (key && val) obj[key] = val; 639 | return obj; 640 | }, {}); 641 | }; 642 | 643 | /** 644 | * Initialize a new `Response` with the given `xhr`. 645 | * 646 | * - set flags (.ok, .error, etc) 647 | * - parse header 648 | * 649 | * Examples: 650 | * 651 | * Aliasing `superagent` as `request` is nice: 652 | * 653 | * request = superagent; 654 | * 655 | * We can use the promise-like API, or pass callbacks: 656 | * 657 | * request.get('/').end(function(res){}); 658 | * request.get('/', function(res){}); 659 | * 660 | * Sending data can be chained: 661 | * 662 | * request 663 | * .post('/user') 664 | * .send({ name: 'tj' }) 665 | * .end(function(res){}); 666 | * 667 | * Or passed to `.send()`: 668 | * 669 | * request 670 | * .post('/user') 671 | * .send({ name: 'tj' }, function(res){}); 672 | * 673 | * Or passed to `.post()`: 674 | * 675 | * request 676 | * .post('/user', { name: 'tj' }) 677 | * .end(function(res){}); 678 | * 679 | * Or further reduced to a single call for simple cases: 680 | * 681 | * request 682 | * .post('/user', { name: 'tj' }, function(res){}); 683 | * 684 | * @param {XMLHTTPRequest} xhr 685 | * @param {Object} options 686 | * @api private 687 | */ 688 | 689 | function Response(req, options) { 690 | options = options || {}; 691 | this.req = req; 692 | this.xhr = this.req.xhr; 693 | this.text = this.req.method !='HEAD' 694 | ? this.xhr.responseText 695 | : null; 696 | this.setStatusProperties(this.xhr.status); 697 | this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders()); 698 | // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but 699 | // getResponseHeader still works. so we get content-type even if getting 700 | // other headers fails. 701 | this.header['content-type'] = this.xhr.getResponseHeader('content-type'); 702 | this.setHeaderProperties(this.header); 703 | this.body = this.req.method != 'HEAD' 704 | ? this.parseBody(this.text) 705 | : null; 706 | } 707 | 708 | /** 709 | * Get case-insensitive `field` value. 710 | * 711 | * @param {String} field 712 | * @return {String} 713 | * @api public 714 | */ 715 | 716 | Response.prototype.get = function(field){ 717 | return this.header[field.toLowerCase()]; 718 | }; 719 | 720 | /** 721 | * Set header related properties: 722 | * 723 | * - `.type` the content type without params 724 | * 725 | * A response of "Content-Type: text/plain; charset=utf-8" 726 | * will provide you with a `.type` of "text/plain". 727 | * 728 | * @param {Object} header 729 | * @api private 730 | */ 731 | 732 | Response.prototype.setHeaderProperties = function(header){ 733 | // content-type 734 | var ct = this.header['content-type'] || ''; 735 | this.type = type(ct); 736 | 737 | // params 738 | var obj = params(ct); 739 | for (var key in obj) this[key] = obj[key]; 740 | }; 741 | 742 | /** 743 | * Parse the given body `str`. 744 | * 745 | * Used for auto-parsing of bodies. Parsers 746 | * are defined on the `superagent.parse` object. 747 | * 748 | * @param {String} str 749 | * @return {Mixed} 750 | * @api private 751 | */ 752 | 753 | Response.prototype.parseBody = function(str){ 754 | var parse = request.parse[this.type]; 755 | return parse && str && str.length 756 | ? parse(str) 757 | : null; 758 | }; 759 | 760 | /** 761 | * Set flags such as `.ok` based on `status`. 762 | * 763 | * For example a 2xx response will give you a `.ok` of __true__ 764 | * whereas 5xx will be __false__ and `.error` will be __true__. The 765 | * `.clientError` and `.serverError` are also available to be more 766 | * specific, and `.statusType` is the class of error ranging from 1..5 767 | * sometimes useful for mapping respond colors etc. 768 | * 769 | * "sugar" properties are also defined for common cases. Currently providing: 770 | * 771 | * - .noContent 772 | * - .badRequest 773 | * - .unauthorized 774 | * - .notAcceptable 775 | * - .notFound 776 | * 777 | * @param {Number} status 778 | * @api private 779 | */ 780 | 781 | Response.prototype.setStatusProperties = function(status){ 782 | var type = status / 100 | 0; 783 | 784 | // status / class 785 | this.status = status; 786 | this.statusType = type; 787 | 788 | // basics 789 | this.info = 1 == type; 790 | this.ok = 2 == type; 791 | this.clientError = 4 == type; 792 | this.serverError = 5 == type; 793 | this.error = (4 == type || 5 == type) 794 | ? this.toError() 795 | : false; 796 | 797 | // sugar 798 | this.accepted = 202 == status; 799 | this.noContent = 204 == status || 1223 == status; 800 | this.badRequest = 400 == status; 801 | this.unauthorized = 401 == status; 802 | this.notAcceptable = 406 == status; 803 | this.notFound = 404 == status; 804 | this.forbidden = 403 == status; 805 | }; 806 | 807 | /** 808 | * Return an `Error` representative of this response. 809 | * 810 | * @return {Error} 811 | * @api public 812 | */ 813 | 814 | Response.prototype.toError = function(){ 815 | var req = this.req; 816 | var method = req.method; 817 | var url = req.url; 818 | 819 | var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')'; 820 | var err = new Error(msg); 821 | err.status = this.status; 822 | err.method = method; 823 | err.url = url; 824 | 825 | return err; 826 | }; 827 | 828 | /** 829 | * Expose `Response`. 830 | */ 831 | 832 | request.Response = Response; 833 | 834 | /** 835 | * Initialize a new `Request` with the given `method` and `url`. 836 | * 837 | * @param {String} method 838 | * @param {String} url 839 | * @api public 840 | */ 841 | 842 | function Request(method, url) { 843 | var self = this; 844 | Emitter.call(this); 845 | this._query = this._query || []; 846 | this.method = method; 847 | this.url = url; 848 | this.header = {}; 849 | this._header = {}; 850 | this.on('end', function(){ 851 | var err = null; 852 | var res = null; 853 | 854 | try { 855 | res = new Response(self); 856 | } catch(e) { 857 | err = new Error('Parser is unable to parse the response'); 858 | err.parse = true; 859 | err.original = e; 860 | } 861 | 862 | self.callback(err, res); 863 | }); 864 | } 865 | 866 | /** 867 | * Mixin `Emitter`. 868 | */ 869 | 870 | Emitter(Request.prototype); 871 | 872 | /** 873 | * Allow for extension 874 | */ 875 | 876 | Request.prototype.use = function(fn) { 877 | fn(this); 878 | return this; 879 | } 880 | 881 | /** 882 | * Set timeout to `ms`. 883 | * 884 | * @param {Number} ms 885 | * @return {Request} for chaining 886 | * @api public 887 | */ 888 | 889 | Request.prototype.timeout = function(ms){ 890 | this._timeout = ms; 891 | return this; 892 | }; 893 | 894 | /** 895 | * Clear previous timeout. 896 | * 897 | * @return {Request} for chaining 898 | * @api public 899 | */ 900 | 901 | Request.prototype.clearTimeout = function(){ 902 | this._timeout = 0; 903 | clearTimeout(this._timer); 904 | return this; 905 | }; 906 | 907 | /** 908 | * Abort the request, and clear potential timeout. 909 | * 910 | * @return {Request} 911 | * @api public 912 | */ 913 | 914 | Request.prototype.abort = function(){ 915 | if (this.aborted) return; 916 | this.aborted = true; 917 | this.xhr.abort(); 918 | this.clearTimeout(); 919 | this.emit('abort'); 920 | return this; 921 | }; 922 | 923 | /** 924 | * Set header `field` to `val`, or multiple fields with one object. 925 | * 926 | * Examples: 927 | * 928 | * req.get('/') 929 | * .set('Accept', 'application/json') 930 | * .set('X-API-Key', 'foobar') 931 | * .end(callback); 932 | * 933 | * req.get('/') 934 | * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' }) 935 | * .end(callback); 936 | * 937 | * @param {String|Object} field 938 | * @param {String} val 939 | * @return {Request} for chaining 940 | * @api public 941 | */ 942 | 943 | Request.prototype.set = function(field, val){ 944 | if (isObject(field)) { 945 | for (var key in field) { 946 | this.set(key, field[key]); 947 | } 948 | return this; 949 | } 950 | this._header[field.toLowerCase()] = val; 951 | this.header[field] = val; 952 | return this; 953 | }; 954 | 955 | /** 956 | * Remove header `field`. 957 | * 958 | * Example: 959 | * 960 | * req.get('/') 961 | * .unset('User-Agent') 962 | * .end(callback); 963 | * 964 | * @param {String} field 965 | * @return {Request} for chaining 966 | * @api public 967 | */ 968 | 969 | Request.prototype.unset = function(field){ 970 | delete this._header[field.toLowerCase()]; 971 | delete this.header[field]; 972 | return this; 973 | }; 974 | 975 | /** 976 | * Get case-insensitive header `field` value. 977 | * 978 | * @param {String} field 979 | * @return {String} 980 | * @api private 981 | */ 982 | 983 | Request.prototype.getHeader = function(field){ 984 | return this._header[field.toLowerCase()]; 985 | }; 986 | 987 | /** 988 | * Set Content-Type to `type`, mapping values from `request.types`. 989 | * 990 | * Examples: 991 | * 992 | * superagent.types.xml = 'application/xml'; 993 | * 994 | * request.post('/') 995 | * .type('xml') 996 | * .send(xmlstring) 997 | * .end(callback); 998 | * 999 | * request.post('/') 1000 | * .type('application/xml') 1001 | * .send(xmlstring) 1002 | * .end(callback); 1003 | * 1004 | * @param {String} type 1005 | * @return {Request} for chaining 1006 | * @api public 1007 | */ 1008 | 1009 | Request.prototype.type = function(type){ 1010 | this.set('Content-Type', request.types[type] || type); 1011 | return this; 1012 | }; 1013 | 1014 | /** 1015 | * Set Accept to `type`, mapping values from `request.types`. 1016 | * 1017 | * Examples: 1018 | * 1019 | * superagent.types.json = 'application/json'; 1020 | * 1021 | * request.get('/agent') 1022 | * .accept('json') 1023 | * .end(callback); 1024 | * 1025 | * request.get('/agent') 1026 | * .accept('application/json') 1027 | * .end(callback); 1028 | * 1029 | * @param {String} accept 1030 | * @return {Request} for chaining 1031 | * @api public 1032 | */ 1033 | 1034 | Request.prototype.accept = function(type){ 1035 | this.set('Accept', request.types[type] || type); 1036 | return this; 1037 | }; 1038 | 1039 | /** 1040 | * Set Authorization field value with `user` and `pass`. 1041 | * 1042 | * @param {String} user 1043 | * @param {String} pass 1044 | * @return {Request} for chaining 1045 | * @api public 1046 | */ 1047 | 1048 | Request.prototype.auth = function(user, pass){ 1049 | var str = btoa(user + ':' + pass); 1050 | this.set('Authorization', 'Basic ' + str); 1051 | return this; 1052 | }; 1053 | 1054 | /** 1055 | * Add query-string `val`. 1056 | * 1057 | * Examples: 1058 | * 1059 | * request.get('/shoes') 1060 | * .query('size=10') 1061 | * .query({ color: 'blue' }) 1062 | * 1063 | * @param {Object|String} val 1064 | * @return {Request} for chaining 1065 | * @api public 1066 | */ 1067 | 1068 | Request.prototype.query = function(val){ 1069 | if ('string' != typeof val) val = serialize(val); 1070 | if (val) this._query.push(val); 1071 | return this; 1072 | }; 1073 | 1074 | /** 1075 | * Write the field `name` and `val` for "multipart/form-data" 1076 | * request bodies. 1077 | * 1078 | * ``` js 1079 | * request.post('/upload') 1080 | * .field('foo', 'bar') 1081 | * .end(callback); 1082 | * ``` 1083 | * 1084 | * @param {String} name 1085 | * @param {String|Blob|File} val 1086 | * @return {Request} for chaining 1087 | * @api public 1088 | */ 1089 | 1090 | Request.prototype.field = function(name, val){ 1091 | if (!this._formData) this._formData = new FormData(); 1092 | this._formData.append(name, val); 1093 | return this; 1094 | }; 1095 | 1096 | /** 1097 | * Queue the given `file` as an attachment to the specified `field`, 1098 | * with optional `filename`. 1099 | * 1100 | * ``` js 1101 | * request.post('/upload') 1102 | * .attach(new Blob(['hey!'], { type: "text/html"})) 1103 | * .end(callback); 1104 | * ``` 1105 | * 1106 | * @param {String} field 1107 | * @param {Blob|File} file 1108 | * @param {String} filename 1109 | * @return {Request} for chaining 1110 | * @api public 1111 | */ 1112 | 1113 | Request.prototype.attach = function(field, file, filename){ 1114 | if (!this._formData) this._formData = new FormData(); 1115 | this._formData.append(field, file, filename); 1116 | return this; 1117 | }; 1118 | 1119 | /** 1120 | * Send `data`, defaulting the `.type()` to "json" when 1121 | * an object is given. 1122 | * 1123 | * Examples: 1124 | * 1125 | * // querystring 1126 | * request.get('/search') 1127 | * .end(callback) 1128 | * 1129 | * // multiple data "writes" 1130 | * request.get('/search') 1131 | * .send({ search: 'query' }) 1132 | * .send({ range: '1..5' }) 1133 | * .send({ order: 'desc' }) 1134 | * .end(callback) 1135 | * 1136 | * // manual json 1137 | * request.post('/user') 1138 | * .type('json') 1139 | * .send('{"name":"tj"}) 1140 | * .end(callback) 1141 | * 1142 | * // auto json 1143 | * request.post('/user') 1144 | * .send({ name: 'tj' }) 1145 | * .end(callback) 1146 | * 1147 | * // manual x-www-form-urlencoded 1148 | * request.post('/user') 1149 | * .type('form') 1150 | * .send('name=tj') 1151 | * .end(callback) 1152 | * 1153 | * // auto x-www-form-urlencoded 1154 | * request.post('/user') 1155 | * .type('form') 1156 | * .send({ name: 'tj' }) 1157 | * .end(callback) 1158 | * 1159 | * // defaults to x-www-form-urlencoded 1160 | * request.post('/user') 1161 | * .send('name=tobi') 1162 | * .send('species=ferret') 1163 | * .end(callback) 1164 | * 1165 | * @param {String|Object} data 1166 | * @return {Request} for chaining 1167 | * @api public 1168 | */ 1169 | 1170 | Request.prototype.send = function(data){ 1171 | var obj = isObject(data); 1172 | var type = this.getHeader('Content-Type'); 1173 | 1174 | // merge 1175 | if (obj && isObject(this._data)) { 1176 | for (var key in data) { 1177 | this._data[key] = data[key]; 1178 | } 1179 | } else if ('string' == typeof data) { 1180 | if (!type) this.type('form'); 1181 | type = this.getHeader('Content-Type'); 1182 | if ('application/x-www-form-urlencoded' == type) { 1183 | this._data = this._data 1184 | ? this._data + '&' + data 1185 | : data; 1186 | } else { 1187 | this._data = (this._data || '') + data; 1188 | } 1189 | } else { 1190 | this._data = data; 1191 | } 1192 | 1193 | if (!obj) return this; 1194 | if (!type) this.type('json'); 1195 | return this; 1196 | }; 1197 | 1198 | /** 1199 | * Invoke the callback with `err` and `res` 1200 | * and handle arity check. 1201 | * 1202 | * @param {Error} err 1203 | * @param {Response} res 1204 | * @api private 1205 | */ 1206 | 1207 | Request.prototype.callback = function(err, res){ 1208 | var fn = this._callback; 1209 | this.clearTimeout(); 1210 | if (2 == fn.length) return fn(err, res); 1211 | if (err) return this.emit('error', err); 1212 | fn(res); 1213 | }; 1214 | 1215 | /** 1216 | * Invoke callback with x-domain error. 1217 | * 1218 | * @api private 1219 | */ 1220 | 1221 | Request.prototype.crossDomainError = function(){ 1222 | var err = new Error('Origin is not allowed by Access-Control-Allow-Origin'); 1223 | err.crossDomain = true; 1224 | this.callback(err); 1225 | }; 1226 | 1227 | /** 1228 | * Invoke callback with timeout error. 1229 | * 1230 | * @api private 1231 | */ 1232 | 1233 | Request.prototype.timeoutError = function(){ 1234 | var timeout = this._timeout; 1235 | var err = new Error('timeout of ' + timeout + 'ms exceeded'); 1236 | err.timeout = timeout; 1237 | this.callback(err); 1238 | }; 1239 | 1240 | /** 1241 | * Enable transmission of cookies with x-domain requests. 1242 | * 1243 | * Note that for this to work the origin must not be 1244 | * using "Access-Control-Allow-Origin" with a wildcard, 1245 | * and also must set "Access-Control-Allow-Credentials" 1246 | * to "true". 1247 | * 1248 | * @api public 1249 | */ 1250 | 1251 | Request.prototype.withCredentials = function(){ 1252 | this._withCredentials = true; 1253 | return this; 1254 | }; 1255 | 1256 | /** 1257 | * Initiate request, invoking callback `fn(res)` 1258 | * with an instanceof `Response`. 1259 | * 1260 | * @param {Function} fn 1261 | * @return {Request} for chaining 1262 | * @api public 1263 | */ 1264 | 1265 | Request.prototype.end = function(fn){ 1266 | var self = this; 1267 | var xhr = this.xhr = getXHR(); 1268 | var query = this._query.join('&'); 1269 | var timeout = this._timeout; 1270 | var data = this._formData || this._data; 1271 | 1272 | // store callback 1273 | this._callback = fn || noop; 1274 | 1275 | // state change 1276 | xhr.onreadystatechange = function(){ 1277 | if (4 != xhr.readyState) return; 1278 | if (0 == xhr.status) { 1279 | if (self.aborted) return self.timeoutError(); 1280 | return self.crossDomainError(); 1281 | } 1282 | self.emit('end'); 1283 | }; 1284 | 1285 | // progress 1286 | if (xhr.upload) { 1287 | xhr.upload.onprogress = function(e){ 1288 | e.percent = e.loaded / e.total * 100; 1289 | self.emit('progress', e); 1290 | }; 1291 | } 1292 | 1293 | // timeout 1294 | if (timeout && !this._timer) { 1295 | this._timer = setTimeout(function(){ 1296 | self.abort(); 1297 | }, timeout); 1298 | } 1299 | 1300 | // querystring 1301 | if (query) { 1302 | query = request.serializeObject(query); 1303 | this.url += ~this.url.indexOf('?') 1304 | ? '&' + query 1305 | : '?' + query; 1306 | } 1307 | 1308 | // initiate request 1309 | xhr.open(this.method, this.url, true); 1310 | 1311 | // CORS 1312 | if (this._withCredentials) xhr.withCredentials = true; 1313 | 1314 | // body 1315 | if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) { 1316 | // serialize stuff 1317 | var serialize = request.serialize[this.getHeader('Content-Type')]; 1318 | if (serialize) data = serialize(data); 1319 | } 1320 | 1321 | // set header fields 1322 | for (var field in this.header) { 1323 | if (null == this.header[field]) continue; 1324 | xhr.setRequestHeader(field, this.header[field]); 1325 | } 1326 | 1327 | // send stuff 1328 | this.emit('request', this); 1329 | xhr.send(data); 1330 | return this; 1331 | }; 1332 | 1333 | /** 1334 | * Expose `Request`. 1335 | */ 1336 | 1337 | request.Request = Request; 1338 | 1339 | /** 1340 | * Issue a request: 1341 | * 1342 | * Examples: 1343 | * 1344 | * request('GET', '/users').end(callback) 1345 | * request('/users').end(callback) 1346 | * request('/users', callback) 1347 | * 1348 | * @param {String} method 1349 | * @param {String|Function} url or callback 1350 | * @return {Request} 1351 | * @api public 1352 | */ 1353 | 1354 | function request(method, url) { 1355 | // callback 1356 | if ('function' == typeof url) { 1357 | return new Request('GET', method).end(url); 1358 | } 1359 | 1360 | // url first 1361 | if (1 == arguments.length) { 1362 | return new Request('GET', method); 1363 | } 1364 | 1365 | return new Request(method, url); 1366 | } 1367 | 1368 | /** 1369 | * GET `url` with optional callback `fn(res)`. 1370 | * 1371 | * @param {String} url 1372 | * @param {Mixed|Function} data or fn 1373 | * @param {Function} fn 1374 | * @return {Request} 1375 | * @api public 1376 | */ 1377 | 1378 | request.get = function(url, data, fn){ 1379 | var req = request('GET', url); 1380 | if ('function' == typeof data) fn = data, data = null; 1381 | if (data) req.query(data); 1382 | if (fn) req.end(fn); 1383 | return req; 1384 | }; 1385 | 1386 | /** 1387 | * HEAD `url` with optional callback `fn(res)`. 1388 | * 1389 | * @param {String} url 1390 | * @param {Mixed|Function} data or fn 1391 | * @param {Function} fn 1392 | * @return {Request} 1393 | * @api public 1394 | */ 1395 | 1396 | request.head = function(url, data, fn){ 1397 | var req = request('HEAD', url); 1398 | if ('function' == typeof data) fn = data, data = null; 1399 | if (data) req.send(data); 1400 | if (fn) req.end(fn); 1401 | return req; 1402 | }; 1403 | 1404 | /** 1405 | * DELETE `url` with optional callback `fn(res)`. 1406 | * 1407 | * @param {String} url 1408 | * @param {Function} fn 1409 | * @return {Request} 1410 | * @api public 1411 | */ 1412 | 1413 | request.del = function(url, fn){ 1414 | var req = request('DELETE', url); 1415 | if (fn) req.end(fn); 1416 | return req; 1417 | }; 1418 | 1419 | /** 1420 | * PATCH `url` with optional `data` and callback `fn(res)`. 1421 | * 1422 | * @param {String} url 1423 | * @param {Mixed} data 1424 | * @param {Function} fn 1425 | * @return {Request} 1426 | * @api public 1427 | */ 1428 | 1429 | request.patch = function(url, data, fn){ 1430 | var req = request('PATCH', url); 1431 | if ('function' == typeof data) fn = data, data = null; 1432 | if (data) req.send(data); 1433 | if (fn) req.end(fn); 1434 | return req; 1435 | }; 1436 | 1437 | /** 1438 | * POST `url` with optional `data` and callback `fn(res)`. 1439 | * 1440 | * @param {String} url 1441 | * @param {Mixed} data 1442 | * @param {Function} fn 1443 | * @return {Request} 1444 | * @api public 1445 | */ 1446 | 1447 | request.post = function(url, data, fn){ 1448 | var req = request('POST', url); 1449 | if ('function' == typeof data) fn = data, data = null; 1450 | if (data) req.send(data); 1451 | if (fn) req.end(fn); 1452 | return req; 1453 | }; 1454 | 1455 | /** 1456 | * PUT `url` with optional `data` and callback `fn(res)`. 1457 | * 1458 | * @param {String} url 1459 | * @param {Mixed|Function} data or fn 1460 | * @param {Function} fn 1461 | * @return {Request} 1462 | * @api public 1463 | */ 1464 | 1465 | request.put = function(url, data, fn){ 1466 | var req = request('PUT', url); 1467 | if ('function' == typeof data) fn = data, data = null; 1468 | if (data) req.send(data); 1469 | if (fn) req.end(fn); 1470 | return req; 1471 | }; 1472 | 1473 | /** 1474 | * Expose `request`. 1475 | */ 1476 | 1477 | module.exports = request; 1478 | 1479 | }); 1480 | 1481 | 1482 | 1483 | 1484 | require.alias("component-emitter/index.js", "superagent/deps/emitter/index.js"); 1485 | require.alias("component-emitter/index.js", "emitter/index.js"); 1486 | 1487 | require.alias("component-reduce/index.js", "superagent/deps/reduce/index.js"); 1488 | require.alias("component-reduce/index.js", "reduce/index.js"); 1489 | 1490 | require.alias("superagent/lib/client.js", "superagent/index.js");if (typeof exports == "object") { 1491 | module.exports = require("superagent"); 1492 | } else if (typeof define == "function" && define.amd) { 1493 | define([], function(){ return require("superagent"); }); 1494 | } else { 1495 | this["superagent"] = require("superagent"); 1496 | }})(); -------------------------------------------------------------------------------- /src/main/webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Rest-API 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 |
14 |
15 | 16 |
17 | 20 |
21 |
22 | 23 |
24 | 25 |
26 | 32 |
33 |
34 | 35 |
36 | 37 |
38 |
39 | 40 |
41 |
42 | 43 |
44 | 45 |
46 | 47 |
48 |
49 | 50 |
51 | 52 |
53 | 54 |
55 |
56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/test/java/com/arccode/test/regexp/AntPathMatchTest.java: -------------------------------------------------------------------------------- 1 | package com.arccode.test.regexp; 2 | 3 | import org.junit.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.util.AntPathMatcher; 7 | 8 | /** 9 | * AntPathMatchTest : 10 | * 11 | * @author http://arccode.net 12 | * @since 2015-04-14 23:12 13 | */ 14 | public class AntPathMatchTest { 15 | 16 | private final Logger logger = LoggerFactory.getLogger(AntPathMatchTest.class); 17 | 18 | @Test 19 | public void test() { 20 | 21 | AntPathMatcher matcher = new AntPathMatcher(); 22 | String[] currUrls = {"/bop/wallpapers", "/bop/wallpapers1", "/bop/wallpapers11", "/bop/wallpapers/1", "/bop/wallpapers/1/labels/2"}; 23 | String[] userAuths = {"/bop/wallpapers", "/bop/wallpapers?","/bop/wallpapers/*", "/bop/wallpapers/**"}; 24 | 25 | for (String currUrl: currUrls) { 26 | for (String userAuth: userAuths) { 27 | logger.info(currUrl + "-----" + userAuth + "-----" + matcher.match(userAuth, currUrl) + ""); 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/arccode/test/util/DateUtilTest.java: -------------------------------------------------------------------------------- 1 | package com.arccode.test.util; 2 | 3 | import com.arccode.core.entity.DateFormat; 4 | import com.arccode.core.util.DateUtil; 5 | import org.junit.Test; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.util.Calendar; 10 | import java.util.Date; 11 | 12 | /** 13 | * DateUtilTest : 14 | * 15 | * @author arccode 16 | * @since 2014-12-19 14:42 17 | */ 18 | public class DateUtilTest { 19 | 20 | private final static Logger logger = LoggerFactory.getLogger(DateUtil.class); 21 | 22 | /** 23 | * 获取给定日期前n天的日期 24 | */ 25 | @Test 26 | public void getNAgo() { 27 | 28 | Date date = new Date(); 29 | Calendar calendar = Calendar.getInstance(); 30 | p(calendar); 31 | calendar.add(Calendar.MONTH, -1); 32 | p(DateUtil.convertDate2String(calendar.getTime(), DateFormat.DatePathSingle)); 33 | 34 | 35 | 36 | } 37 | 38 | private void p(Object o) { 39 | System.out.println(o); 40 | } 41 | 42 | @Test 43 | public void dateBefore() throws InterruptedException { 44 | Date d1 = new Date(); 45 | Thread.sleep(1000); 46 | Date d2 = new Date(); 47 | 48 | logger.info(d1.before(d2) + ""); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/arccode/test/util/UuidTest.java: -------------------------------------------------------------------------------- 1 | package com.arccode.test.util; 2 | 3 | import com.arccode.core.util.ApplicationUtils; 4 | import org.junit.Test; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /** 9 | * UuidTest : 10 | * 11 | * @author http://arccode.net 12 | * @since 2015-04-16 14:16 13 | */ 14 | public class UuidTest { 15 | 16 | private final Logger logger = LoggerFactory.getLogger(UuidTest.class); 17 | 18 | @Test 19 | public void test() { 20 | logger.info(ApplicationUtils.randomUUID()); 21 | } 22 | } 23 | --------------------------------------------------------------------------------