<|start_filename|>speedy-ext-shiro/src/main/java/com/kanasinfo/ext/shiro/filter/ShiroExtFormAuthenticationFilter.java<|end_filename|>
package com.kanasinfo.ext.shiro.filter;

import com.kanasinfo.ext.shiro.bean.ShiroUser;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * shiro登录权限验证过滤器
 */
public abstract class ShiroExtFormAuthenticationFilter extends FormAuthenticationFilter {

    protected abstract void doSomethingOnLoginSuccess(ApplicationContext context, AuthenticationToken token, ShiroUser shiroUser, Subject subject, ServletRequest request, ServletResponse response);

    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext((request.getServletContext()));
        Session session = subject.getSession();
        ShiroUser shiroUser = new ShiroUser((String) subject.getPrincipal());
        doSomethingOnLoginSuccess(context, token, shiroUser, subject, request, response);
        session.setAttribute(ShiroUser.SHIRO_USER_SESSION_KEY, shiroUser);
        return super.onLoginSuccess(token, subject, request, response);
    }
}

<|start_filename|>speedy-portal/src/main/webapp/WEB-INF/jsp/login.jsp<|end_filename|>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<html>
<head>
    <title>登录</title>
    <sec:csrfMetaTags/>
</head>
<body>
<form action="/login" method="post">
    <sec:csrfInput/>
    <input type="text" placeholder="username" name="username">
    <input type="password" placeholder="password" name="password">
    <button type="submit">登录</button>
</form>
</body>
</html>


<|start_filename|>speedy-ext-shiro/src/main/java/com/kanasinfo/ext/shiro/bean/UserModel.java<|end_filename|>
package com.kanasinfo.ext.shiro.bean;

import com.kanasinfo.ext.persistence.SupportModel;
import com.kanasinfo.ext.shiro.utils.HashUtils;

import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotNull;

/**
 * 用于Shiro登录校验的用户封装，自定义User Model可以继承此类
 */
@MappedSuperclass
public class UserModel extends SupportModel {

    @NotNull
    private String username;        // 登录名
    @NotNull
    private String password;        // 密码
    private String salt;            // 密码盐值

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }

    /**
     * 加密用户，赋予用户salt值及md5 password
     */
    public void encryptUser(){
        String salt = HashUtils.generateSalt();
        this.setSalt(salt);
        String password = HashUtils.toMd5(this.getPassword(), salt);
        this.setPassword(password);
    }
}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/cost/MediaTypeCost.java<|end_filename|>
package com.kanasinfo.utils.cost;

import okhttp3.MediaType;

/**
 * Created by gefangshuai on 2017/5/18.
 */
public final class MediaTypeCost {
    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    public static final MediaType XML = MediaType.parse("application/xml; charset=utf-8");
}


<|start_filename|>speedy-sample/src/main/java/com/kanasinfo/demo/model/User.java<|end_filename|>
package com.kanasinfo.demo.model;

import com.kanasinfo.ext.shiro.bean.UserModel;

import javax.persistence.Entity;
import javax.persistence.Table;

/**
 * Created by gefangshuai on 2016/1/6.
 */
@Entity
@Table(name = "user")
public class User extends UserModel{
    private String realname;

    public String getRealname() {
        return realname;
    }

    public void setRealname(String realname) {
        this.realname = realname;
    }
}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/StringKit.java<|end_filename|>
package com.kanasinfo.utils;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public final class StringKit {

    /**
     * 转换成String，如果为null，返回""
     */
    public static String toString(Object object) {
        return toString(object, "");
    }


    /**
     * 转换成String，如果为null，返回defaultVal
     */
    public static String toString(Object object, String defaultVal) {
        if (object == null)
            return defaultVal;
        if ("null".equalsIgnoreCase(object.toString()))
            return defaultVal;
        if (StringUtils.isBlank(object.toString()))
            return defaultVal;
        if(object instanceof Number)
            return NumberFormat.getInstance().format(object).replace(",", "");
        return object.toString();
    }

    /**
     * 比较俩对象转换成字符串后是否相等。null eq ""
     */
    public static boolean equals(Object object1, Object object2) {
        String str1 = toString(object1, "");
        String str2 = toString(object2, "");

        return str1.equals(str2);
    }

    /**
     * 转换成int类型
     */
    public static Integer toInt(Object object) {
        String value = toString(object, "0");
        String str = StringUtils.contains(value, ".") ? value.substring(0, value.indexOf(".")) : value;
        int intgeo = Integer.parseInt(str);
        return intgeo;
    }

    /**
     * 转换成double类型
     * @param object
     * @return
     */
    public static Double toDouble(Object object){
        return Double.parseDouble(toString(object, "0"));
    }

    /**
     * 转换成Long类型
     * @param object
     * @return
     */
    public static Long toLong(Object object){
        return Long.parseLong(toString(object, "0"));
    }

    public static List<Long> toLongs(List<String> list) {
        List<Long> longs = new ArrayList<Long>();
        for (String str : list) {
            longs.add(toLong(str));
        }
        return longs;
    }

    public static List<String> toStrings(List<? extends Object> list){
        List<String> strings = new ArrayList<String>();
        for (Object obj : list) {
            strings.add(toString(obj));
        }
        return strings;
    }
    /**
     * 格式化Double值，返回String
     */
    public static String formatNumber(Number d, int scale) {
        if (d == null)
            return null;
        return String.format("%." + scale + "f", Double.parseDouble(d.toString()));
    }

    /**
     */
    public static String formatNumber(Number d, int length, int scale) {
        return formatNumber(d, length, scale, null);
    }

    public static String formatNumber(Number d, int length, int scale, String defaultValue) {
        if (d == null)
            return defaultValue;
        String value = formatNumber(d, scale); // 22.000000
        length = length + (scale > 0 ? 1 : 0);
        if (value.length() > length) {
            System.out.println("数值：" + value + "超出长度：" + length);
        }
        return StringUtils.right(value, length);
    }

    /**
     * 由于Java是基于Unicode编码的，因此，一个汉字的长度为1，而不是2。
     * 但有时需要以字节单位获得字符串的长度。例如，“123abc长城”按字节长度计算是10，而按Unicode计算长度是8。
     * 为了获得10，需要从头扫描根据字符的Ascii来获得具体的长度。如果是标准的字符，Ascii的范围是0至255，
     * 如果是汉字或其他全角字符，Ascii会大于255。
     * 因此，可以编写如下的方法来获得以字节为单位的字符串长度。
     */
    public static int getWordCount(String s) {
        if(StringUtils.isBlank(s))
            return 0;
        int length = 0;
        for (int i = 0; i < s.length(); i++) {
            int ascii = Character.codePointAt(s, i);
            if (ascii >= 0 && ascii <= 255)
                length++;
            else
                length += 2;

        }
        return length;

    }

    /**
     * 基本原理是将字符串中所有的非标准字符（双字节字符）替换成两个标准字符（**，或其他的也可以）。
     * 这样就可以直接例用length方法获得字符串的字节长度了
     */
    public static int getWordCountRegex(String s) {
        if(StringUtils.isBlank(s))
            return 0;
        s = s.replaceAll("[^\\x00-\\xff]", "**");
        int length = s.length();
        return length;
    }

    /**
     * 按特定的编码格式获取长度
     */
    public static int getWordCountCode(String str, String code) throws UnsupportedEncodingException {
        if(StringUtils.isBlank(str))
            return 0;
        return str.getBytes(code).length;
    }

    /**
     * 从左向右截取字符串，ascii取1，Unicode取2
     * @param str
     * @param length
     * @return
     */
    public static String left(String str, int length){
        if(StringUtils.isBlank(str))
            return str;
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i< str.length(); i++) {
            if(length >= getWordCount(StringUtils.substring(str, 0, i+1))){
                sb.append(str.charAt(i));
            }else{
                break;
            }
        }
        return sb.toString();
    }

    public static boolean isBlank(String string) {
        return StringUtils.isBlank(string) || "null".equalsIgnoreCase(string);
    }

    public static boolean isNotBlank(String string) {
        return !isBlank(string);
    }

    /**
     * 生成随机盐值
     */
    public static String generateRandomSalt(){
        return new String(Base64.encodeBase64(RandomStringUtils.random(8).getBytes()));
    }

    public static void main(String[] args) {
        NumberFormat format = NumberFormat.getInstance();
        System.out.println(format.format(10000000000000d).replace(",", ""));
    }

    /**
     * 分割字符串并转换为数值数组
     * @param value
     * @return
     */
    public static int[] splitToInt(String value) {
        return splitToInt(value, ",");
    }

    /**
     * 获取一定长度的随机字符串
     * @param length 指定字符串长度
     * @return 一定长度的字符串
     */
    public static String generateRandomStrByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    /**
     * 分割字符串并转换为数值数组
     * @param value
     * @return
     */
    public static int[] splitToInt(String value, String split) {
        String[] arr = StringUtils.split(value,split);
        int[] intArr = new int[arr.length];
        for (int i = 0; i< arr.length; i++) {
            intArr[i] = Integer.parseInt(arr[i]);
        }
        return intArr;
    }
    
}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/ObjectReflectUtils.java<|end_filename|>
package com.kanasinfo.utils;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class ObjectReflectUtils {
	
	public static Map<String,String> getAllParams(Object model) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		Map<String,String> map = new HashMap<String,String>();
		for(Class<?> clazz = model.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {   
			Field[] field = null;        //获取实体类的所有属性，返回Field数组  
			try {    
	            field =  clazz.getDeclaredFields();
	        } catch (Exception e) {    
	            //这里甚么都不要做！并且这里的异常必须这样写，不能抛出去。    
	            //如果这里的异常打印或者往外抛，则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了                      
	        }     
			for(int j=0 ; j<field.length ; j++){     //遍历所有属性
				String name = field[j].getName();    //获取属性的名字
				if("interfaceName".equals(name)||"enterpriseCode".equals(name)){
					continue;
				}
				String newName = name.substring(0,1).toUpperCase()+name.substring(1); //将属性的首字符大写，方便构造get，set方法
				String type = field[j].getGenericType().toString();    //获取属性的类型
				Method m = clazz.getMethod("get"+newName);
				if("class java.lang.Date".equals(type)){
					
					Date date = (Date) m.invoke(model);
					if(date != null){
						map.put(name, date.toLocaleString());
					}
				}else{
					Object inte = m.invoke(model);
					if(inte != null){
						map.put(name, inte.toString());
					}
				}
			}
		}
		System.out.println("params:"+map.toString());
        return map;
    }

	public static Map<String, Object> getMap(Object o) {
	    Map<String, Object> result = new HashMap<String, Object>();
	    Class clazz = o.getClass();
	    Field[] declaredFields = clazz.getDeclaredFields();
	    
	    for (Field field : declaredFields) {
	        try {
	        	Method method = clazz.getDeclaredMethod("get" + StringUtils.capitalize(field.getName()));
				result.put(field.getName(), method.invoke(o));
			} catch (Exception e) {
				e.printStackTrace();
			}
	    }
	    return result;
	}
}


<|start_filename|>speedy-ext-websocket/src/main/java/com/kanasinfo/config/WebSocketConfig.java<|end_filename|>
package com.kanasinfo.config;

import com.kanasinfo.web.MessageWebSocketInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

import java.security.Principal;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");
        registry.setUserDestinationPrefix("/user");
        registry.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/gs-guide-websocket")
                .addInterceptors(new MessageWebSocketInterceptor())
                .setAllowedOrigins("*").withSockJS()
                .setStreamBytesLimit(512 * 1024)
                .setHttpMessageCacheSize(1000)
                .setDisconnectDelay(30 * 1000);
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.setInterceptors(new ChannelInterceptorAdapter() {

            @Override
            public Message<?> preSend(Message<?> message, MessageChannel channel) {

                StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

                if (StompCommand.CONNECT.equals(accessor.getCommand())) {
                    String token = accessor.getFirstNativeHeader("X-Authorization");
                    Principal user = () -> "ggffss";
                    accessor.setUser(user);
                }


                return message;
            }
        });
    }

}

<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/common/ObjectIdEditor.java<|end_filename|>
package com.kanasinfo.ext.mvc.common;

import com.kanasinfo.utils.StringKit;
import org.bson.types.ObjectId;

import java.beans.PropertyEditorSupport;

public class ObjectIdEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) throws IllegalArgumentException {

        setValue(StringKit.isBlank(text) ? null : new ObjectId(text));
    }

    @Override
    public String getAsText() {
        return getValue().toString();
    }
}


<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/utils/HttpVerifyUtils.java<|end_filename|>
package com.kanasinfo.ext.mvc.utils;


import com.kanasinfo.utils.EncryptUtils;

/**
 * 进行请求校验
 * Created by user on 2016/9/17.
 */
public final class HttpVerifyUtils {
    /**
     * 规则：“httpBody + {salt}。（盐值）”做sha1摘要
     */
    public static String getDigestValue(String httpBody, String secretKey) {
        String value = httpBody + String.format("{%s}", secretKey);
        String sha1Value = EncryptUtils.sha1(value);
        return sha1Value;
    }
}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/PropKit.java<|end_filename|>
package com.kanasinfo.utils;

import com.kanasinfo.utils.gson.GsonUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;

/**
 * properties文件加载器
 * Created by Devid on 2016/12/5.
 */
public final class PropKit {
    /**
     * 获取properties文件
     */
    public static Properties getProps(String propFilePath) throws IOException {
        InputStream inputStream = PropKit.class.getResourceAsStream(propFilePath);
        Properties properties = new Properties();
        properties.load(inputStream);
        return properties;
    }

    /**
     * 根据字符串json形式，获取key对应的Value
     * @param propString
     * @param key
     * @return
     */
    public static String getPropValue(String propString, String key) {
        Map<String, String> props = GsonUtils.getGson(true).fromJson(propString, Map.class);
        return props.get(key);
    }
}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/DateUtils.java<|end_filename|>
package com.kanasinfo.utils;

import org.joda.time.DateTime;

import java.util.Date;

/**
 * 日期处理相关类
 * Created by Devid on 2016/12/2.
 */
public class DateUtils {
    public static String format(Date date, String pattern) {
        return date == null ? "" : new DateTime(date).toString(pattern);
    }
}


<|start_filename|>speedy-ext-websocket/src/main/java/com/kanasinfo/model/Greeting.java<|end_filename|>
package com.kanasinfo.model;

/**
 * Created by gefangshuai on 2017/5/29.
 */
public class Greeting {
    private String content;
    public Greeting(String content) {
        this.content = content;
    }
    public String getContent() {
        return content;
    }
}


<|start_filename|>speedy-sample/src/main/java/com/kanasinfo/demo/controller/IndexController.java<|end_filename|>
package com.kanasinfo.demo.controller;

import com.kanasinfo.demo.config.TestConfig;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Created by gefan on 2016/1/4.
 */
@Controller
public class IndexController {
    @Autowired
    private TestConfig testConfig;

    @RequestMapping("/")
    public String index(){
        return "index";
    }

    @RequestMapping("/login")
    public String login(){
        if (SecurityUtils.getSubject().isAuthenticated()) {
            return "redirect:/";
        }
        return "login";
    }

}


<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/annotation/Menu.java<|end_filename|>
package com.kanasinfo.ext.mvc.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 菜单注解，与前台映射
 * Created by gefangshuai on 2015/11/13.
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Menu {
    String value() default "";
}


<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/common/SupportController.java<|end_filename|>
package com.kanasinfo.ext.mvc.common;

import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;

import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * @author J.Mars
 */
public abstract class SupportController {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static final String BUSINESS_EXCEPTION_KEY = "bsExpCode";

    protected final Logger logger;

    public SupportController() {
        logger = LoggerFactory.getLogger(this.getClass());
    }


    @InitBinder
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(DEFAULT_DATETIME_FORMAT);
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
//        binder.registerCustomEditor(ObjectId.class, new ObjectIdEditor());
    }

    /**
     * 将错误信息统一打到页面，Key为"code"
     *
     * @param object
     * @param model
     */
    protected void addBusinessExceptionAttribute(Object object, Model model) {
        model.addAttribute(BUSINESS_EXCEPTION_KEY, object);
    }

}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/gson/GsonUtils.java<|end_filename|>
package com.kanasinfo.utils.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapterFactory;

import java.text.DateFormat;

public class GsonUtils {
    private static Gson instance = null;

    public synchronized static Gson getGson(Boolean excludeFieldsWithoutExposeAnnotation, TypeAdapterFactory... adapterFactories) {
        if (instance == null) {
            GsonBuilder builder = new GsonBuilder();
            builder.addSerializationExclusionStrategy(new IgnoreStrategy());
            if (excludeFieldsWithoutExposeAnnotation)
                builder.excludeFieldsWithoutExposeAnnotation();
            builder.registerTypeAdapter(java.util.Date.class, new DateSerializer()).setDateFormat(DateFormat.LONG);
            builder.registerTypeAdapter(java.util.Date.class, new DateDeserializer()).setDateFormat(DateFormat.LONG);
            for (TypeAdapterFactory adapter : adapterFactories) {
                builder.registerTypeAdapterFactory(adapter);
            }
            instance = builder.create();
        }
        return instance;
    }

    public synchronized static Gson getGson(TypeAdapterFactory... adapterFactories) {
        if (instance == null) {
            GsonBuilder builder = new GsonBuilder();
            builder.addSerializationExclusionStrategy(new IgnoreStrategy());
            builder.registerTypeAdapter(java.util.Date.class, new DateSerializer()).setDateFormat(DateFormat.LONG);
            builder.registerTypeAdapter(java.util.Date.class, new DateDeserializer()).setDateFormat(DateFormat.LONG);
            for (TypeAdapterFactory adapter : adapterFactories) {
                builder.registerTypeAdapterFactory(adapter);
            }
            instance = builder.create();
        }
        return instance;
    }
}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/gson/IgnoreStrategy.java<|end_filename|>
package com.kanasinfo.utils.gson;

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;

import java.lang.annotation.Annotation;
import java.util.Collection;

public class IgnoreStrategy implements ExclusionStrategy {

    /* 
     * (non-Javadoc) 
     *  
     * @see com.google.gson.ExclusionStrategy#shouldSkipClass(java.lang.Class) 
     */
    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }

    /* 
     * (non-Javadoc) 
     *  
     * @see com.google.gson.ExclusionStrategy#shouldSkipField(com.google.gson. 
     * FieldAttributes) 
     */
    @Override
    public boolean shouldSkipField(FieldAttributes fieldAttributes) {
        Collection<Annotation> annotations = fieldAttributes.getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation.annotationType() == GsonIgnore.class) {
                return true;
            }
        }
        return false;
    }

}  

<|start_filename|>speedy-sample/src/main/java/com/kanasinfo/demo/config/ShiroConfiguration.java<|end_filename|>
package com.kanasinfo.demo.config;

import com.kanasinfo.demo.service.UserService;
import com.kanasinfo.demo.model.User;
import com.kanasinfo.ext.shiro.ShiroExtConfiguration;
import com.kanasinfo.ext.shiro.ShiroExtRealm;
import com.kanasinfo.ext.shiro.bean.ShiroExtConfig;
import com.kanasinfo.ext.shiro.bean.ShiroUser;
import com.kanasinfo.ext.shiro.bean.UserModel;
import com.kanasinfo.ext.shiro.filter.ShiroExtFormAuthenticationFilter;
import org.apache.log4j.Logger;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * Created by gefangshuai on 2016/1/5.
 */
@Configuration
public class ShiroConfiguration extends ShiroExtConfiguration implements ApplicationContextAware{
    private Logger logger = Logger.getLogger(ShiroConfiguration.class);
    private ApplicationContext context;

    @Override
    protected ShiroExtConfig shiroExtConfig() {
        return new ShiroExtConfig() {
            @Override
            public ShiroExtRealm getShiroExtRealm() {
                return new ShiroExtRealm() {
                    @Override
                    protected UserModel getUserByUsername(String username) {
                        UserService userService = (UserService) context.getBean("userService");
                        User user = userService.findByUsername(username);
                        return user;
                    }

                    @Override
                    protected Set<String> getRolesByUsername(String username) {
                        return null;
                    }

                    @Override
                    protected Set<String> getPermissionsByUsername(String username) {
                        return null;
                    }
                };
            }

            @Override
            public ShiroExtFormAuthenticationFilter getShiroServerFormAuthenticationFilter() {
                return new ShiroExtFormAuthenticationFilter() {
                    @Override
                    protected void doSomethingOnLoginSuccess(ApplicationContext context, AuthenticationToken token, ShiroUser shiroUser, Subject subject, ServletRequest request, ServletResponse response) {
                        logger.debug("login success!");
                    }
                };
            }

            @Override
            public String getLoginUrl() {
                return "/login";
            }

            @Override
            public String getSuccessUrl() {
                return "/";
            }

            @Override
            public String getUnauthorizedUrl() {
                return "/unauthorized";
            }

            @Override
            public Map<String, String> getFilterChainDefinitionMap() {
                Map<String, String> filterMap = new LinkedHashMap<>();
                filterMap.put("/favicon.ico", "anon");
                filterMap.put("/static/**", "anon");
                filterMap.put("/u/**", "anon");
                filterMap.put("/p/**", "authc");
                filterMap.put("/login", "authc");
                filterMap.put("/**", "anon");
//                filterMap.put("/**", "authc");
                return filterMap;
            }
        };
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
}


<|start_filename|>speedy-portal/src/main/webapp/static/Source-Files/bower_components/jquery.counterup/.bower.json<|end_filename|>
{
  "name": "jquery.counterup",
  "homepage": "https://github.com/ciromattia/jquery.counterup",
  "description": "A lightweight jQuery plugin that counts up to a targeted number when the number becomes visible.",
  "main": "jquery.counterup.js",
  "moduleType": [],
  "keywords": [
    "jquery",
    "plugin",
    "counter",
    "count",
    "up",
    "number",
    "figure",
    "numeric",
    "int",
    "float",
    "animation"
  ],
  "dependencies": {
    "jquery": ">=1.5",
    "waypoints": ">=4.0"
  },
  "bugs": "https://github.com/ciromattia/jquery.counterup/issues",
  "demo": "http://ciromattia.github.io/jquery.counterup/demo/index.html",
  "authors": [
    "<NAME>",
    "<NAME>",
    "<NAME>"
  ],
  "license": "GPL-2.0",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "version": "2.0.4",
  "_release": "2.0.4",
  "_resolution": {
    "type": "version",
    "tag": "2.0.4",
    "commit": "e16b75b13f22c1d020ff6e1d196312f2e6eb1d94"
  },
  "_source": "https://github.com/ciromattia/jquery.counterup.git",
  "_target": "^2.0.4",
  "_originalSource": "jquery.counterup",
  "_direct": true
}

<|start_filename|>speedy-ext-persistence/src/main/java/com/kanasinfo/ext/persistence/SupportMongoModel.java<|end_filename|>
package com.kanasinfo.ext.persistence;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

/**
 * Created by gefangshuai on 2015/11/13.
 */
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class SupportMongoModel implements Serializable {
    @Id
    @JsonSerialize(using = ObjectIdSerializer.class)
    private ObjectId id;

    @CreatedDate
    private Date createdDate;

    @LastModifiedDate
    private Date lastModifiedDate;

    @CreatedBy
    private ObjectId createdBy;

    @LastModifiedBy
    private ObjectId lastModifiedBy;

    public SupportMongoModel() {
    }

    public ObjectId getId() {
        return id;
    }

    public void setId(ObjectId id) {
        this.id = id;
    }

    public Date getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }

    public Date getLastModifiedDate() {
        return lastModifiedDate;
    }

    public void setLastModifiedDate(Date lastModifiedDate) {
        this.lastModifiedDate = lastModifiedDate;
    }

    public ObjectId getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(ObjectId createdBy) {
        this.createdBy = createdBy;
    }

    public ObjectId getLastModifiedBy() {
        return lastModifiedBy;
    }

    public void setLastModifiedBy(ObjectId lastModifiedBy) {
        this.lastModifiedBy = lastModifiedBy;
    }

    @Transient
    public boolean isNew() {
        return id == null;
    }

    @Transient
    public boolean isNotNew() {
        return !isNew();
    }
}


<|start_filename|>speedy-portal/src/main/webapp/static/Source-Files/old-main-2.css<|end_filename|>
@import url(https://fonts.googleapis.com/css?family=Poppins:400,600);
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,300);
body,
html {
    font-family: Open Sans, sans-serif;
    font-weight: 400;
    color: #2b2c2d;
    font-size: 12px;
    line-height: 1.75em
}
@media (min-width: 600px) {
    body,
    html {
        font-size: calc(12px + 3 * ((100vw - 600px) / 540))
    }
}
@media (min-width: 1140px) {
    body,
    html {
        font-size: 15px
    }
}
a,
abbr,
acronym,
address,
b,
big,
blockquote,
caption,
center,
cite,
code,
dd,
del,
dfn,
dl,
dt,
em,
fieldset,
form,
h1,
h2,
h3,
h4,
h5,
h6,
i,
img,
ins,
kbd,
label,
legend,
li,
ol,
p,
pre,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
table,
tbody,
td,
tfoot,
th,
thead,
tr,
tt,
u,
ul,
var {
    margin: 0;
    padding: 0
}
address,
blockquote,
dl,
ol,
p,
pre,
table,
ul {
    margin-bottom: 1.75em
}
h1,
h2,
h3,
h4,
h5,
h6 {
    font-family: Poppins, sans-serif;
    font-weight: 600;
    color: #2b2c2d;
    clear: both
}
h1 {
    font-size: 27.8543898685px;
    margin-top: .9424008253em;
    line-height: 1.1308809903em;
    margin-bottom: .1884801651em
}
@media (min-width: 600px) {
    h1 {
        font-size: calc(27.8543898685px + 6.9636 * ((100vw - 600px) / 540))
    }
}
@media (min-width: 1140px) {
    h1 {
        font-size: 34.8179873356px;
        margin-top: .9424008253em;
        line-height: 1.1308809903em;
        margin-bottom: .1884801651em
    }
}
h2 {
    font-size: 23.5370033519px;
    margin-top: 1.1152651681em;
    line-height: 1.3383182017em;
    margin-bottom: .2514831227em
}
@media (min-width: 600px) {
    h2 {
        font-size: calc(23.5370033519px + 5.88425 * ((100vw - 600px) / 540))
    }
}
@media (min-width: 1140px) {
    h2 {
        font-size: 29.4212541899px;
        margin-top: 1.1152651681em;
        line-height: 1.3383182017em;
        margin-bottom: .2457971048em
    }
}
h3 {
    font-size: 19.888804939px;
    margin-top: 1.3198379732em;
    line-height: 1.5838055678em;
    margin-bottom: .3037841038em
}
@media (min-width: 600px) {
    h3 {
        font-size: calc(19.888804939px + 4.9722 * ((100vw - 600px) / 540))
    }
}
@media (min-width: 1140px) {
    h3 {
        font-size: 24.8610061737px;
        margin-top: 1.3198379732em;
        line-height: 1.5838055678em;
        margin-bottom: .295820802em
    }
}
h4 {
    font-size: 16.8060715286px;
    margin-top: 1.5619355157em;
    line-height: 1.8743226189em;
    margin-bottom: .3681503615em
}
@media (min-width: 600px) {
    h4 {
        font-size: calc(16.8060715286px + 4.20152 * ((100vw - 600px) / 540))
    }
}
@media (min-width: 1140px) {
    h4 {
        font-size: 21.0075894107px;
        margin-top: 1.5619355157em;
        line-height: 1.8743226189em;
        margin-bottom: .3569977099em
    }
}
h5 {
    font-size: 14.2011569368px;
    margin-top: 1.8484409486em;
    line-height: 2.2181291384em;
    margin-bottom: .3696881897em
}
@media (min-width: 600px) {
    h5 {
        font-size: calc(14.2011569368px + 3.55029 * ((100vw - 600px) / 540))
    }
}
@media (min-width: 1140px) {
    h5 {
        font-size: 17.751446171px;
        margin-top: 1.8484409486em;
        line-height: 2.2181291384em;
        margin-bottom: .3696881897em
    }
}
h6 {
    font-size: 12px;
    margin-top: 2.1875em;
    line-height: 2.625em;
    margin-bottom: .5104166667em
}
@media (min-width: 600px) {
    h6 {
        font-size: calc(12px + 3 * ((100vw - 600px) / 540))
    }
}
@media (min-width: 1140px) {
    h6 {
        font-size: 15px;
        margin-top: 2.1875em;
        line-height: 2.625em;
        margin-bottom: .4739583333em
    }
}
blockquote {
    font-style: italic
}
blockquote cite {
    display: block;
    font-style: normal
}
pre {
    padding: .875em;
    margin-bottom: 1.75em
}
pre code {
    padding: 0
}
code {
    font-family: Courier New, Courier, Lucida Sans Typewriter, Lucida Typewriter, "monospace";
    padding: .0875em .2625em
}
big,
code,
small,
sub,
sup {
    line-height: 0
}
abbr,
acronym {
    border-bottom: 1px dotted currentColor;
    cursor: help
}
address {
    font-style: normal
}
dt {
    color: #2b2c2d;
    font-weight: 700
}
ul {
    padding-left: 1.1em
}
ol {
    padding-left: 1.4em
}
fieldset {
    padding: .875em 1.75em 1.75em;
    border-width: 1px;
    border-style: solid;
    max-width: 100%;
    margin-bottom: 1.8666666667em
}
@media (min-width: 1140px) {
    fieldset {
        margin-bottom: 2.0416666667em
    }
}
fieldset button,
fieldset input[type=submit] {
    margin-bottom: 0
}
legend {
    color: #2b2c2d;
    font-weight: 700
}
input[type=email],
input[type=password],
input[type=text],
textarea {
    display: block;
    max-width: 100%;
    padding: .4375em;
    font-size: 12px;
    margin-bottom: 1.2833333333em
}
@media (min-width: 600px) {
    input[type=email],
    input[type=password],
    input[type=text],
    textarea {
        font-size: calc(12px + 3 * ((100vw - 600px) / 540))
    }
}
@media (min-width: 1140px) {
    input[type=email],
    input[type=password],
    input[type=text],
    textarea {
        font-size: 15px;
        margin-bottom: .5395833333em
    }
}
button,
input[type=submit] {
    display: block;
    cursor: pointer;
    font-size: 12px;
    padding: .4375em 1.75em;
    margin-bottom: 1.1375em
}
@media (min-width: 600px) {
    button,
    input[type=submit] {
        font-size: calc(12px + 3 * ((100vw - 600px) / 540))
    }
}
@media (min-width: 1140px) {
    button,
    input[type=submit] {
        font-size: 15px;
        margin-bottom: 1.3125em
    }
}
label {
    display: block;
    padding-bottom: .21875em;
    margin-bottom: -.1458333333em
}
table {
    width: 100%;
    border-spacing: 0;
    border-collapse: collapse;
    margin-bottom: 2.3333333333em
}
@media (min-width: 1140px) {
    table {
        margin-bottom: 2.1em
    }
}
th {
    text-align: left;
    color: #2b2c2d;
    padding: .21875em .875em
}
@media (min-width: 1140px) {
    th {
        padding: .4375em .875em
    }
}
td {
    padding: .875em;
    padding: .21875em .875em
}
@media (min-width: 1140px) {
    td {
        padding: .4375em .875em
    }
}
body {
    font-family: Open Sans, sans-serif;
    -webkit-font-smoothing: antialiased
}
::-moz-selection {
    background-color: #2b2c2d;
    color: #fff
}
::selection {
    background-color: #2b2c2d;
    color: #fff
}
ul {
    list-style: none
}
a {
    text-decoration: none!important
}
.light-text {
    color: #c2c2c2
}
.zero-padding {
    padding: 0!important
}
.mbn {
    margin-bottom: 0!important
}
.mb10 {
    margin-bottom: 10px!important
}
.mb20 {
    margin-bottom: 20px!important
}
.mb30 {
    margin-bottom: 30px!important
}
.mb40 {
    margin-bottom: 40px!important
}
.mb50 {
    margin-bottom: 50px!important
}
.mb60 {
    margin-bottom: 60px!important
}
.mtn {
    margin-top: 0!important
}
.mt10 {
    margin-top: 10px!important
}
.mt20 {
    margin-top: 20px!important
}
.mt30 {
    margin-top: 30px!important
}
.mt40 {
    margin-top: 40px!important
}
.mt50 {
    margin-top: 50px!important
}
.mt60 {
    margin-top: 60px!important
}
.mln {
    margin-left: 0
}
.ml10 {
    margin-left: 10px
}
.ml20 {
    margin-left: 20px
}
.ml30 {
    margin-left: 30px
}
.ml40 {
    margin-left: 40px
}
.ml50 {
    margin-left: 50px
}
.ml60 {
    margin-left: 60px
}
.mrn {
    margin-right: 0
}
.mr10 {
    margin-right: 10px
}
.mr20 {
    margin-right: 20px
}
.mr30 {
    margin-right: 30px
}
.mr40 {
    margin-right: 40px
}
.mr50 {
    margin-right: 50px
}
.mr60 {
    margin-right: 60px
}
.pbn {
    padding-bottom: 0!important
}
.pb10 {
    padding-bottom: 10px
}
.pb20 {
    padding-bottom: 20px
}
.pb30 {
    padding-bottom: 30px
}
.pb40 {
    padding-bottom: 40px
}
.pb50 {
    padding-bottom: 50px
}
.pb60 {
    padding-bottom: 60px
}
.pb70 {
    padding-bottom: 70px
}
.pb80 {
    padding-bottom: 80px
}
.ptn {
    padding-top: 0!important
}
.pt10 {
    padding-top: 10px
}
.pt20 {
    padding-top: 20px
}
.pt30 {
    padding-top: 30px
}
.pt40 {
    padding-top: 40px
}
.pt50 {
    padding-top: 50px
}
.pt60 {
    padding-top: 60px
}
.pt70 {
    padding-top: 70px
}
.pt80 {
    padding-top: 80px
}
.pt90 {
    padding-top: 90px
}
.pln {
    padding-left: 0
}
.pl10 {
    padding-left: 10px
}
.pl20 {
    padding-left: 20px
}
.pl30 {
    padding-left: 30px
}
.pl40 {
    padding-left: 40px
}
.pl50 {
    padding-left: 50px
}
.pl60 {
    padding-left: 60px
}
.prn {
    padding-right: 0
}
.pr10 {
    padding-right: 10px
}
.pr20 {
    padding-right: 20px
}
.pr30 {
    padding-right: 30px
}
.pr40 {
    padding-right: 40px
}
.pr50 {
    padding-right: 50px
}
.pr60 {
    padding-right: 60px
}
.white-color {
    color: #fff!important
}
.underline {
    position: relative;
    padding-bottom: .667em;
    margin-bottom: 1.5em
}
.underline:after {
    content: "";
    width: 32px;
    height: 1px;
    background: #c2c2c2;
    position: absolute;
    bottom: 0;
    left: 0
}
.full-underline:after {
    width: 100%
}
.longer-underline:after {
    width: 60px
}
.text-center .underline:after {
    width: 4%;
    left: 48%
}
.text-center .longer-underline:after {
    width: 8%;
    left: 46%
}
.text-muted {
    font-size: 85%;
    font-style: italic
}
.boxed {
    background: url(../images/boxed-bg.png)
}
.boxed>.container {
    background: #fff;
    box-shadow: 0 2px 10px 1px rgba(0, 0, 0, .2);
    padding: 0
}
button,
input[type=button],
input[type=reset],
input[type=submit] {
    background-color: #4aa3df;
    color: #fff;
    border: 1px solid #4aa3df;
    -webkit-transition: all .4s ease-in-out;
    transition: all .4s ease-in-out;
    outline: none!important;
    box-shadow: none!important
}
button:active,
button:focus,
button:hover,
input[type=button]:active,
input[type=button]:focus,
input[type=button]:hover,
input[type=reset]:active,
input[type=reset]:focus,
input[type=reset]:hover,
input[type=submit]:active,
input[type=submit]:focus,
input[type=submit]:hover {
    background-color: #fff;
    color: #4aa3df;
    border: 1px solid #4aa3df
}
.btn {
    font-family: Poppins, sans-serif;
    letter-spacing: .1em;
    text-transform: uppercase;
    height: 40px;
    line-height: 40px;
    padding: 0 30px;
    -webkit-transition: all .4s ease-in-out;
    transition: all .4s ease-in-out
}
.btn.se-btn {
    background: #4aa3df;
    color: #fff
}
.btn.se-btn:hover {
    background: #fff;
    color: #4aa3df
}
.btn.se-btn-black {
    background: #2b2c2d;
    color: #fff
}
.btn.se-btn-black:hover {
    background: #fff;
    color: #2b2c2d
}
.btn.se-btn-white {
    background: #fff;
    color: #4aa3df
}
.btn.se-btn-white:hover {
    background: #4aa3df;
    color: #fff
}
.btn.btn-rounded {
    border-radius: 30px
}
.badge {
    padding: 4px 12px;
    background: #4aa3df;
    border-radius: 2px;
    margin: 0 5px;
    text-transform: uppercase;
    letter-spacing: .1em
}
.learn-more {
    color: #4aa3df;
    padding: 0 10px;
    -webkit-transition: all .4s ease-in-out;
    transition: all .4s ease-in-out
}
.learn-more:after {
    content: "\f054";
    font-family: FontAwesome;
    margin-left: 5px;
    font-size: .8em
}
input:not([type]),
input[type=color],
input[type=date],
input[type=datetime-local],
input[type=datetime],
input[type=email],
input[type=month],
input[type=number],
input[type=password],
input[type=search],
input[type=tel],
input[type=text],
input[type=time],
input[type=url],
input[type=week],
textarea {
    border: 1px solid #ececec;
    background: #fff;
    padding: .618em 1em;
    font-family: Poppins, sans-serif;
    box-shadow: none;
    min-height: 40px;
    width: 100%
}
input:not([type]):active,
input:not([type]):focus,
input:not([type]):hover,
input[type=color]:active,
input[type=color]:focus,
input[type=color]:hover,
input[type=date]:active,
input[type=date]:focus,
input[type=date]:hover,
input[type=datetime-local]:active,
input[type=datetime-local]:focus,
input[type=datetime-local]:hover,
input[type=datetime]:active,
input[type=datetime]:focus,
input[type=datetime]:hover,
input[type=email]:active,
input[type=email]:focus,
input[type=email]:hover,
input[type=month]:active,
input[type=month]:focus,
input[type=month]:hover,
input[type=number]:active,
input[type=number]:focus,
input[type=number]:hover,
input[type=password]:active,
input[type=password]:focus,
input[type=password]:hover,
input[type=search]:active,
input[type=search]:focus,
input[type=search]:hover,
input[type=tel]:active,
input[type=tel]:focus,
input[type=tel]:hover,
input[type=text]:active,
input[type=text]:focus,
input[type=text]:hover,
input[type=time]:active,
input[type=time]:focus,
input[type=time]:hover,
input[type=url]:active,
input[type=url]:focus,
input[type=url]:hover,
input[type=week]:active,
input[type=week]:focus,
input[type=week]:hover,
textarea:active,
textarea:focus,
textarea:hover {
    border: 1px solid #d3d3d3;
    outline: 0;
    box-shadow: none
}
.inp-rounded {
    border-radius: 30px
}
.animated {
    -webkit-animation-duration: .4s;
    animation-duration: .4s
}
@media (min-width: 992px) {
    ul.nav li.dropdown:hover>ul.dropdown-menu {
        display: block
    }
}
.navbar-nav>li>a {
    color: #fff;
    text-transform: uppercase;
    letter-spacing: .05em;
    line-height: 30px;
    -webkit-transition: all .4s ease-in-out;
    transition: all .4s ease-in-out
}
.navbar-fixed-top {
    border: 0
}
.navbar {
    -webkit-transition: all .4s ease-in-out;
    transition: all .4s ease-in-out
}
.navbar-brand {
    height: 60px
}
.navbar-brand img {
    height: 30px
}
.navbar-brand .dark-logo {
    display: none
}
.nav>li:not(.nav-btn-wrap):focus,
.nav>li:not(.nav-btn-wrap):hover {
    background: #217dbb
}
.dark-header .nav>li:not(.nav-btn-wrap):focus>a,
.dark-header .nav>li:not(.nav-btn-wrap):hover>a {
    color: #ffffff
}
.nav>li>a:focus,
.nav>li>a:hover {
    background: #217dbb
}
.nav .open>a,
.nav .open>a:focus,
.nav .open>a:hover {
    background: #217dbb
}
.yamm .yamm-content {
    padding: 0
}
.yamm .collapse,
.yamm .dropdown,
.yamm .dropup,
.yamm .nav {
    position: relative
}
.nav-btn {
    margin-top: 10px;
    display: inline-block
}
.dropdown-menu {
    background: #217dbb;
    border: 0;
    box-shadow: none;
    padding: 0;
    color: #fff;
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.15)
}
.dropdown-menu a {
    color: #fff;
    display: block;
    padding: 3px 0;
    -webkit-transition: all .4s ease-in-out;
    transition: all .4s ease-in-out
}
.dropdown-menu a:hover {
    padding-left: 6px;
}
.dropdown-menu a.btn {
    padding: 0
}
.dropdown-menu .yamm-content {
    display: table
}
.dropdown-menu .nav-col {
    display: table-cell;
    padding: 20px;
    min-width: 200px
}
.dropdown-menu .nav-col h1,
.dropdown-menu .nav-col h2,
.dropdown-menu .nav-col h3,
.dropdown-menu .nav-col h4,
.dropdown-menu .nav-col h5,
.dropdown-menu .nav-col h6 {
    margin-top: 0;
    margin-left: 0;
    font-weight: 400;
    color: #fff
}
.dropdown-menu .nav-col ul {
    padding-left: 0
}
.dropdown-menu .nav-col.dark-bg {
    background: #2b2c2d
}
.dd-left .dropdown-menu {
    right: 0;
    left: auto
}
.body-scrolled .dark-logo {
    display: inline-block
}
.body-scrolled .light-logo {
    display: none
}
.body-scrolled .navbar {
    box-shadow: 0 2px 10px 1px rgba(0, 0, 0, .1);
    background: #fff
}
.body-scrolled .navbar .navbar-nav>li>a {
    color: #2b2c2d
}
.body-scrolled .navbar .nav>li>a:focus,
.body-scrolled .navbar .nav>li:hover a {
    background: #217dbb;
    color: #fff
}
.dark-header .navbar-nav>li>a {
    color: #787878
}
.dark-header .nav>li>a:focus,
.dark-header .nav>li>a:hover {
    color: #fff;
    background: #217dbb
}
.dark-header .dark-logo {
    display: inline-block
}
.dark-header .light-logo {
    display: none
}
.breadcrumb {
    background: transparent;
    padding: 15px;
    margin-bottom: 0
}
.breadcrumb a {
    color: #787878;
    font-size: 95%;
    -webkit-transition: all .4s ease-in-out;
    transition: all .4s ease-in-out
}
.breadcrumb a:hover {
    color: #4aa3df
}
.breadcrumb .icon {
    margin: 0 5px
}
.navbar-header {
    position: relative;
    z-index: 1
}
.navbar-toggle {
    background: #fff
}
.navbar-toggle .icon-bar {
    background: #2b2c2d
}
.navbar-fixed-bottom .navbar-collapse,
.navbar-fixed-top .navbar-collapse {
    max-height: 500px
}

@media (max-width: 992px) {
    .navbar-nav {
        width: 100%
    }
    .dropdown-menu a,
    .navbar-nav>li>a {
        color: #787878
    }
    .navbar-collapse.in {
        background: #fff
    }
    .navbar-collapse.in .nav>li:not(.nav-btn-wrap):focus, .navbar-collapse.in .nav>li:not(.nav-btn-wrap):hover{
        background: #f2f2f2;
    }
    .navbar-collapse.in .nav>li>a:focus, .navbar-collapse.in .nav>li>a:hover{
        background: #f2f2f2;
    }
    .nav .open>a,
    .nav .open>a:focus,
    .nav .open>a:hover {
        background: #f2f2f2;
    }
    .dark-header .nav>li:not(.nav-btn-wrap):focus>a, .dark-header .nav>li:not(.nav-btn-wrap):hover>a{
        color: #222;
    }
    .dropdown-menu .nav-col h1, .dropdown-menu .nav-col h2, .dropdown-menu .nav-col h3, .dropdown-menu .nav-col h4, .dropdown-menu .nav-col h5, .dropdown-menu .nav-col h6{
        color: #222;
    }
    .dropdown-menu .nav-col.dark-bg h1, .dropdown-menu .nav-col.dark-bg h2, .dropdown-menu .nav-col.dark-bg h3, .dropdown-menu .nav-col.dark-bg h4, .dropdown-menu .nav-col.dark-bg h5, .dropdown-menu .nav-col.dark-bg h6{
        color: #fff;
    }
    .body-scrolled .navbar .nav>li>a:focus, .body-scrolled .navbar .nav>li:hover a{
        background: #f2f2f2;
        color: #787878;
    }
}
.main-header {
    height: 100vh
}
.main-header .primary-trans-bg {
    height: 100%;
    background-color: rgba(74, 163, 223, .9);
    color: #fff
}
.main-header .container {
    height: 100%
}
.main-header .h1,
.main-header h1 {
    font-size: 4.236em;
    font-family: Poppins, sans-serif;
    font-weight: 700
}
.main-header h5 {
    font-family: Open Sans, sans-serif;
    font-weight: 400;
    color: #fff;
    margin-bottom: 1.618em;
    letter-spacing: .04em
}
@media (max-width: 768px) {
    .main-header .h1,
    .main-header h1 {
        font-size: 2.618em
    }
}
.outer {
    display: table;
    width: 100%;
    height: 100%
}
.inner {
    display: table-cell;
    vertical-align: middle
}
.header-style-2 {
    height: 100vh;
    position: relative
}
.header-style-2 .primary-trans-bg {
    position: absolute;
    width: 100%;
    height: 100%
}
.header-style-3 {
    border-bottom: 1px solid #ececec;
    height: 100vh;
    position: relative
}
.header-style-3 .primary-trans-bg {
    position: absolute;
    width: 100%;
    height: 100%
}
.header-style-3 h1 {
    font-size: 2.618em;
    line-height: 1.25em
}
.img-shadow {
    box-shadow: 0 2px 10px 1px rgba(0, 0, 0, .2)
}
.swiper-container {
    width: 100%;
    height: 100%
}
.swiper-slide {
    text-align: center;
    background-color: #787878;
    background-size: cover;
    background-position: 50%
}
.swiper-slide .slide-text {
    position: absolute;
    z-index: 1;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, .6)
}
.swiper-button-next,
.swiper-container-rtl .swiper-button-prev {
    background-image: none
}
.swiper-button-next:after,
.swiper-container-rtl .swiper-button-prev:after {
    content: "\f3d1";
    position: absolute;
    font-family: Ionicons;
    display: inline-block;
    -webkit-font-smoothing: antialiased;
    top: 50%;
    right: 0;
    color: #4aa3df;
    font-size: 4.236em
}
.swiper-button-prev,
.swiper-container-rtl .swiper-button-next {
    background-image: none
}
.swiper-button-prev:after,
.swiper-container-rtl .swiper-button-next:after {
    content: "\f3cf";
    position: absolute;
    font-family: Ionicons;
    display: inline-block;
    -webkit-font-smoothing: antialiased;
    top: 50%;
    right: 0;
    color: #4aa3df;
    font-size: 4.236em
}
.swiper-pagination-bullet-active {
    background: #4aa3df
}
.se-section {
    padding: 90px 0;
    border-bottom: 1px solid #ececec
}
.gray-section {
    background: #f9f9f9
}
.gray-section p {
    margin-bottom: 0;
    color: #787878
}
section.parallax-bg {
    padding: 0;
    border: 0
}
.offer-section {
    padding: 35px
}
.black-gradient {
    padding: 90px 0;
    background: rgba(0, 0, 0, .6);
    border: 0
}
.black-gradient,
.black-gradient h1,
.black-gradient h2,
.black-gradient h3,
.black-gradient h4,
.black-gradient h5,
.black-gradient h6,
.black-gradient p {
    color: #fff!important
}
.primary-bg {
    background: #4aa3df;
    color: #f9f9f9
}
.primary-bg h1,
.primary-bg h2,
.primary-bg h3,
.primary-bg h4,
.primary-bg h5,
.primary-bg h6 {
    color: #fff
}
.pp-section p {
    color: #787878
}
.pp-section ul {
    color: #787878;
    padding-left: 30px;
    list-style: circle
}
.pp-section ul li {
    margin-bottom: 10px
}
.se-feature {
    text-align: center
}
.se-feature .icon {
    font-size: 2.618em;
    color: #4aa3df
}
.se-feature h5 {
    margin-top: 1em
}
.se-feature p {
    color: #787878;
    margin-bottom: 0
}
@media (max-width: 991px) {
    .se-feature {
        margin-bottom: 50px
    }
    .se-feature:last-child {
        margin-bottom: 0
    }
}
.se-feature-style-2 .left {
    float: left;
    width: 12%
}
.se-feature-style-2 .right {
    float: left;
    width: 88%
}
.se-feature-style-2 .icon {
    font-size: 2.618em
}
.se-feature-style-2 h5 {
    margin-top: 0
}
.se-feature-style-2 p {
    color: #787878;
    margin-bottom: 0
}
@media (max-width: 768px) {
    .se-feature-style-2 p {
        margin-bottom: 30px
    }
}
.se-feature-style-3 {
    text-align: center
}
.se-feature-style-3 h5 {
    margin-top: 1em
}
.se-feature-style-3 h5,
.se-feature-style-3 p {
    -webkit-transition: all .4s ease-in-out;
    transition: all .4s ease-in-out
}
.se-feature-style-3 p {
    color: #787878;
    margin-bottom: 1em
}
.se-feature-style-3 .feature-wrap {
    background: #f9f9f9;
    padding: 1.618em;
    border-radius: 6px;
    position: relative;
    margin-bottom: 40px;
    -webkit-transition: all .4s ease-in-out;
    transition: all .4s ease-in-out
}
.se-feature-style-3 .feature-wrap .icon {
    font-size: 2.618em;
    color: #4aa3df;
    -webkit-transition: all .4s ease-in-out;
    transition: all .4s ease-in-out
}
.se-feature-style-3:hover .feature-wrap {
    background: #4aa3df;
    color: #fff
}
.se-feature-style-3:hover .feature-wrap .icon {
    color: #fff
}
.se-feature-style-3:hover p {
    color: #f9f9f9
}
.se-feature-style-3:hover .learn-more,
.se-feature-style-3:hover h5 {
    color: #fff
}
.single-feature .side-img img {
    box-shadow: 0 2px 10px 1px rgba(0, 0, 0, .2)
}
.single-feature .feature-desc h2 {
    margin-bottom: 1em;
    width: 60%
}
.single-feature .feature-desc p {
    color: #787878
}
@media (min-width: 991px) {
    .single-feature .feature-desc .row {
        position: relative
    }
    .single-feature .feature-desc .feature-info {
        position: absolute
    }
}
ul.highlights {
    padding-left: 0
}
ul.highlights li {
    margin-bottom: .618em
}
ul.highlights .icon {
    margin-right: 10px;
    font-size: 80%
}
.se-steps {
    counter-reset: a
}
.se-steps h4 {
    position: relative;
    z-index: 0
}
.se-steps h4:before {
    content: counter(a);
    counter-increment: a;
    position: absolute;
    color: #f4f4f4;
    font-size: 4.236em;
    font-style: italic;
    z-index: -1
}
footer {
    padding: 90px 0 50px;
    background: #f9f9f9
}
footer .footer-logo {
    width: 80%
}
footer h6 {
    letter-spacing: .1em;
    font-size: .9em
}
footer ul {
    padding-left: 0
}
footer a {
    color: #787878;
    font-size: 90%
}
footer .footer-bottom {
    border-top: 1px dashed #ececec;
    padding: 20px 0
}
footer .footer-bottom p {
    font-size: 90%;
    color: #787878;
    margin-bottom: 0
}
footer .footer-bottom h6 {
    display: inline-block;
    padding: 0 10px;
    margin: 0;
    color: #787878
}
@media (max-width: 991px) {
    footer .col-md-6 {
        text-align: center!important
    }
}
.page-title {
    height: 50vh;
    background: url(../images/page-title-bg.png);
    position: relative
}
.page-title .container {
    height: 100%
}
.page-title h5 {
    font-family: Open Sans, sans-serif;
    color: #787878;
    font-weight: 400
}
.form-wrap {
    background: #f9f9f9;
    padding: 2.618em;
    box-shadow: 0 2px 10px 1px rgba(0, 0, 0, .2);
    color: #787878
}
.form-wrap .logo-wrap {
    margin-bottom: 1.618em
}
.form-wrap .social-login {
    border-top: 1px dashed #787878;
    padding-top: 1em
}
.form-wrap .social-login p {
    color: #787878;
    font-size: 90%
}
.form-wrap .social-login .btn {
    font-size: 80%;
    padding: 0 22px;
    margin: 0 5px
}
.form-wrap .social-login .fb-btn {
    background: #3b5998
}
.form-wrap .social-login .tw-btn {
    background: #00acee
}
.form-wrap .social-login .gp-btn {
    background: #dd4b39
}
.panel-title {
    font-size: 1em
}
.panel-title a {
    display: block
}
.panel-title a .icon {
    float: right;
    display: inline-block;
    line-height: inherit;
    -webkit-transform: rotate(135deg);
    transform: rotate(135deg);
    -webkit-transition: all .4s ease-in-out;
    transition: all .4s ease-in-out
}
.panel-title .collapsed .icon {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg)
}
#fullWidthMap {
    height: 400px
}
.contact-info p {
    color: #787878
}
.counter-box .count-icon {
    float: left;
    font-size: 4.236em;
    color: #787878;
    margin-right: 10px
}
.counter-box .count-info {
    float: left;
    text-align: center
}
.counter-box .count-info h4 {
    margin-top: 0;
    margin-bottom: 0
}
.se-plan {
    border: 1px solid #ececec;
    margin-bottom: 1em
}
.se-plan .plan-header {
    background: #2b2c2d;
    color: #fff;
    text-align: center;
    padding: 2.618em 1em
}
.se-plan .plan-header h2 {
    color: #fff;
    margin-top: 0
}
.se-plan .plan-header p {
    margin-bottom: 0
}
.se-plan .plan-header small {
    font-size: 60%;
    color: #fff
}
.se-plan .plan-features ul {
    margin-top: 10px;
    padding-left: 0;
    margin-bottom: 10px
}
.se-plan .plan-features li {
    line-height: 4.618em;
    padding-left: 20px;
    border-bottom: 1px dotted #ececec
}
.se-plan .plan-features li:last-child {
    border-bottom: 0
}
.se-plan .plan-features li .icon {
    float: right;
    margin-right: 20px;
    font-size: 1.618em
}
.se-plan.plan-popular .plan-header {
    background: #4aa3df;
    position: relative
}
.se-plan.plan-popular .plan-header:before {
    content: 'Popular';
    position: absolute;
    top: -30px;
    background: #1d6fa6;
    line-height: 30px;
    width: 100%;
    left: 0;
    font-family: Poppins, sans-serif;
    text-transform: uppercase;
    letter-spacing: .1em
}
.strike {
    text-decoration: line-through
}


<|start_filename|>speedy-ext-persistence/src/main/java/com/kanasinfo/ext/persistence/SupportRepository.java<|end_filename|>
package com.kanasinfo.ext.persistence;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;

import java.io.Serializable;

/**
 * 核心Dao接口
 * Created by gefangshuai on 2015/11/6.
 */
@NoRepositoryBean
public interface SupportRepository<T, ID extends Serializable> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {

}


<|start_filename|>speedy-ext-persistence/src/main/java/com/kanasinfo/ext/persistence/SupportService.java<|end_filename|>
package com.kanasinfo.ext.persistence;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.List;

/**
 * 核心 Service 类
 * Created by gefangshuai on 2015/11/16.
 */
@Transactional(readOnly = true)
public abstract class SupportService<T, ID extends Serializable> {
    protected abstract SupportRepository<T, ID> getRepository();

    public T findOne(ID id) {
        return getRepository().findOne(id);
    }

    @Transactional
    public T save(T t) {
        return getRepository().save(t);
    }

    public List<T> findAll() {
        return getRepository().findAll();
    }

    public List<T> findAll(Sort sort) {
        return getRepository().findAll(sort);
    }

    public Page<T> findAll(Pageable pageable){
        return getRepository().findAll(pageable);
    }

    @Transactional
    public void delete(ID id) {
        getRepository().delete(id);
    }

    public long count(){
        return getRepository().count();
    }

}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/QueryUtils.java<|end_filename|>
package com.kanasinfo.utils;

import org.apache.commons.lang3.StringUtils;

/**
 * 拼接Like查询字符串
 * Created by gefangshuai on 2015/11/30.
 */
public class QueryUtils {
    public static String getLike(String key){
        if (StringUtils.isBlank(key))
            key = "";
        return "%" + key + "%";
    }

    public static String getLeftLike(String key) {
        if (StringUtils.isBlank(key))
            key = "";
        return "%" + key;
    }

    public static String getRightLike(String key){
        if (StringUtils.isBlank(key))
            key = "";
        return key + "%";
    }
}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/MathUtils.java<|end_filename|>
package com.kanasinfo.utils;

import java.math.BigDecimal;

/**
 * 精度计算工具类
 * 
 * @author Devid
 *
 */
public class MathUtils {
	
	
	/**
	 * 加法
	 */
	public static double add(Double d1, Double d2) {
		BigDecimal b1 = new BigDecimal(d1);
		BigDecimal b2 = new BigDecimal(d2);
		return b1.add(b2).doubleValue();
	}

	/**
	 * 减法
	 */
	public static double sub(Double d1, Double d2) { 
		BigDecimal b1 = new BigDecimal(d1);
		BigDecimal b2 = new BigDecimal(d2);
		return b1.subtract(b2).doubleValue();
	}

	/**
	 * 乘法
	 */
	public static double mul(Double d1, Double d2) { // 进行乘法运算
		BigDecimal b1 = new BigDecimal(d1);
		BigDecimal b2 = new BigDecimal(d2);
		return b1.multiply(b2).doubleValue();
	}

	/**
	 * 除法
	 */
	public static double div(Double d1, Double d2, int len) {
		if (d1 == null || d2 == null) {
			System.out.println("[除法运算]数值为空");
			return 0;
		}
		if(d2.doubleValue() == 0) {
			System.out.println("[除法运算]分母为0");
			return 0;
		}
		BigDecimal b1 = new BigDecimal(d1);
		BigDecimal b2 = new BigDecimal(d2);
		return b1.divide(b2, len, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 对数值进行四舍五入操作
	 */
	public static double round(Double d, int len) { // 进行四舍五入操作
		BigDecimal b1 = new BigDecimal(d);
		BigDecimal b2 = new BigDecimal(1);
		// 任何一个数字除以1都是原数字
		// ROUND_HALF_UP是BigDecimal的一个常量， 表示进行四舍五入的操作
		return b1.divide(b2, len, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	public static void main(String[] args) {
        System.out.println(MathUtils.div(20.0, 0.0, 2));

    }
}


<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/common/BusinessHandler.java<|end_filename|>
package com.kanasinfo.ext.mvc.common;

public interface BusinessHandler<T> {
    public T handle() throws Exception;
}


<|start_filename|>speedy-sample/src/main/java/com/kanasinfo/demo/config/TestConfig.java<|end_filename|>
package com.kanasinfo.demo.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * Created by gefangshuai on 2017/5/16.
 */
@Component
@ConfigurationProperties(prefix = "test")
public class TestConfig {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}


<|start_filename|>speedy-portal/src/main/webapp/static/Source-Files/main.js<|end_filename|>
$(function($) {
    "use strict";

    // For page transitions
    $(".animsition").animsition();

    // For Matching all .campaign-card heights
	$(".nav-col").matchHeight();

    // For counters
	$(".counter").counterUp({
		delay: 10,
		time: 1000
	});

    // For Owl Carousel
    $(".owl-carousel-single").owlCarousel({
        loop: true,
        navRewind: false,
        margin: 10,
        dots: true,
        nav: false,
        autoplay: false,
        navText: [],
        items: 1
    });

    // For Swiper
    Swiper(".swiper-container", {
        loop: true,
        pagination: ".swiper-pagination",
        paginationClickable: true,
        nextButton: ".swiper-button-next",
        prevButton: ".swiper-button-prev"
    });

    // For Swiper Background Images
    $(".swiper-slide", "#swiper").each(function(){
        var bgImg = $(this).data("slide-img");
        $(this).css("background-image", "url(" + bgImg + ")");
    });

    // For Tooltips
    $("[data-toggle='tooltip']").tooltip();

    // For revealing elements on scroll
    var elemReveal = {
        delay: 200,
        duration: 600,
        distance: "60px",
        easing: "ease-in-out",
        rotate: { z: 0 },
        scale: 1.0
    };
    window.sr = ScrollReveal();
    sr.reveal(".one-step", elemReveal, 500);

    // For Text Animation in Header
    $("#animated-text").textillate({
        loop: true
    });

    // For changing body class on scroll
    $(window).on("scroll resize", function() {
        if ($(window).scrollTop() >= 75) {
            $("body").addClass("body-scrolled");
        }
        else {
            return $("body").removeClass("body-scrolled");
        }
    });


});


<|start_filename|>speedy-portal/src/main/java/com/kanasinfo/portal/controller/IndexController.java<|end_filename|>
package com.kanasinfo.portal.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Created by gefangshuai on 2017/4/9.
 */
@Controller
@RequestMapping("/")
public class IndexController {

    @RequestMapping
    public String index(){
        return "index";
    }

    @RequestMapping("/users")
    public String users(){
        return "users";
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login(){
        return "login";
    }

}


<|start_filename|>speedy-sample/src/main/java/com/kanasinfo/demo/controller/AccountController.java<|end_filename|>
package com.kanasinfo.demo.controller;

import com.kanasinfo.ext.mvc.utils.FlashMessageUtils;
import com.kanasinfo.demo.model.User;
import com.kanasinfo.demo.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.annotation.Resource;

/**
 * Created by gefangshuai on 2016/1/6.
 */
@Controller
@RequestMapping("/u")
public class AccountController {
    @Resource
    private UserService userService;


    @RequestMapping("/create")
    public String register(){
        return "register";
    }

    @RequestMapping(value = "/save-user", method = RequestMethod.POST)
    public String saveUser(User user, String confirm_password, RedirectAttributes redirectAttributes){
        if (StringUtils.isNotBlank(confirm_password) && confirm_password.equals(user.getPassword())) {
            user.encryptUser();
            userService.save(user);
            FlashMessageUtils.success(redirectAttributes, "注册成功，请登录！");
            return "redirect:/login";
        }else{
            FlashMessageUtils.error(redirectAttributes, "密码不符合标准!");
            return "redirect:/register";
        }
    }

    @RequestMapping("/logout")
    public String logout(RedirectAttributes redirectAttributes){
        SecurityUtils.getSubject().logout();
        FlashMessageUtils.success(redirectAttributes, "退出成功!");
        return "redirect:/login";
    }
}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/gson/DateSerializer.java<|end_filename|>
package com.kanasinfo.utils.gson;

import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import java.lang.reflect.Type;
import java.util.Date;

public class DateSerializer implements JsonSerializer<Date> {
    public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(src.getTime());
    }
}

<|start_filename|>speedy-ext-shiro/src/main/java/com/kanasinfo/ext/shiro/bean/ShiroExtConfig.java<|end_filename|>
package com.kanasinfo.ext.shiro.bean;

import com.kanasinfo.ext.shiro.filter.ShiroExtFormAuthenticationFilter;
import com.kanasinfo.ext.shiro.ShiroExtRealm;

import java.util.Map;

/**
 * Created by gefangshuai on 2016/1/5.
 */
public interface ShiroExtConfig {

    ShiroExtRealm getShiroExtRealm();
    ShiroExtFormAuthenticationFilter getShiroServerFormAuthenticationFilter();

    /**
     * 定义登陆url
     */
    String getLoginUrl();

    /**
     * 定义登陆成功跳转的Url
     */
    String getSuccessUrl();

    /**
     * 定义未授权跳转的Url
     */
    String getUnauthorizedUrl();

    /**
     * 定义权限过滤链
     */
    Map<String, String> getFilterChainDefinitionMap();

}


<|start_filename|>speedy-portal/src/main/webapp/WEB-INF/jsp/index.jsp<|end_filename|>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!doctype html>
<html class="no-js" lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- ========== VIEWPORT META ========== -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
    <!-- ========== PAGE TITLE ========== -->
    <title>SoftEase | Software, Mobile App & SaaS HTML template</title>
    <!-- ========== META TAGS ========== -->
    <meta name="description" content="HTML template for Software, Mobile App & SaaS applications.">
    <meta name="keywords" content="software, mobile app, saas">
    <meta name="author" content="ThemesEase">
    <!-- ========== FAVICON & APPLE ICONS ========== -->
    <link rel="shortcut icon" href="/static/images/favicon.png">
    <link rel="apple-touch-icon" href="/static/images/apple-touch-icon.png">
    <!-- ========== MINIFIED VENDOR CSS ========== -->
    <link rel="stylesheet" href="/static/css/vendor.css">
    <link rel="stylesheet" href="/static/css/main.css">
    <!-- ========== MODERNIZR ========== -->
    <script src="/static/js/vendor/modernizr.js"></script>
</head>

<!-- ========== BODY ==========
.light-header: for light colored header
.dark-header: for dark colored header
==========  ========== -->
<body class="light-header animsition">

<!-- ========== NAVIGATION ========== -->
<nav class="navbar yamm navbar-fixed-top" role="navigation">
    <div class="container-fluid">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button> <!-- end navbar-toggle -->
            <a class="navbar-brand" href="index.html">
                <img src="/static/images/light-logo.svg" alt="SoftEase Logo" class="light-logo">
                <img src="/static/images/dark-logo.svg" alt="SoftEase Logo" class="dark-logo">
            </a> <!-- end navbar-brand -->
        </div> <!-- end navbar-header -->

        <div id="navbar" class="navbar-collapse collapse">
            <ul class="nav navbar-nav pull-right">
                <li class="active dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Home <span class="caret"></span></a>
                    <ul class="dropdown-menu animated fadeIn">
                        <li>
                            <div class="yamm-content">
                                <div class="nav-col">
                                    <ul>
                                        <li><a href="index.html">Default Home</a></li>
                                        <li><a href="index-animated-bg.html">Animated Background</a></li>
                                        <li><a href="index-animated-text.html">Animated Text</a></li>
                                        <li><a href="index-simple.html">Animated + Image</a></li>
                                        <li><a href="index-slider.html">Home With Slider</a></li>
                                        <li><a href="index-boxed.html">Boxed Home</a></li>
                                    </ul>
                                </div> <!-- end nav-col -->
                            </div> <!-- end yamm-content -->
                        </li>
                    </ul> <!-- end dropdown-menu -->
                </li>
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Features <b class="caret"></b></a>
                    <ul class="dropdown-menu animated fadeIn">
                        <li>
                            <div class="yamm-content">
                                <div class="nav-col">
                                    <ul>
                                        <li><h5>FEATURES</h5></li>
                                        <li><a href="#">Demo Link</a></li>
                                        <li><a href="#">Demo Link</a></li>
                                        <li><a href="#">Demo Link</a></li>
                                        <li><a href="#">Demo Link</a></li>
                                    </ul>
                                </div> <!-- end nav-col -->
                                <div class="nav-col">
                                    <ul>
                                        <li><h5>FEATURES</h5></li>
                                        <li><a href="#">Demo Link</a></li>
                                        <li><a href="#">Demo Link</a></li>
                                        <li><a href="#">Demo Link</a></li>
                                        <li><a href="#">Demo Link</a></li>
                                    </ul>
                                </div> <!-- end nav-col -->
                                <div class="nav-col dark-bg text-center">
                                    <h4>Take a demo for FREE!</h4>
                                    <p class="light-text">This is for demo purpose only. </p>
                                    <a href="sign-up.html" class="btn se-btn btn-rounded">SIGN UP</a>
                                </div> <!-- end nav-col -->
                            </div> <!-- end yamm-content -->
                        </li>
                    </ul> <!-- end dropdown-menu -->
                </li> <!-- end dropdown (features) -->
                <li class="">
                    <a href="feature-details.html" class="" >Feature Details </a>
                </li>
                <li><a href="pricing.html">Pricing</a></li>
                <li><a href="about-us.html">About Us</a></li>
                <li class="dropdown dd-left">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Pages <span class="caret"></span></a>
                    <ul class="dropdown-menu animated fadeIn">
                        <li>
                            <div class="yamm-content">
                                <div class="nav-col">
                                    <ul>
                                        <li><a href="features.html">Features</a></li>
                                        <li><a href="feature-details.html">Feature Details</a></li>
                                        <li><a href="login.html">Login</a></li>
                                        <li><a href="sign-up.html">Sign Up</a></li>
                                        <li><a href="faqs.html">FAQs</a></li>
                                        <li><a href="contact-us.html">Contact Us</a></li>
                                        <li><a href="privacy-policy.html">Privacy Policy</a></li>
                                    </ul>
                                </div> <!-- end nav-col -->
                            </div> <!-- end yamm-content -->
                        </li>
                    </ul>
                </li> <!-- end dropdown.dd-left (pages) -->

                <li class="dropdown dd-left">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Blog <b class="caret"></b></a>
                    <ul class="dropdown-menu animated fadeIn">
                        <li>
                            <div class="yamm-content">
                                <div class="nav-col">
                                    <ul>
                                        <li><h5>Default</h5></li>
                                        <li><a href="blog.html">Default Layout</a></li>
                                        <li><a href="blog-2.html">Layout 2</a></li>
                                        <li><a href="blog-left-sidebar.html">Left Sidebar</a></li>
                                        <li><a href="blog-2-left-sidebar.html">Left Sidebar 2</a></li>
                                    </ul>
                                </div> <!-- end nav-col -->
                                <div class="nav-col">
                                    <ul>
                                        <li><h5>Single Post</h5></li>
                                        <li><a href="blog-single-post.html">Default</a></li>
                                        <li><a href="blog-single-left-sidebar.html">Left Sidebar</a></li>
                                        <li><a href="blog-single-post-full.html">Full Width</a></li>
                                    </ul>
                                </div> <!-- end nav-col -->
                                <div class="nav-col dark-bg text-center">
                                    <h4>Stay Updated!</h4>
                                    <p class="light-text">Subscribe to our newsletter. </p>
                                    <a href="sign-up.html" class="btn se-btn btn-rounded">SUBSCRIBE</a>
                                </div> <!-- end nav-col -->
                            </div> <!-- end yamm-content -->
                        </li>
                    </ul> <!-- end dropdown-menu -->
                </li> <!-- end dropdown (blog) -->
                <li class="nav-btn-wrap">
                    <span class="nav-btn"><a href="sign-up.html" class="btn se-btn-black btn-rounded">Sign Up</a></span>
                </li>
            </ul> <!-- end navbar-nav -->

        </div> <!--end nav-collapse -->
    </div> <!-- end container -->
</nav>

<!-- ========== HEADER ========== -->
<header class="header main-header parallax-bg" data-parallax="scroll" data-image-src="/static/images/bg-img-3.jpg" data-speed="0.4" >
    <div class="primary-trans-bg">
        <div class="container">
            <!-- For centering the content vertically -->
            <div class="outer">
                <div class="inner text-center">
                    <h1 class="white-color">Create Website That Will Impress Your Customers.</h1>
                    <h5 class="">One of the best HTML templates for Software, Mobile App or SaaS product.</h5>
                    <a href="#" class="btn se-btn-white btn-rounded">Free 30 Days Trial</a>
                </div> <!-- end inner -->
            </div> <!-- end outer -->
        </div> <!-- end container -->
    </div> <!-- end primary-trans-bg -->
</header>

<!-- ========== OFFER SECTION ========== -->
<section class="se-section offer-section gray-section">
    <div class="container">
        <div class="row">
            <div class="col-md-12 text-center">
                <p><span class="badge">FREE</span> This is best place to offer something more to customer & increase the conversion rate. <a href="#" class="learn-more">Learn More</a></p>
            </div>
        </div> <!-- end row -->
    </div> <!-- end container -->
</section>

<!-- ========== FEATURES ========== -->
<section class="se-section features-section">
    <div class="container">
        <div class="row">

            <div class="col-md-3 col-sm-6 se-feature">
                <i class="icon ion-ios-analytics-outline"></i>
                <h5>Fully Responsive</h5>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut.</p>
            </div> <!-- end se-feature -->

            <div class="col-md-3 col-sm-6 se-feature">
                <i class="icon ion-ios-paper-outline"></i>
                <h5>Well Documented</h5>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut.</p>
            </div> <!-- end se-feature -->

            <div class="col-md-3 col-sm-6 se-feature">
                <i class="icon ion-ios-lightbulb-outline"></i>
                <h5>Easy To Use</h5>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut.</p>
            </div> <!-- end se-feature -->

            <div class="col-md-3 col-sm-6 se-feature">
                <i class="icon ion-ios-speedometer-outline"></i>
                <h5>Lightning Fast</h5>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut.</p>
            </div> <!-- end se-feature -->

        </div> <!-- end row -->
    </div> <!-- end container -->
</section>

<!-- ========== SINGLE FEATURE SECTION ========== -->
<section class="se-section single-feature">

    <div class="col-md-6 zero-padding col-md-push-6 side-img">
        <img src="http://placehold.it/1600x1000?text=SoftEase" alt="" class="img-responsive">
    </div> <!-- end side-img -->

    <div class="container feature-desc">
        <div class="row">
            <div class="col-md-5 feature-info">
                <h2>This is amazing dashboard</h2>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud officia deserunt mollit exercitation.</p>
                <p>Ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui anim id est laborum.</p>
                <a href="#" class="btn se-btn btn-rounded">Learn More</a>
            </div>

        </div> <!-- end row -->
    </div> <!-- end container -->

</section>

<!-- ========== SINGLE FEATURE SECTION ========== -->
<section class="se-section single-feature">

    <div class="col-md-6 zero-padding side-img">
        <img src="http://placehold.it/1600x1000?text=SoftEase" alt="" class="img-responsive">
    </div> <!-- end side-img -->

    <div class="container feature-desc">
        <div class="row">
            <div class="col-md-5 col-md-push-7 feature-info">
                <h2>This is amazing dashboard</h2>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud officia deserunt mollit exercitation.</p>
                <p>Ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui anim id est laborum.</p>
                <a href="#" class="btn se-btn btn-rounded">Learn More</a>
            </div>
        </div> <!-- end row -->
    </div> <!-- end container -->
</section>

<!-- ========== STEPS ========== -->
<section class="se-section se-steps">
    <div class="container">
        <div class="row text-center">
            <h3 class="underline mtn">It's as ease as 1 - 2 - 3!</h3>
        </div> <!-- end row -->

        <div class="row">
            <div class="col-md-4 col-sm-4 one-step">
                <h4>Sign Up</h4>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
            </div>

            <div class="col-md-4 col-sm-4 one-step">
                <h4>Add Users</h4>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
            </div>

            <div class="col-md-4 col-sm-4 one-step">
                <h4>Assign Tasks</h4>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
            </div>
        </div> <!-- end row -->
    </div> <!-- end container -->
</section>

<!-- ========== FEATURES ========== -->
<section class="se-section features-section parallax-bg" data-parallax="scroll" data-image-src="/static/images/bg-img-3.jpg" data-speed="0.4">
    <div class="black-gradient">
        <div class="container">
            <div class="row">
                <div class="col-md-6 col-sm-6 se-feature-style-2 mb60">
                    <div class="left">
                        <i class="icon ion-arrow-expand"></i>
                    </div>
                    <div class="right">
                        <h5>Fully Responsive</h5>
                        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut.</p>
                    </div>
                </div> <!-- end se-feature -->

                <div class="col-md-6 col-sm-6 se-feature-style-2 mb60">
                    <div class="left">
                        <i class="icon ion-android-search"></i>
                    </div>
                    <div class="right">
                        <h5>Retina Ready</h5>
                        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut.</p>
                    </div>
                </div> <!-- end se-feature -->

                <div class="col-md-6 col-sm-6 se-feature-style-2 mb60">
                    <div class="left">
                        <i class="icon ion-ios-bolt"></i>
                    </div>
                    <div class="right">
                        <h5>Lightning Fast</h5>
                        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut.</p>
                    </div>
                </div> <!-- end se-feature -->

                <div class="col-md-6 col-sm-6 se-feature-style-2 mb60">
                    <div class="left">
                        <i class="icon ion-information"></i>
                    </div>
                    <div class="right">
                        <h5>Google Fonts</h5>
                        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut.</p>
                    </div>
                </div> <!-- end se-feature -->

                <div class="col-md-6 col-sm-6 se-feature-style-2">
                    <div class="left">
                        <i class="icon ion-checkmark"></i>
                    </div>
                    <div class="right">
                        <h5>Light Weight</h5>
                        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut.</p>
                    </div>
                </div> <!-- end se-feature -->

                <div class="col-md-6 col-sm-6 se-feature-style-2">
                    <div class="left">
                        <i class="icon ion-settings"></i>
                    </div>
                    <div class="right">
                        <h5>Easy To Edit</h5>
                        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut.</p>
                    </div>
                </div> <!-- end se-feature -->

            </div> <!-- end row -->
        </div> <!-- end container -->
    </div> <!-- end black-gradient -->
</section> <!-- end features-section -->

<!-- ========== CTA SECTION ========== -->
<section class="se-section primary-bg">
    <div class="container">
        <div class="row text-center">
            <h3>Create Your Account Now!</h3>
            <p>Get 30 days trial. No credit card required.</p>
            <a href="#" class="btn se-btn-black btn-rounded">SIGN UP</a>
        </div> <!-- end row -->
    </div> <!-- end container -->
</section>

<!-- ========== FOOTER ========== -->
<footer class="light-footer">
    <div class="container">
        <div class="row">
            <div class="col-md-2 col-sm-3 col-xs-6">
                <img src="/static/images/dark-logo.svg" alt="" class="footer-logo">
            </div>

            <div class="col-md-2 col-sm-3 col-xs-6">
                <h6 class="mtn">HOME</h6>
                <ul>
                    <li><a href="#">Parallax Background</a></li>
                    <li><a href="#">Animated Background</a></li>
                    <li><a href="#">Solid Color</a></li>
                    <li><a href="#">Gradient Background</a></li>
                </ul>
            </div>

            <div class="col-md-2 col-sm-3 col-xs-6">
                <h6 class="mtn">PAGES</h6>
                <ul>
                    <li><a href="#">About Us</a></li>
                    <li><a href="#">Our Team</a></li>
                    <li><a href="#">Pricing</a></li>
                    <li><a href="#">Features</a></li>
                </ul>
            </div>

            <div class="col-md-2 col-sm-3 col-xs-6">
                <h6 class="mtn">OTHER</h6>
                <ul>
                    <li><a href="#">Sign Up</a></li>
                    <li><a href="#">Login</a></li>
                    <li><a href="#">Privacy Policy</a></li>
                    <li><a href="#">Terms of Service</a></li>
                </ul>
            </div>

            <div class="col-md-4 col-sm-8 col-sm-offset-2 col-md-offset-0">
                <h6 class="mtn">SUBSCRIBE</h6>
                <div class="input-group">
                    <input type="email" class="form-control inp-rounded" placeholder="Enter your email id">
                    <span class="input-group-btn">
                                <button class="btn se-btn btn-rounded" type="button">Subscribe!</button>
                            </span> <!-- end input-group-btn -->
                </div><!-- end input-group -->
                <p class="text-center text-muted">We don't spam!</p>
            </div>
        </div> <!-- end row -->

        <div class="row footer-bottom">
            <div class="col-md-6">
                <p>Copyright &copy; SoftEase Technologies. 2016. All Rights Reserved.</p>
            </div>

            <div class="col-md-6 text-right">
                <h6><a href="#">FACEBOOK</a></h6>
                <h6><a href="#">TWITTER</a></h6>
                <h6><a href="#">LINKEDIN</a></h6>
                <h6><a href="#">GOOGLE PLUS</a></h6>
            </div>
        </div> <!-- end footer-bottom -->
    </div> <!-- end container -->
</footer>


<script src="/static/js/vendor.js"></script>

<!-- ========== MINIFIED PLUGINS JS ========== -->
<script src="/static/js/plugins.js"></script>

<script src="/static/js/main.js"></script>
</body>

</html>

<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/spring/JsonpAdvice.java<|end_filename|>
package com.kanasinfo.ext.mvc.spring;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;

/**
 * 开启jsonp支持
 * Created by gefangshuai on 2015/12/16.
 */
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {

    public JsonpAdvice() {
        super("callback");
    }
}


<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/interceptor/NavigationHandlerInterceptor.java<|end_filename|>
package com.kanasinfo.ext.mvc.interceptor;

import com.kanasinfo.ext.mvc.annotation.Menu;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 自定义全局拦截器
 * Created by gefangshuai on 2015/11/3.
 */
public class NavigationHandlerInterceptor extends HandlerInterceptorAdapter {
    Logger logger = LoggerFactory.getLogger(NavigationHandlerInterceptor.class);


    private static final String NAV_MENU_ATTR = "nav_menu";
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        String menu = "index";
        Method method = ((HandlerMethod) handler).getMethod();
        Class clazz = ((HandlerMethod) handler).getBeanType();
        if (method.isAnnotationPresent(Menu.class)) {
            Menu menuAnno = method.getAnnotation(Menu.class);
            menu = menuAnno.value();
        } else if (clazz.isAnnotationPresent(Menu.class)) {
            Menu menuAnno = (Menu) clazz.getAnnotation(Menu.class);
            menu = menuAnno.value();
        }
        request.setAttribute(NAV_MENU_ATTR, menu);
        logger.debug("servlet menu: " + menu);
        super.postHandle(request, response, handler, modelAndView);
    }

}


<|start_filename|>speedy-ext-shiro/src/main/java/com/kanasinfo/ext/shiro/CustomAuthorizationAttributeSourceAdvisor.java<|end_filename|>
package com.kanasinfo.ext.shiro;

import org.apache.shiro.authz.annotation.*;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * 由于官方的 AuthorizationAttributeSourceAdvisor 存在一个bug，不支持类上的shiro注解
 * 扩展 AuthorizationAttributeSourceAdvisor，提供shiro注解对类的支持
 * Created by gefangshuai on 2015/11/16.
 */
public class CustomAuthorizationAttributeSourceAdvisor extends StaticMethodMatcherPointcutAdvisor {
    private static final Logger log = LoggerFactory.getLogger(AuthorizationAttributeSourceAdvisor.class);

    private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =
            new Class[]{
                    RequiresPermissions.class, RequiresRoles.class,
                    RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class
            };

    protected SecurityManager securityManager = null;

    /**
     * Create a new AuthorizationAttributeSourceAdvisor.
     */
    public CustomAuthorizationAttributeSourceAdvisor() {
        setAdvice(new AopAllianceAnnotationsAuthorizingMethodInterceptor());
    }

    public SecurityManager getSecurityManager() {
        return securityManager;
    }

    public void setSecurityManager(SecurityManager securityManager) {
        this.securityManager = securityManager;
    }

    /**
     * Returns <tt>true</tt> if the method has any Shiro annotations, false otherwise.
     * The annotations inspected are:
     * <ul>
     * <li>{@link RequiresAuthentication RequiresAuthentication}</li>
     * <li>{@link RequiresUser RequiresUser}</li>
     * <li>{@link RequiresGuest RequiresGuest}</li>
     * <li>{@link RequiresRoles RequiresRoles}</li>
     * <li>{@link RequiresPermissions RequiresPermissions}</li>
     * </ul>
     *
     * @param method      the method to check for a Shiro annotation
     * @param targetClass the class potentially declaring Shiro annotations
     * @return <tt>true</tt> if the method has a Shiro annotation, false otherwise.
     * @see org.springframework.aop.MethodMatcher#matches(Method, Class)
     */
    public boolean matches(Method method, Class targetClass) {
        Method m = method;

        if (isAuthzAnnotationPresent(m)) {
            return true;
        }

        //The 'method' parameter could be from an interface that doesn't have the annotation.
        //Check to see if the implementation has it.
        if (targetClass != null) {
            try {
                m = targetClass.getMethod(m.getName(), m.getParameterTypes());
                if (isAuthzAnnotationPresent(m)) {
                    return true;
                }else if(isAuthzAnnotationPresent(targetClass)){
                    return true;
                }
            } catch (NoSuchMethodException ignored) {
                //default return value is false.  If we can't find the method, then obviously
                //there is no annotation, so just use the default return value.
            }
        }

        return false;
    }

    private boolean isAuthzAnnotationPresent(Class targetClass) {
        for (Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES) {
            Annotation a = AnnotationUtils.findAnnotation(targetClass, annClass);
            if (a != null) {
                return true;
            }
        }
        return false;
    }

    private boolean isAuthzAnnotationPresent(Method method) {
        for (Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES) {
            Annotation a = AnnotationUtils.findAnnotation(method, annClass);
            if (a != null) {
                return true;
            }
        }
        return false;
    }
}


<|start_filename|>speedy-ext-websocket/src/main/java/com/kanasinfo/web/controller/GreetingController.java<|end_filename|>
package com.kanasinfo.web.controller;

import com.kanasinfo.model.Greeting;
import com.kanasinfo.model.HelloMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Controller;

import java.security.Principal;

/**
 * Created by gefangshuai on 2017/5/29.
 */
@Controller
@MessageMapping("/hello")
public class GreetingController {
    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;

    @MessageMapping
    @SendTo(value = "/topic/greetings")
    public Greeting greeting(HelloMessage message, Principal principal) throws Exception {
        return new Greeting(String.format("%s say: %s.", message.getName(), message.getMessage()));
    }

    @MessageMapping("/user")
    @SendToUser(value = "/topic/greetings", broadcast = false)
    public Greeting greetingUser(HelloMessage message, Principal principal) throws Exception {
        return new Greeting(String.format("%s say: %s.", message.getName(), message.getMessage()));
    }

    @MessageMapping("/user/{baz}")
    public void processMessageFromClient(HelloMessage message, @DestinationVariable String baz) throws Exception {
        simpMessagingTemplate.convertAndSend("/topic/reply/" + baz, new Greeting(String.format("%s say: %s.", message.getName(), message.getMessage())));
    }
}


<|start_filename|>speedy-ext-shiro/src/main/java/com/kanasinfo/ext/shiro/utils/HashUtils.java<|end_filename|>
package com.kanasinfo.ext.shiro.utils;

import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;

/**
 * 安全有关
 * Created by gefangshuai on 2015/11/9.
 */
public class HashUtils {

    /**
     * 获取一个随机的盐值
     *
     * @return
     */
    public static String generateSalt() {
        return new SecureRandomNumberGenerator().nextBytes().toHex();
    }

    /**
     * 获取加密后的hash值
     * @param password
     * @param salt
     * @return
     */
    public static String toMd5(String password, String salt) {
        SimpleHash hash = new SimpleHash("md5", password, salt, 2);
        return hash.toHex();
    }
}


<|start_filename|>speedy-ext-shiro/src/main/java/com/kanasinfo/ext/shiro/ShiroExtConfiguration.java<|end_filename|>
package com.kanasinfo.ext.shiro;

import com.kanasinfo.ext.shiro.bean.ShiroExtConfig;
import com.kanasinfo.ext.shiro.filter.ShiroExtFormAuthenticationFilter;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by gefangshuai on 2015/11/4.
 */
@Configuration
public abstract class ShiroExtConfiguration {

    protected abstract ShiroExtConfig shiroExtConfig();

    @Bean(name = "ShiroRealmImpl")
    public ShiroExtRealm getShiroRealm() {
        ShiroExtRealm serverRealm = shiroExtConfig().getShiroExtRealm();

        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("md5");
        credentialsMatcher.setHashIterations(2);
        credentialsMatcher.setStoredCredentialsHexEncoded(true);

        serverRealm.setCredentialsMatcher(credentialsMatcher);
        return serverRealm;
    }


    @Bean(name = "shiroEhcacheManager")
    public EhCacheManager getEhCacheManager() {
        EhCacheManager em = new EhCacheManager();
        em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
        return em;
    }

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }


    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(getShiroRealm());
        securityManager.setCacheManager(getEhCacheManager());
        return securityManager;
    }

    @Bean
    public CustomAuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
        CustomAuthorizationAttributeSourceAdvisor sourceAdvisor = new CustomAuthorizationAttributeSourceAdvisor();
        sourceAdvisor.setSecurityManager(getDefaultWebSecurityManager());
        return new CustomAuthorizationAttributeSourceAdvisor();
    }

    /**
     * 设置自定义的formFilter
     *
     * @return
     */
    public ShiroExtFormAuthenticationFilter getCustomFormAuthenticationFilter() {
        ShiroExtFormAuthenticationFilter authenticationFilter = shiroExtConfig().getShiroServerFormAuthenticationFilter();
        return authenticationFilter;
    }

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();

        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("authc", getCustomFormAuthenticationFilter());

        filterFactoryBean.setSecurityManager(getDefaultWebSecurityManager());
        filterFactoryBean.setLoginUrl(shiroExtConfig().getLoginUrl());
        filterFactoryBean.setSuccessUrl(shiroExtConfig().getSuccessUrl());
        filterFactoryBean.setUnauthorizedUrl(shiroExtConfig().getUnauthorizedUrl());
        filterFactoryBean.setFilters(filterMap);
        filterFactoryBean.setFilterChainDefinitionMap(shiroExtConfig().getFilterChainDefinitionMap());

        return filterFactoryBean;
    }
}


<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/common/MultiReadHttpServletRequest.java<|end_filename|>
package com.kanasinfo.ext.mvc.common;

import com.google.common.primitives.Bytes;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

/**
 * 缓冲HttpServletRequest中的RequestBody
 * Created by gefangshuai on 2016/9/12.
 */
public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {

    private byte[] requestBody = new byte[0];
    private boolean bufferFilled = false;

    /**
     - Constructs a request object wrapping the given request.
     *
     - @param request The request to wrap
     - @throws IllegalArgumentException if the request is null
     */
    public MultiReadHttpServletRequest(HttpServletRequest request) {
        super(request);
    }

    public byte[] getRequestBody() throws IOException {
        if (bufferFilled) {
            return Arrays.copyOf(requestBody, requestBody.length);
        }

        InputStream inputStream = super.getInputStream();

        byte[] buffer = new byte[102400]; // 100kb buffer

        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            requestBody = Bytes.concat(this.requestBody, Arrays.copyOfRange(buffer, 0, bytesRead));
        }

        bufferFilled = true;
        return requestBody;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new CustomServletInputStream(getRequestBody());
    }

    private static class CustomServletInputStream extends ServletInputStream {

        private ByteArrayInputStream buffer;

        public CustomServletInputStream(byte[] contents) {
            this.buffer = new ByteArrayInputStream(contents);
        }

        @Override
        public int read() throws IOException {
            return buffer.read();
        }

        @Override
        public boolean isFinished() {
            return buffer.available() == 0;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) {
            throw new RuntimeException("Not implemented");
        }
    }
}


<|start_filename|>speedy-sample/src/main/java/com/kanasinfo/demo/dao/UserRepository.java<|end_filename|>
package com.kanasinfo.demo.dao;

import com.kanasinfo.demo.model.User;
import com.kanasinfo.ext.persistence.SupportRepository;

/**
 * Created by gefangshuai on 2016/1/6.
 */
public interface UserRepository extends SupportRepository<User, String> {
    User findByUsername(String username);
}


<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/common/BusinessException.java<|end_filename|>
package com.kanasinfo.ext.mvc.common;

public class BusinessException extends Exception {

    public static final BusinessException DATA_NOT_FOUND = new BusinessException("data_not_found");
    public static final BusinessException DATA_DUPLICATION = new BusinessException("data_duplication");

    private static final long serialVersionUID = 1L;
    private String code;
    private String message;

    public BusinessException newMessage(String msg) {
        BusinessException be = new BusinessException(this.getCode());
        be.setMessage(message);
        return be;
    }

    public BusinessException() {

    }

    public BusinessException(String code, String msg) {
        this.message = msg;
        this.code = code;
    }

    public BusinessException(String code) {
        super();
        this.code = code;
        this.message = code;
    }

    public String getCode() {
        return this.code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}


<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/common/ResponseMessage.java<|end_filename|>
package com.kanasinfo.ext.mvc.common;

import org.apache.log4j.Logger;

import java.io.Serializable;


public class ResponseMessage<T> implements Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public static final String SUCCESS = "success";
    public static final String ERROR = "error";
    public static final String WARNING = "warning";

    public static final <T> ResponseMessage<T> handleException(BusinessHandler<T> bh, Logger logger) {
        ResponseMessage<T> rm = new ResponseMessage<T>();
        try {
            rm.setMessage(bh.handle());
            rm.setStatus(ResponseMessage.SUCCESS);
        } catch (BusinessException be) {
            rm.setExceptionCode(be.getCode());
            rm.setExceptionMessage(be.getMessage());
            rm.setStatus(ResponseMessage.WARNING);
            if (logger != null && logger.isDebugEnabled()) logger.debug(be.getMessage());
        } catch (Exception e) {
            rm.setExceptionCode(e.getClass().getCanonicalName());
            rm.setExceptionMessage(e.getMessage());
            rm.setStatus(ResponseMessage.ERROR);
            logger.info(e);
        }
        return rm;
    }

    private String status;

    private String exceptionCode;

    private String exceptionMessage;

    private T message;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }

    public String getExceptionCode() {
        return exceptionCode;
    }

    public void setExceptionCode(String exceptionCode) {
        this.exceptionCode = exceptionCode;
    }

    public String getExceptionMessage() {
        return exceptionMessage;
    }

    public void setExceptionMessage(String exceptionMessage) {
        this.exceptionMessage = exceptionMessage;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer("{");
        sb.append("status:\"")
                .append(status == null ? "" : status.replaceAll("\\\"", "\\\\\\\"").replaceAll("\n", "\\\\n").replaceAll("\r", "\\\\r"))
                .append("\",message:\"")
                .append(message == null ? "" : message.toString().replaceAll("\\\"", "\\\\\\\"").replaceAll("\n", "\\\\n").replaceAll("\r", "\\\\r"))
                .append("\"}");
        return sb.toString();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((exceptionCode == null) ? 0 : exceptionCode.hashCode());
        result = prime * result + ((message == null) ? 0 : message.hashCode());
        result = prime * result + ((status == null) ? 0 : status.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ResponseMessage<?> other = (ResponseMessage<?>) obj;
        if (exceptionCode == null) {
            if (other.exceptionCode != null)
                return false;
        } else if (!exceptionCode.equals(other.exceptionCode))
            return false;
        if (message == null) {
            if (other.message != null)
                return false;
        } else if (!message.equals(other.message))
            return false;
        if (status == null) {
            if (other.status != null)
                return false;
        } else if (!status.equals(other.status))
            return false;
        return true;
    }
}


<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/utils/CommonJsonView.java<|end_filename|>
package com.kanasinfo.ext.mvc.utils;

/**
 * Created by gefangshuai on 2015/12/16.
 */
public class CommonJsonView {
    public interface CoreJsonView{}
}


<|start_filename|>speedy-portal/src/main/webapp/static/Source-Files/main.css<|end_filename|>
/**
 * ----------------------------------------------------------------------------------------
 * main.scss
 *
 * Main css file for this template.
 * ----------------------------------------------------------------------------------------
 */
/**
 * ----------------------------------------------------------------------------------------
 *  [TABLE OF CONTENTS]
 *
 * 1. VARIABLES & MIXINS
 * 2. COMMON - Margin, Padding etc
 * 3. BUTTONS, INPUTS, LINKS, BADGES
 * 4. NAVIGATION
 * 5. HEADER
 * 6. SECTIONS
 * 7. FEATURES
 * 8. STEPS
 * 9. FOOTER
 * 10. PAGE TITLE
 * 11. FORMS
 * 12. FAQs
 * 13. CONTACT & MAP
 * 14. COUNTER
 * 15. PRICING
 * 16. Blog
 * ----------------------------------------------------------------------------------------
 */
/**
 * ----------------------------------------------------------------------------------------
 * 1. VARIABLES & MIXINS
 * ----------------------------------------------------------------------------------------
 */
@import url(https://fonts.googleapis.com/css?family=Poppins:400,600);
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,300);
html, body {
  font-family: "Open Sans", sans-serif;
  font-weight: 400;
  color: #2b2c2d;
  font-size: 12px;
  line-height: 1.75em;
}

@media (min-width: 600px) {
  html, body {
    font-size: calc( 12px + (15 - 12) * ((100vw - 600px) / (1140 - 600)));
  }
}

@media (min-width: 1140px) {
  html, body {
    font-size: 15px;
  }
}

h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
  margin: 0;
  padding: 0;
}

p, blockquote, pre,
address,
dl, ol, ul,
table {
  margin-bottom: 1.75em;
}

h1, h2, h3, h4, h5, h6 {
  font-family: "Poppins", sans-serif;
  font-weight: 600;
  color: #2b2c2d;
  clear: both;
}

h1 {
  font-size: 27.85439px;
  margin-top: 0.9424em;
  line-height: 1.13088em;
  margin-bottom: 0.18848em;
}

@media (min-width: 600px) {
  h1 {
    font-size: calc( 27.85439px + (34.81799 - 27.85439) * ((100vw - 600px) / (1140 - 600)));
  }
}

@media (min-width: 1140px) {
  h1 {
    font-size: 34.81799px;
    margin-top: 0.9424em;
    line-height: 1.13088em;
    margin-bottom: 0.18848em;
  }
}

h2 {
  font-size: 23.537px;
  margin-top: 1.11527em;
  line-height: 1.33832em;
  margin-bottom: 0.25148em;
}

@media (min-width: 600px) {
  h2 {
    font-size: calc( 23.537px + (29.42125 - 23.537) * ((100vw - 600px) / (1140 - 600)));
  }
}

@media (min-width: 1140px) {
  h2 {
    font-size: 29.42125px;
    margin-top: 1.11527em;
    line-height: 1.33832em;
    margin-bottom: 0.2458em;
  }
}

h3 {
  font-size: 19.8888px;
  margin-top: 1.31984em;
  line-height: 1.58381em;
  margin-bottom: 0.30378em;
}

@media (min-width: 600px) {
  h3 {
    font-size: calc( 19.8888px + (24.86101 - 19.8888) * ((100vw - 600px) / (1140 - 600)));
  }
}

@media (min-width: 1140px) {
  h3 {
    font-size: 24.86101px;
    margin-top: 1.31984em;
    line-height: 1.58381em;
    margin-bottom: 0.29582em;
  }
}

h4 {
  font-size: 16.80607px;
  margin-top: 1.56194em;
  line-height: 1.87432em;
  margin-bottom: 0.36815em;
}

@media (min-width: 600px) {
  h4 {
    font-size: calc( 16.80607px + (21.00759 - 16.80607) * ((100vw - 600px) / (1140 - 600)));
  }
}

@media (min-width: 1140px) {
  h4 {
    font-size: 21.00759px;
    margin-top: 1.56194em;
    line-height: 1.87432em;
    margin-bottom: 0.357em;
  }
}

h5 {
  font-size: 14.20116px;
  margin-top: 1.84844em;
  line-height: 2.21813em;
  margin-bottom: 0.36969em;
}

@media (min-width: 600px) {
  h5 {
    font-size: calc( 14.20116px + (17.75145 - 14.20116) * ((100vw - 600px) / (1140 - 600)));
  }
}

@media (min-width: 1140px) {
  h5 {
    font-size: 17.75145px;
    margin-top: 1.84844em;
    line-height: 2.21813em;
    margin-bottom: 0.36969em;
  }
}

h6 {
  font-size: 12px;
  margin-top: 2.1875em;
  line-height: 2.625em;
  margin-bottom: 0.51042em;
}

@media (min-width: 600px) {
  h6 {
    font-size: calc( 12px + (15 - 12) * ((100vw - 600px) / (1140 - 600)));
  }
}

@media (min-width: 1140px) {
  h6 {
    font-size: 15px;
    margin-top: 2.1875em;
    line-height: 2.625em;
    margin-bottom: 0.47396em;
  }
}

blockquote {
  font-style: italic;
}

blockquote cite {
  display: block;
  font-style: normal;
}

pre {
  padding: 0.875em;
  margin-bottom: 1.75em;
}

pre code {
  padding: 0;
}

code {
  font-family: "Courier New", "Courier", "Lucida Sans Typewriter", "Lucida Typewriter", "monospace";
  padding: 0.0875em 0.2625em;
  line-height: 0;
}

big, small, sub, sup {
  line-height: 0;
}

abbr, acronym {
  border-bottom: 1px dotted currentColor;
  cursor: help;
}

address {
  font-style: normal;
}

dt {
  color: #2b2c2d;
  font-weight: bold;
}

ul {
  padding-left: 1.1em;
}

ol {
  padding-left: 1.4em;
}

fieldset {
  padding: 0.875em 1.75em 1.75em;
  border-width: 1px;
  border-style: solid;
  max-width: 100%;
  margin-bottom: 1.86667em;
}

@media (min-width: 1140px) {
  fieldset {
    margin-bottom: 2.04167em;
  }
}

fieldset button, fieldset input[type="submit"] {
  margin-bottom: 0;
}

legend {
  color: #2b2c2d;
  font-weight: bold;
}

input[type="text"], input[type="email"], input[type="password"], textarea {
  display: block;
  max-width: 100%;
  padding: 0.4375em;
  font-size: 12px;
  margin-bottom: 1.28333em;
}

@media (min-width: 600px) {
  input[type="text"], input[type="email"], input[type="password"], textarea {
    font-size: calc( 12px + (15 - 12) * ((100vw - 600px) / (1140 - 600)));
  }
}

@media (min-width: 1140px) {
  input[type="text"], input[type="email"], input[type="password"], textarea {
    font-size: 15px;
    margin-bottom: 0.53958em;
  }
}

input[type="submit"], button {
  display: block;
  cursor: pointer;
  font-size: 12px;
  padding: 0.4375em 1.75em;
  margin-bottom: 1.1375em;
}

@media (min-width: 600px) {
  input[type="submit"], button {
    font-size: calc( 12px + (15 - 12) * ((100vw - 600px) / (1140 - 600)));
  }
}

@media (min-width: 1140px) {
  input[type="submit"], button {
    font-size: 15px;
    margin-bottom: 1.3125em;
  }
}

label {
  display: block;
  padding-bottom: 0.21875em;
  margin-bottom: -0.14583em;
}

table {
  width: 100%;
  border-spacing: 0;
  border-collapse: collapse;
  margin-bottom: 2.33333em;
}

@media (min-width: 1140px) {
  table {
    margin-bottom: 2.1em;
  }
}

th {
  text-align: left;
  color: #2b2c2d;
  padding: 0.21875em 0.875em;
}

@media (min-width: 1140px) {
  th {
    padding: 0.4375em 0.875em;
  }
}

td {
  padding: 0.875em;
  padding: 0.21875em 0.875em;
}

@media (min-width: 1140px) {
  td {
    padding: 0.4375em 0.875em;
  }
}

/**
 * ----------------------------------------------------------------------------------------
 * 2. COMMON - Margin, Padding
 * ----------------------------------------------------------------------------------------
 */
body {
  font-family: "Open Sans", sans-serif;
  -webkit-font-smoothing: antialiased;
}

::-moz-selection {
  background-color: #2b2c2d;
  color: #fff;
}

::selection {
  background-color: #2b2c2d;
  color: #fff;
}

ul {
  list-style: none;
}

a {
  text-decoration: none !important;
}

.light-text {
  color: #c2c2c2;
}

.zero-padding {
  padding: 0px !important;
}

.mbn {
  margin-bottom: 0 !important;
}

.mb10 {
  margin-bottom: 10px !important;
}

.mb20 {
  margin-bottom: 20px !important;
}

.mb30 {
  margin-bottom: 30px !important;
}

.mb40 {
  margin-bottom: 40px !important;
}

.mb50 {
  margin-bottom: 50px !important;
}

.mb60 {
  margin-bottom: 60px !important;
}

.mtn {
  margin-top: 0 !important;
}

.mt10 {
  margin-top: 10px !important;
}

.mt20 {
  margin-top: 20px !important;
}

.mt30 {
  margin-top: 30px !important;
}

.mt40 {
  margin-top: 40px !important;
}

.mt50 {
  margin-top: 50px !important;
}

.mt60 {
  margin-top: 60px !important;
}

.mln {
  margin-left: 0;
}

.ml10 {
  margin-left: 10px;
}

.ml20 {
  margin-left: 20px;
}

.ml30 {
  margin-left: 30px;
}

.ml40 {
  margin-left: 40px;
}

.ml50 {
  margin-left: 50px;
}

.ml60 {
  margin-left: 60px;
}

.mrn {
  margin-right: 0;
}

.mr10 {
  margin-right: 10px;
}

.mr20 {
  margin-right: 20px;
}

.mr30 {
  margin-right: 30px;
}

.mr40 {
  margin-right: 40px;
}

.mr50 {
  margin-right: 50px;
}

.mr60 {
  margin-right: 60px;
}

.pbn {
  padding-bottom: 0 !important;
}

.pb10 {
  padding-bottom: 10px;
}

.pb20 {
  padding-bottom: 20px;
}

.pb30 {
  padding-bottom: 30px;
}

.pb40 {
  padding-bottom: 40px;
}

.pb50 {
  padding-bottom: 50px;
}

.pb60 {
  padding-bottom: 60px;
}

.pb70 {
  padding-bottom: 70px;
}

.pb80 {
  padding-bottom: 80px;
}

.ptn {
  padding-top: 0 !important;
}

.pt10 {
  padding-top: 10px;
}

.pt20 {
  padding-top: 20px;
}

.pt30 {
  padding-top: 30px;
}

.pt40 {
  padding-top: 40px;
}

.pt50 {
  padding-top: 50px;
}

.pt60 {
  padding-top: 60px;
}

.pt70 {
  padding-top: 70px;
}

.pt80 {
  padding-top: 80px;
}

.pt90 {
  padding-top: 90px;
}

.pln {
  padding-left: 0;
}

.pl10 {
  padding-left: 10px;
}

.pl20 {
  padding-left: 20px;
}

.pl30 {
  padding-left: 30px;
}

.pl40 {
  padding-left: 40px;
}

.pl50 {
  padding-left: 50px;
}

.pl60 {
  padding-left: 60px;
}

.prn {
  padding-right: 0;
}

.pr10 {
  padding-right: 10px;
}

.pr20 {
  padding-right: 20px;
}

.pr30 {
  padding-right: 30px;
}

.pr40 {
  padding-right: 40px;
}

.pr50 {
  padding-right: 50px;
}

.pr60 {
  padding-right: 60px;
}

.white-color {
  color: #fff !important;
}

.underline {
  position: relative;
  padding-bottom: 0.667em;
  margin-bottom: 1.5em;
}

.underline:after {
  content: "";
  width: 32px;
  height: 1px;
  background: #c2c2c2;
  position: absolute;
  bottom: 0;
  left: 0;
}

.full-underline::after {
  width: 100%;
}

.longer-underline::after {
  width: 60px;
}

.text-center .underline::after {
  width: 4%;
  left: 48%;
}

.text-center .longer-underline::after {
  width: 8%;
  left: 46%;
}

.text-muted {
  font-size: 85%;
  font-style: italic;
}

.boxed {
  background: url(../images/boxed-bg.png);
}

.boxed > .container {
  background: #fff;
  box-shadow: 0 2px 10px 1px rgba(0, 0, 0, 0.2);
  padding: 0;
}

/**
 * ----------------------------------------------------------------------------------------
 * 3. BUTTONS, INPUTS, LINKS, BADGES
 * ----------------------------------------------------------------------------------------
 */
button, input[type="button"], input[type="reset"], input[type="submit"] {
  background-color: #4aa3df;
  color: #fff;
  border: 1px solid #4aa3df;
  transition: all 0.4s ease-in-out;
  outline: none !important;
  box-shadow: none !important;
}

button:focus, input[type="button"]:focus, input[type="reset"]:focus, input[type="submit"]:focus,
button:hover, input[type="button"]:hover, input[type="reset"]:hover, input[type="submit"]:hover,
button:active, input[type="button"]:active, input[type="reset"]:active, input[type="submit"]:active {
  background-color: #fff;
  color: #4aa3df;
  border: 1px solid #4aa3df;
}

.btn {
  font-family: "Poppins", sans-serif;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  height: 40px;
  line-height: 40px;
  padding: 0 30px;
  transition: all 0.4s ease-in-out;
}

.btn.se-btn {
  background: #4aa3df;
  color: #fff;
}

.btn.se-btn:hover {
  background: #fff;
  color: #4aa3df;
}

.btn.se-btn-black {
  background: #2b2c2d;
  color: #fff;
}

.btn.se-btn-black:hover {
  background: #fff;
  color: #2b2c2d;
}

.btn.se-btn-white {
  background: #fff;
  color: #4aa3df;
}

.btn.se-btn-white:hover {
  background: #4aa3df;
  color: #fff;
}

.btn.btn-rounded {
  border-radius: 30px;
}

.badge {
  padding: 4px 12px;
  background: #4aa3df;
  border-radius: 2px;
  margin: 0 5px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.learn-more {
  color: #4aa3df;
  padding: 0px 10px;
  transition: all 0.4s ease-in-out;
}

.learn-more:after {
  content: "\f054";
  font-family: 'FontAwesome';
  margin-left: 5px;
  font-size: 0.8em;
}

input[type="color"], input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"], input:not([type]), textarea {
  border: 1px solid #ececec;
  background: #fff;
  padding: 0.618em 1em;
  font-family: "Poppins", sans-serif;
  box-shadow: none;
  min-height: 40px;
  width: 100%;
}

input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="email"]:focus, input[type="month"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="time"]:focus, input[type="url"]:focus, input[type="week"]:focus, input:not([type]):focus, textarea:focus,
input[type="color"]:hover, input[type="date"]:hover, input[type="datetime"]:hover, input[type="datetime-local"]:hover, input[type="email"]:hover, input[type="month"]:hover, input[type="number"]:hover, input[type="password"]:hover, input[type="search"]:hover, input[type="tel"]:hover, input[type="text"]:hover, input[type="time"]:hover, input[type="url"]:hover, input[type="week"]:hover, input:not([type]):hover, textarea:hover {
  border: 1px solid lightgray;
  outline: 0;
  box-shadow: none;
}

input[type="color"]:active, input[type="date"]:active, input[type="datetime"]:active, input[type="datetime-local"]:active, input[type="email"]:active, input[type="month"]:active, input[type="number"]:active, input[type="password"]:active, input[type="search"]:active, input[type="tel"]:active, input[type="text"]:active, input[type="time"]:active, input[type="url"]:active, input[type="week"]:active, input:not([type]):active, textarea:active {
  border: 1px solid lightgray;
  outline: 0;
  box-shadow: none;
}

.inp-rounded {
  border-radius: 30px;
}

.animated {
  -webkit-animation-duration: 0.4s;
          animation-duration: 0.4s;
}

/**
 * ----------------------------------------------------------------------------------------
 * 4. NAVIGATION
 * ----------------------------------------------------------------------------------------
 */
@media (min-width: 992px) {
  ul.nav li.dropdown:hover > ul.dropdown-menu {
    display: block;
  }
}

.navbar-nav > li > a {
  color: #fff;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  line-height: 30px;
  transition: all 0.4s ease-in-out;
}

.navbar-fixed-top {
  border: 0px;
}

.navbar {
  transition: all 0.4s ease-in-out;
}

.navbar-brand {
  height: 60px;
}

.navbar-brand img {
  height: 30px;
}

.navbar-brand .dark-logo {
  display: none;
}

.nav > li:not(.nav-btn-wrap):hover, .nav > li:not(.nav-btn-wrap):focus {
  background: #217dbb;
}

.nav > li:not(.nav-btn-wrap):hover > a, .nav > li:not(.nav-btn-wrap):focus > a {
  color: #fff;
}

.dark-header .nav > li:not(.nav-btn-wrap):focus > a,
.dark-header .nav > li:not(.nav-btn-wrap):hover > a {
  color: #ffffff;
}

.nav > li > a:hover, .nav > li > a:focus {
  background: #217dbb;
}

.nav .open > a, .nav .open > a:focus, .nav .open > a:hover {
  background: #217dbb;
}

.yamm .yamm-content {
  padding: 0px;
}

.yamm .nav, .yamm .collapse, .yamm .dropup, .yamm .dropdown {
  position: relative;
}

.nav-btn {
  margin-top: 10px;
  display: inline-block;
}

.dropdown-menu {
  background: #217dbb;
  border: 0px;
  box-shadow: none;
  padding: 0;
  color: #fff;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.15);
}

.dropdown-menu a {
  color: #fff;
  display: block;
  padding: 3px 0;
  transition: all 0.4s ease-in-out;
}

.dropdown-menu a:hover {
  padding-left: 6px;
}

.dropdown-menu a.btn {
  padding: 0;
}

.dropdown-menu .yamm-content {
  display: table;
}

.dropdown-menu .nav-col {
  display: table-cell;
  padding: 20px;
  min-width: 200px;
}

.dropdown-menu .nav-col h1,
.dropdown-menu .nav-col h2,
.dropdown-menu .nav-col h3,
.dropdown-menu .nav-col h4,
.dropdown-menu .nav-col h5,
.dropdown-menu .nav-col h6 {
  margin-top: 0;
  margin-left: 0;
  font-weight: 400;
  color: #fff;
}

.dropdown-menu .nav-col ul {
  padding-left: 0;
}

.dropdown-menu .nav-col.dark-bg {
  background: #2b2c2d;
}

.dd-left .dropdown-menu {
  right: 0;
  left: auto;
}

.body-scrolled .dark-logo {
  display: inline-block;
}

.body-scrolled .light-logo {
  display: none;
}

.body-scrolled .navbar {
  box-shadow: 0 2px 10px 1px rgba(0, 0, 0, 0.1);
  background: #fff;
}

.body-scrolled .navbar .navbar-nav > li > a {
  color: #2b2c2d;
}

.body-scrolled .navbar .nav > li:hover > a, .body-scrolled .navbar .nav > li:focus > a {
  background: #217dbb;
  color: #fff;
}

.dark-header .navbar-nav > li > a {
  color: #787878;
}

.dark-header .nav > li > a:hover, .dark-header .nav > li > a:focus {
  color: #fff;
  /* background: $primary-color; */
}

.dark-header .dark-logo {
  display: inline-block;
}

.dark-header .light-logo {
  display: none;
}

.breadcrumb {
  background: transparent;
  padding: 15px;
  margin-bottom: 0;
}

.breadcrumb a {
  color: #787878;
  font-size: 95%;
  transition: all 0.4s ease-in-out;
}

.breadcrumb a:hover {
  color: #4aa3df;
}

.breadcrumb .icon {
  margin: 0 5px;
}

.navbar-header {
  position: relative;
  z-index: 1;
}

.navbar-toggle {
  background: #fff;
}

.navbar-toggle .icon-bar {
  background: #2b2c2d;
}

.navbar-fixed-top .navbar-collapse, .navbar-fixed-bottom .navbar-collapse {
  max-height: 500px;
}

@media (max-width: 992px) {
  .navbar-nav {
    width: 100%;
  }
  .dropdown-menu a {
    color: #787878;
  }
  .navbar-nav > li > a {
    color: #787878;
  }
  .navbar-collapse.in {
    background: #fff;
  }
  .navbar-collapse.in {
    background: #fff;
  }
  .navbar-collapse.in .nav > li:not(.nav-btn-wrap):focus, .navbar-collapse.in .nav > li:not(.nav-btn-wrap):hover {
    background: #f2f2f2;
  }
  .navbar-collapse.in .nav > li > a:focus, .navbar-collapse.in .nav > li > a:hover {
    background: #f2f2f2;
  }
  .nav > li:not(.nav-btn-wrap):hover > a, .nav > li:not(.nav-btn-wrap):focus > a {
    color: inherit;
  }
  .nav .open > a,
  .nav .open > a:focus,
  .nav .open > a:hover {
    background: #f2f2f2;
  }
  .dark-header .nav > li:not(.nav-btn-wrap):focus > a, .dark-header .nav > li:not(.nav-btn-wrap):hover > a {
    color: #222;
  }
  .dropdown-menu .nav-col h1, .dropdown-menu .nav-col h2, .dropdown-menu .nav-col h3, .dropdown-menu .nav-col h4, .dropdown-menu .nav-col h5, .dropdown-menu .nav-col h6 {
    color: #222;
  }
  .dropdown-menu .nav-col.dark-bg h1, .dropdown-menu .nav-col.dark-bg h2, .dropdown-menu .nav-col.dark-bg h3, .dropdown-menu .nav-col.dark-bg h4, .dropdown-menu .nav-col.dark-bg h5, .dropdown-menu .nav-col.dark-bg h6 {
    color: #fff;
  }
  .body-scrolled .navbar .nav > li > a:focus, .body-scrolled .navbar .nav > li:hover a {
    background: #f2f2f2;
    color: #787878;
  }
}

/**
 * ----------------------------------------------------------------------------------------
 * 5. HEADER
 * ----------------------------------------------------------------------------------------
 */
.main-header {
  height: 100vh;
}

.main-header .primary-trans-bg {
  height: 100%;
  background-color: rgba(74, 163, 223, 0.9);
  color: #fff;
}

.main-header .container {
  height: 100%;
}

.main-header h1, .main-header .h1 {
  font-size: 4.236em;
  font-family: "Poppins", sans-serif;
  font-weight: bold;
}

.main-header h5 {
  font-family: "Open Sans", sans-serif;
  font-weight: 400;
  color: #fff;
  margin-bottom: 1.618em;
  letter-spacing: 0.04em;
}

@media (max-width: 768px) {
  .main-header h1, .main-header .h1 {
    font-size: 2.618em;
  }
}

.outer {
  display: table;
  width: 100%;
  height: 100%;
}

.inner {
  display: table-cell;
  vertical-align: middle;
}

.header-style-2 {
  height: 100vh;
  position: relative;
}

.header-style-2 .primary-trans-bg {
  position: absolute;
  width: 100%;
  height: 100%;
}

.header-style-3 {
  border-bottom: 1px solid #ececec;
  height: 100vh;
  position: relative;
}

.header-style-3 .primary-trans-bg {
  position: absolute;
  width: 100%;
  height: 100%;
}

.header-style-3 h1 {
  font-size: 2.618em;
  line-height: 1.25em;
}

.img-shadow {
  box-shadow: 0px 2px 10px 1px rgba(0, 0, 0, 0.2);
}

.swiper-container {
  width: 100%;
  height: 100%;
}

.swiper-slide {
  text-align: center;
  background-color: #787878;
  background-size: cover;
  background-position: center;
}

.swiper-slide .slide-text {
  position: absolute;
  z-index: 1;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.6);
}

.swiper-button-next, .swiper-container-rtl .swiper-button-prev {
  background-image: none;
}

.swiper-button-next:after, .swiper-container-rtl .swiper-button-prev:after {
  content: "\f3d1";
  position: absolute;
  font-family: "Ionicons";
  display: inline-block;
  -webkit-font-smoothing: antialiased;
  top: 50%;
  right: 0;
  color: #4aa3df;
  font-size: 4.236em;
}

.swiper-button-prev, .swiper-container-rtl .swiper-button-next {
  background-image: none;
}

.swiper-button-prev:after, .swiper-container-rtl .swiper-button-next:after {
  content: "\f3cf";
  position: absolute;
  font-family: "Ionicons";
  display: inline-block;
  -webkit-font-smoothing: antialiased;
  top: 50%;
  right: 0;
  color: #4aa3df;
  font-size: 4.236em;
}

.swiper-pagination-bullet-active {
  background: #4aa3df;
}

.gradient-bg {
  background: linear-gradient(to bottom, #4aa3df, #1c699d);
}

/**
 * ----------------------------------------------------------------------------------------
 * 6. SECTIONS
 * ----------------------------------------------------------------------------------------
 */
.se-section {
  padding: 90px 0px;
  border-bottom: 1px solid #ececec;
}

.gray-section {
  background: #f9f9f9;
}

.gray-section p {
  margin-bottom: 0;
  color: #787878;
}

section.parallax-bg {
  padding: 0;
  border: 0px;
}

.offer-section {
  padding: 35px;
}

.black-gradient {
  padding: 90px 0;
  background: rgba(0, 0, 0, 0.6);
  color: #fff !important;
  border: 0px;
}

.black-gradient h1, .black-gradient h2, .black-gradient h3, .black-gradient h4, .black-gradient h5, .black-gradient h6 {
  color: #fff !important;
}

.black-gradient p {
  color: #fff !important;
}

.primary-bg {
  background: #4aa3df;
  color: #f9f9f9;
}

.primary-bg h1, .primary-bg h2, .primary-bg h3, .primary-bg h4, .primary-bg h5, .primary-bg h6 {
  color: #fff;
}

.pp-section p {
  color: #787878;
}

.pp-section ul {
  color: #787878;
  padding-left: 30px;
  list-style: circle;
}

.pp-section ul li {
  margin-bottom: 10px;
}

/**
 * ----------------------------------------------------------------------------------------
 * 7. FEATURES
 * ----------------------------------------------------------------------------------------
 */
.se-feature {
  text-align: center;
}

.se-feature .icon {
  font-size: 2.618em;
  color: #4aa3df;
}

.se-feature h5 {
  margin-top: 1em;
}

.se-feature p {
  color: #787878;
  margin-bottom: 0;
}

@media (max-width: 991px) {
  .se-feature {
    margin-bottom: 50px;
  }
  .se-feature:last-child {
    margin-bottom: 0;
  }
}

.se-feature-style-2 .left {
  float: left;
  width: 12%;
}

.se-feature-style-2 .right {
  float: left;
  width: 88%;
}

.se-feature-style-2 .icon {
  font-size: 2.618em;
}

.se-feature-style-2 h5 {
  margin-top: 0;
}

.se-feature-style-2 p {
  color: #787878;
  margin-bottom: 0;
}

@media (max-width: 768px) {
  .se-feature-style-2 p {
    margin-bottom: 30px;
  }
}

.se-feature-style-3 {
  text-align: center;
}

.se-feature-style-3 h5 {
  margin-top: 1em;
  transition: all 0.4s ease-in-out;
}

.se-feature-style-3 p {
  color: #787878;
  margin-bottom: 1em;
  transition: all 0.4s ease-in-out;
}

.se-feature-style-3 .feature-wrap {
  background: #f9f9f9;
  padding: 1.618em;
  border-radius: 6px;
  position: relative;
  margin-bottom: 40px;
  transition: all 0.4s ease-in-out;
}

.se-feature-style-3 .feature-wrap .icon {
  font-size: 2.618em;
  color: #4aa3df;
  transition: all 0.4s ease-in-out;
}

.se-feature-style-3:hover .feature-wrap {
  background: #4aa3df;
  color: #fff;
}

.se-feature-style-3:hover .feature-wrap .icon {
  color: #fff;
}

.se-feature-style-3:hover p {
  color: #f9f9f9;
}

.se-feature-style-3:hover h5 {
  color: #fff;
}

.se-feature-style-3:hover .learn-more {
  color: #fff;
}

.single-feature .side-img img {
  box-shadow: 0px 2px 10px 1px rgba(0, 0, 0, 0.2);
}

.single-feature .feature-desc h2 {
  margin-bottom: 1em;
  width: 60%;
}

.single-feature .feature-desc p {
  color: #787878;
}

@media (min-width: 991px) {
  .single-feature .feature-desc .row {
    position: relative;
  }
  .single-feature .feature-desc .feature-info {
    position: absolute;
  }
}

ul.highlights {
  padding-left: 0;
}

ul.highlights li {
  margin-bottom: 0.618em;
}

ul.highlights .icon {
  margin-right: 10px;
  font-size: 80%;
}

/**
 * ----------------------------------------------------------------------------------------
 * 8. STEPS
 * ----------------------------------------------------------------------------------------
 */
.se-steps {
  counter-reset: se-counter;
}

.se-steps h4 {
  position: relative;
  z-index: 0;
}

.se-steps h4:before {
  content: counter(se-counter);
  counter-increment: se-counter;
  position: absolute;
  color: #f4f4f4;
  font-size: 4.236em;
  font-style: italic;
  z-index: -1;
}

/**
 * ----------------------------------------------------------------------------------------
 * 9. FOOTER
 * ----------------------------------------------------------------------------------------
 */
footer {
  padding: 90px 0px 50px;
  background: #f9f9f9;
}

footer .footer-logo {
  width: 80%;
}

footer h6 {
  letter-spacing: 0.1em;
  font-size: 0.9em;
}

footer ul {
  padding-left: 0px;
}

footer a {
  color: #787878;
  font-size: 90%;
}

footer .footer-bottom {
  border-top: 1px dashed #ececec;
  padding: 20px 0;
}

footer .footer-bottom p {
  font-size: 90%;
  color: #787878;
  margin-bottom: 0;
}

footer .footer-bottom h6 {
  display: inline-block;
  padding: 0 10px;
  margin: 0;
  color: #787878;
}

@media (max-width: 991px) {
  footer .col-md-6 {
    text-align: center !important;
  }
}

/**
 * ----------------------------------------------------------------------------------------
 * 10. PAGE TITLE
 * ----------------------------------------------------------------------------------------
 */
.page-title {
  height: 50vh;
  background: url(../images/page-title-bg.png);
  position: relative;
}

.page-title .container {
  height: 100%;
}

.page-title h5 {
  font-family: "Open Sans", sans-serif;
  color: #787878;
  font-weight: 400;
}

/**
 * ----------------------------------------------------------------------------------------
 * 11. FORMS
 * ----------------------------------------------------------------------------------------
 */
.form-wrap {
  background: #f9f9f9;
  padding: 2.618em;
  box-shadow: 0px 2px 10px 1px rgba(0, 0, 0, 0.2);
  color: #787878;
}

.form-wrap .logo-wrap {
  margin-bottom: 1.618em;
}

.form-wrap .social-login {
  border-top: 1px dashed #787878;
  padding-top: 1em;
}

.form-wrap .social-login p {
  color: #787878;
  font-size: 90%;
}

.form-wrap .social-login .btn {
  font-size: 80%;
  padding: 0 22px;
  margin: 0 5px;
}

.form-wrap .social-login .fb-btn {
  background: #3b5998;
}

.form-wrap .social-login .tw-btn {
  background: #00acee;
}

.form-wrap .social-login .gp-btn {
  background: #dd4b39;
}

/**
 * ----------------------------------------------------------------------------------------
 * 12. FAQs
 * ----------------------------------------------------------------------------------------
 */
.panel-title {
  font-size: 1em;
}

.panel-title a .icon {
  float: right;
  display: inline-block;
  line-height: inherit;
  -webkit-transform: rotate(135deg);
      -ms-transform: rotate(135deg);
          transform: rotate(135deg);
  transition: all 0.4s ease-in-out;
}

.panel-title .collapsed .icon {
  -webkit-transform: rotate(0deg);
      -ms-transform: rotate(0deg);
          transform: rotate(0deg);
}

.acc-faq-2 .panel-title a {
  display: block;
}

/**
 * ----------------------------------------------------------------------------------------
 * 13. CONTACT & MAP
 * ----------------------------------------------------------------------------------------
 */
#fullWidthMap {
  height: 400px;
}

.contact-info p {
  color: #787878;
}

/**
 * ----------------------------------------------------------------------------------------
 * 14. COUNTER
 * ----------------------------------------------------------------------------------------
 */
.counter-box .count-icon {
  float: left;
  font-size: 4.236em;
  color: #787878;
  margin-right: 10px;
}

.counter-box .count-info {
  float: left;
  text-align: center;
}

.counter-box .count-info h4 {
  margin-top: 0;
  margin-bottom: 0;
}

/**
 * ----------------------------------------------------------------------------------------
 * 15. PRICING
 * ----------------------------------------------------------------------------------------
 */
.se-plan {
  border: 1px solid #ececec;
  margin-bottom: 1em;
}

.se-plan .plan-header {
  background: #2b2c2d;
  color: #fff;
  text-align: center;
  padding: 2.618em 1em;
}

.se-plan .plan-header h2 {
  color: #fff;
  margin-top: 0;
}

.se-plan .plan-header p {
  margin-bottom: 0;
}

.se-plan .plan-header small {
  font-size: 60%;
  color: #fff;
}

.se-plan .plan-features ul {
  margin-top: 10px;
  padding-left: 0;
  margin-bottom: 10px;
}

.se-plan .plan-features li {
  line-height: 4.618em;
  padding-left: 20px;
  border-bottom: 1px dotted #ececec;
}

.se-plan .plan-features li:last-child {
  border-bottom: 0;
}

.se-plan .plan-features li .icon {
  float: right;
  margin-right: 20px;
  font-size: 1.618em;
}

.se-plan.plan-popular .plan-header {
  background: #4aa3df;
  position: relative;
}

.se-plan.plan-popular .plan-header:before {
  content: 'Popular';
  position: absolute;
  top: -30px;
  background: #1d6fa6;
  line-height: 30px;
  width: 100%;
  left: 0;
  font-family: "Poppins", sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.strike {
  text-decoration: line-through;
}

/**
 * ----------------------------------------------------------------------------------------
 * 16. BLOG
 * ----------------------------------------------------------------------------------------
 */
.entry {
  margin-bottom: 80px;
}

.entry-image img {
  margin: auto;
}

.entry-title a {
  color: inherit !important;
  transition: all 0.4s ease-in-out;
}

.entry-title a:hover {
  color: #4aa3df !important;
}

/*# sourceMappingURL=main.css.map */

<|start_filename|>speedy-ext-websocket/src/main/java/com/kanasinfo/web/MyHandler.java<|end_filename|>
package com.kanasinfo.web;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;

import java.util.ArrayList;
import java.util.List;

public class MyHandler implements WebSocketHandler {
    private Logger logger = LoggerFactory.getLogger(MyHandler.class);
    private static final List<WebSocketSession> clients = new ArrayList<>();
    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
        logger.info(String.format("客户端[%s]建立连接.", webSocketSession.getId()));
        clients.add(webSocketSession);
    }

    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {

    }

    @Override
    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
        if(webSocketSession.isOpen()){
            webSocketSession.close();
        }
        logger.error("连接出现错误:"+ throwable.toString());
        clients.remove(webSocketSession);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
        logger.debug(String.format("客户端[%s]断开连接.", webSocketSession.getId()));
        clients.remove(webSocketSession);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }
}

<|start_filename|>speedy-ext-shiro/src/main/java/com/kanasinfo/ext/shiro/ShiroExtRealm.java<|end_filename|>
package com.kanasinfo.ext.shiro;

import com.kanasinfo.ext.shiro.bean.UserModel;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.stereotype.Component;

import java.util.Set;

/**
 * 自定义Realm
 * Created by gefangshuai on 2015/11/4.
 */
@Component
public abstract class ShiroExtRealm extends AuthorizingRealm {
    /**
     * 获取登录用户信息
     */
    protected abstract UserModel getUserByUsername(String username);

    /**
     * 获取登录用户的角色信息
     */
    protected abstract Set<String> getRolesByUsername(String username);

    /**
     * 获取登录用户的权限信息
     */
    protected abstract Set<String> getPermissionsByUsername(String username);
    /**
     * 授权验证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken credentials = (UsernamePasswordToken) token;
        String username = credentials.getUsername();
        if (username == null) {
            throw new UnknownAccountException("username not provided!");
        }
        UserModel user = getUserByUsername(username);
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, user.getPassword(), getName());
        authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
        return authenticationInfo;
    }


    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(getRolesByUsername(username));
        authorizationInfo.setStringPermissions(getPermissionsByUsername(username));
        return authorizationInfo;
    }
}


<|start_filename|>speedy-ext-mail/src/main/java/com/kanasinfo/ext/mail/MailSendContent.java<|end_filename|>
package com.kanasinfo.ext.mail;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;

/**
 * Created by gefangshuai on 2017/5/23.
 */
@Component
public class MailSendContent {
    @Autowired
    private JavaMailSender javaMailSender;
    @Autowired
    private Configuration freemarkerConfig;

    /**
     * @param from     发件人
     * @param to       收件人
     * @param subject  主题
     * @param template 模板
     * @param model    数据
     * @param cc       抄送
     * @param bcc      密送
     * @throws MessagingException
     * @throws IOException
     * @throws TemplateException
     */
    public void sendMail(String from, String personal, String[] to, String subject, String template, Object model, String[] cc, String[] bcc) throws MessagingException, IOException, TemplateException {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        helper.setFrom(from, personal);
        helper.setTo(to);
        if (cc != null && cc.length > 0)
            helper.setCc(cc);
        if (bcc != null && bcc.length > 0)
            helper.setBcc(bcc);
        helper.setSubject(subject);
        Template t = freemarkerConfig.getTemplate(template);
        String text = FreeMarkerTemplateUtils.processTemplateIntoString(t, model);

        helper.setText(text, true);
        javaMailSender.send(mimeMessage);
    }
}


<|start_filename|>speedy-ext-shiro/src/main/java/com/kanasinfo/ext/shiro/bean/ShiroUser.java<|end_filename|>
package com.kanasinfo.ext.shiro.bean;

/**
 * 封装登录用户Shiro信息
 * Created by gefangshuai on 2015/11/5.
 */
public class ShiroUser {
    public static final String SHIRO_USER_SESSION_KEY = "shiro_ext_user_session_key";

    private Object user;
    private String principal;
    private String[] roles;
    private String[] permissions;

    public ShiroUser(String principal) {
        this.principal = principal;
    }

    public ShiroUser(boolean isLogin, String principal, Object user) {
        this.principal = principal;
        this.user = user;
    }


    public Object getUser() {
        return user;
    }

    public void setUser(Object user) {
        this.user = user;
    }

    public String getPrincipal() {
        return principal;
    }

    public void setPrincipal(String principal) {
        this.principal = principal;
    }

    public String[] getRoles() {
        return roles;
    }

    public void setRoles(String[] roles) {
        this.roles = roles;
    }

    public String[] getPermissions() {
        return permissions;
    }

    public void setPermissions(String[] permissions) {
        this.permissions = permissions;
    }
}


<|start_filename|>speedy-sample/bower.json<|end_filename|>
{
  "name": "speedy-sample",
  "homepage": "https://github.com/gefangshuai/SpeedyFramework",
  "authors": [
    "葛方帅 <<EMAIL>>"
  ],
  "description": "",
  "main": "",
  "moduleType": [],
  "license": "MIT",
  "dependencies": {
    "bootstrap": "~3.3.6"
  }
}


<|start_filename|>speedy-ext-persistence/src/main/java/com/kanasinfo/ext/persistence/anno/Mongo.java<|end_filename|>
package com.kanasinfo.ext.persistence.anno;

/**
 * 特殊地方支持Mongodb标记
 * Created by gefangshuai on 2017/6/12.
 */
public enum Mongo {
}


<|start_filename|>speedy-sample/src/main/java/com/kanasinfo/demo/service/UserService.java<|end_filename|>
package com.kanasinfo.demo.service;

import com.kanasinfo.demo.dao.UserRepository;
import com.kanasinfo.demo.model.User;
import com.kanasinfo.ext.persistence.SupportRepository;
import com.kanasinfo.ext.persistence.SupportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * Created by gefangshuai on 2016/1/6.
 */
@Service
public class UserService extends SupportService<User, String> {

    @Autowired
    private UserRepository userRepository;

    @Resource
    public void setUserDao(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User findByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    @Override
    protected SupportRepository<User, String> getRepository() {
        return this.userRepository;
    }
}


<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/utils/RequestUtils.java<|end_filename|>
package com.kanasinfo.ext.mvc.utils;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by gefangshuai on 2017/5/24.
 */
public class RequestUtils {
    /**
     * 获取服务器域名
     */
    public static String getDomain(HttpServletRequest request){
        StringBuffer url = request.getRequestURL();
        return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(request.getServletContext().getContextPath()).toString();
    }
}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/CollUtils.java<|end_filename|>
package com.kanasinfo.utils;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * Created by Devid on 2016/11/22.
 */
public class CollUtils {

    public static boolean isEmpty(Collection<?> collection) {
        return (collection == null || collection.isEmpty());
    }

    public static boolean isEmpty(Map<?, ?> map) {
        return (map == null || map.isEmpty());
    }

    public static boolean isNotEmpty(Collection<?> collection) {
        return !isEmpty(collection);
    }

    public static boolean isNotEmpty(Map<?, ?> map) {
        return !isEmpty(map);
    }

    public static <T> List<T> create(T[] arr) {
        return Arrays.asList(arr);
    }
    
}


<|start_filename|>speedy-ext-persistence/src/main/java/com/kanasinfo/ext/persistence/ObjectIdSerializer.java<|end_filename|>
package com.kanasinfo.ext.persistence;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;

public class ObjectIdSerializer extends JsonSerializer<Object> {
    @Override
    public void serialize(Object value, JsonGenerator jsonGen, SerializerProvider provider) throws IOException {
        jsonGen.writeString(value.toString());
    }
}

<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/gson/DateDeserializer.java<|end_filename|>
package com.kanasinfo.utils.gson;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

import java.lang.reflect.Type;
import java.util.Date;

public class DateDeserializer implements JsonDeserializer<Date> {

    public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return new Date(json.getAsJsonPrimitive().getAsLong());
    }
}


<|start_filename|>speedy-sample/src/main/java/com/kanasinfo/demo/controller/PostController.java<|end_filename|>
package com.kanasinfo.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Created by gefangshuai on 2016/1/6.
 */
@Controller
@RequestMapping("/p")
public class PostController {
    @RequestMapping
    public String index(){
        return "p/index";
    }
}


<|start_filename|>speedy-utils/src/main/java/com/kanasinfo/utils/gson/GsonIgnore.java<|end_filename|>
package com.kanasinfo.utils.gson;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)  
@Retention(RetentionPolicy.RUNTIME)  
public @interface GsonIgnore {
}

<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/utils/FlashMessageUtils.java<|end_filename|>
package com.kanasinfo.ext.mvc.utils;

import org.springframework.web.servlet.mvc.support.RedirectAttributes;

/**
 * Created by gefangshuai on 2015/11/13.
 */
public class FlashMessageUtils {
    public static final String SUCCESS_ATTR = "flash_message_success";
    public static final String WARNING_ATTR = "flash_message_warning";
    public static final String ERROR_ATTR = "flash_message_error";

    public static void success(RedirectAttributes redirectAttributes, String message) {
        redirectAttributes.addFlashAttribute(SUCCESS_ATTR, message);
    }

    public static void warning(RedirectAttributes redirectAttributes, String message) {
        redirectAttributes.addFlashAttribute(WARNING_ATTR, message);
    }

    public static void error(RedirectAttributes redirectAttributes, String message) {
        redirectAttributes.addFlashAttribute(ERROR_ATTR, message);
    }
}


<|start_filename|>speedy-ext-persistence/src/main/java/com/kanasinfo/ext/persistence/SupportModel.java<|end_filename|>
package com.kanasinfo.ext.persistence;

import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;

/**
 * Created by gefangshuai on 2015/11/13.
 */
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class SupportModel implements Serializable {
    @Id
    @Column(name = "id")
    private String id;

    @CreatedDate
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created_date")
    private Date createdDate;

    @LastModifiedDate
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "last_modified_date")
    private Date lastModifiedDate;

    @CreatedBy
	@Column(name = "created_by")
    private String createdBy;

    @LastModifiedBy
	@Column(name = "last_modified_by")
	private String LastModifiedBy;

    public SupportModel() {
        this.id = UUID.randomUUID().toString().replace("-", "");
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Date getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }

    public Date getLastModifiedDate() {
        return lastModifiedDate;
    }

    public void setLastModifiedDate(Date lastModifiedDate) {
        this.lastModifiedDate = lastModifiedDate;
    }

    @Transient
    public boolean isNew() {
        return id == null;
    }

    @Transient
    public boolean isNotNew() {
        return !isNew();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SupportModel that = (SupportModel) o;
        return Objects.equals(id, that.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

	public String getCreatedBy() {
		return createdBy;
	}

	public void setCreatedBy(String createdBy) {
		this.createdBy = createdBy;
	}

	public String getLastModifiedBy() {
		return LastModifiedBy;
	}

	public void setLastModifiedBy(String lastModifiedBy) {
		LastModifiedBy = lastModifiedBy;
	}
}


<|start_filename|>speedy-ext-webmvc/src/main/java/com/kanasinfo/ext/mvc/spring/WebMVCConfigurerExtAdapter.java<|end_filename|>
package com.kanasinfo.ext.mvc.spring;

import com.kanasinfo.ext.mvc.interceptor.NavigationHandlerInterceptor;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import java.util.Locale;

/**
 * 定义了mvc适配器
 * Created by gefangshuai on 2015/11/3.
 */
//@Configuration
public class WebMVCConfigurerExtAdapter extends WebMvcConfigurerAdapter {

    /**
     * 国际化配置
     */
    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {
        LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
        lci.setParamName("lang");
        return lci;
    }

    /**
     * 防止出现：Cannot change HTTP accept header - use a different locale resolution strategy异常
     *
     * @return
     */
    @Bean(name = "localeResolver")
    public LocaleResolver localeResolver() {
        CookieLocaleResolver slr = new CookieLocaleResolver();
        //设置默认区域,
        slr.setDefaultLocale(Locale.CHINA);
        slr.setCookieMaxAge(3600 * 24 * 7);//设置cookie有效期.
        return slr;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(localeChangeInterceptor()).addPathPatterns("/**");
        NavigationHandlerInterceptor navigationHandlerInterceptor = new NavigationHandlerInterceptor();
        registry.addInterceptor(navigationHandlerInterceptor).addPathPatterns("/**");
    }

    /**
     * 配置文件上传
     *
     * @return
     */
    @Bean(name = "multipartResolver")
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setDefaultEncoding("utf-8");
        multipartResolver.setMaxUploadSize(100000000);
        return multipartResolver;
    }

    //@Bean
    public EmbeddedServletContainerCustomizer containerCustomizer() {
        return new EmbeddedServletContainerCustomizer() {
            @Override
            public void customize(ConfigurableEmbeddedServletContainer container) {
                container.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
                container.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500"));
                container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/404"));
            }
        };
    }
}
