diff --git a/.gitignore b/.gitignore index 9f0fc218e..f20eba4ee 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ /target/ /.classpath /.project +/jwp-basic.iml +/.idea/ +/tomcat.8080/ diff --git a/README.md b/README.md deleted file mode 100644 index af5cc7e49..000000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# jwp-basic -자바 웹 프로그래밍 기본 실습 diff --git a/pom.xml b/pom.xml index 00be1e5c4..4bb9ab9af 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ UTF-8 UTF-8 - 3.2.9.RELEASE + 4.2.5.RELEASE 8.0.15 @@ -24,12 +24,24 @@ + + javax.servlet + javax.servlet-api + 3.1.0 + provided + javax.servlet jstl 1.2 + + com.google.guava + guava + 18.0 + + com.h2database h2 @@ -41,9 +53,9 @@ 3.3.2 - commons-dbcp - commons-dbcp - 1.2.2 + org.apache.commons + commons-dbcp2 + 2.1.1 org.springframework @@ -56,24 +68,26 @@ ${org.springframework.version} - + + org.reflections + reflections + 0.9.10 + + ch.qos.logback logback-classic 1.1.2 + - org.freemarker - freemarker - 2.3.23 - - - javax.servlet - javax.servlet-api - 3.1.0 - provided + com.fasterxml.jackson.core + jackson-databind + 2.4.4 + + org.apache.tomcat.embed tomcat-embed-core @@ -92,24 +106,6 @@ ${tomcat.version} provided - - org.apache.tomcat - tomcat-jasper - ${tomcat.version} - provided - - - org.apache.tomcat - tomcat-jasper-el - ${tomcat.version} - provided - - - org.apache.tomcat - tomcat-jsp-api - ${tomcat.version} - provided - @@ -131,11 +127,15 @@ 2.4 webapp + false maven-eclipse-plugin 2.9 + + true + org.apache.maven.plugins diff --git a/src/main/java/core/db/DataBase.java b/src/main/java/core/db/DataBase.java new file mode 100644 index 000000000..1931f88bd --- /dev/null +++ b/src/main/java/core/db/DataBase.java @@ -0,0 +1,28 @@ +package core.db; + +import java.util.Collection; +import java.util.Map; + +import com.google.common.collect.Maps; + +import next.model.User; + +public class DataBase { + private static Map users = Maps.newHashMap(); + + static { + users.put("admin", new User("admin", "password", "자바지기", "admin@slipp.net")); + } + + public static void addUser(User user) { + users.put(user.getUserId(), user); + } + + public static User findUserById(String userId) { + return users.get(userId); + } + + public static Collection findAll() { + return users.values(); + } +} diff --git a/src/main/java/core/jdbc/ConnectionManager.java b/src/main/java/core/jdbc/ConnectionManager.java index cc7a37439..042d8fcec 100644 --- a/src/main/java/core/jdbc/ConnectionManager.java +++ b/src/main/java/core/jdbc/ConnectionManager.java @@ -5,28 +5,28 @@ import javax.sql.DataSource; -import org.apache.commons.dbcp.BasicDataSource; +import org.apache.commons.dbcp2.BasicDataSource; public class ConnectionManager { - private static final String DB_DRIVER = "org.h2.Driver"; - private static final String DB_URL = "jdbc:h2:~/jwp-basic;AUTO_SERVER=TRUE"; - private static final String DB_USERNAME = "sa"; - private static final String DB_PW = ""; - - public static DataSource getDataSource() { - BasicDataSource ds = new BasicDataSource(); - ds.setDriverClassName(DB_DRIVER); - ds.setUrl(DB_URL); - ds.setUsername(DB_USERNAME); - ds.setPassword(DB_PW); - return ds; - } - - public static Connection getConnection() { - try { - return getDataSource().getConnection(); - } catch (SQLException e) { - throw new IllegalStateException(e); - } - } + private static final String DB_DRIVER = "org.h2.Driver"; + private static final String DB_URL = "jdbc:h2:~/jwp-basic;AUTO_SERVER=TRUE"; + private static final String DB_USERNAME = "sa"; + private static final String DB_PW = ""; + + public static DataSource getDataSource() { + BasicDataSource ds = new BasicDataSource(); + ds.setDriverClassName(DB_DRIVER); + ds.setUrl(DB_URL); + ds.setUsername(DB_USERNAME); + ds.setPassword(DB_PW); + return ds; + } + + public static Connection getConnection() { + try { + return getDataSource().getConnection(); + } catch (SQLException e) { + throw new IllegalStateException(e); + } + } } diff --git a/src/main/java/core/jdbc/DateAccessException.java b/src/main/java/core/jdbc/DateAccessException.java new file mode 100644 index 000000000..8c2750da7 --- /dev/null +++ b/src/main/java/core/jdbc/DateAccessException.java @@ -0,0 +1,24 @@ +package core.jdbc; + +public class DateAccessException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public DateAccessException() { + super(); + } + + public DateAccessException(String message,Throwable cause,boolean enableSuppression,boolean writeableStackTrace) { + super(message,cause,enableSuppression,writeableStackTrace); + } + + public DateAccessException(String message,Throwable cause) { + super(message,cause); + } + public DateAccessException(String message) { + super(message); + } + public DateAccessException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/core/jdbc/JdbcTemplate.java b/src/main/java/core/jdbc/JdbcTemplate.java new file mode 100644 index 000000000..5b7d04c42 --- /dev/null +++ b/src/main/java/core/jdbc/JdbcTemplate.java @@ -0,0 +1,102 @@ +package core.jdbc; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.jdbc.core.PreparedStatementCreator; + +public class JdbcTemplate { + + + + public void update(String sql,PreparedStatementSetter pss) throws DateAccessException { + + try(Connection con = ConnectionManager.getConnection(); + PreparedStatement pstmt = con.prepareStatement(sql); + ) { + + pss.setParameters(pstmt); + pstmt.executeUpdate(); + + } catch (SQLException e) { + throw new DateAccessException(e); + } + } + public void update(PreparedStatementCreator psc,KeyHolder holder) throws DateAccessException { + + try(Connection con = ConnectionManager.getConnection()) { + + PreparedStatement pstmt = psc.createPreparedStatement(con); + pstmt.executeUpdate(); + + ResultSet rs=pstmt.getGeneratedKeys(); + if(rs.next()) { + holder.setId(rs.getLong(1)); + } + rs.close(); + } catch (SQLException e) { + throw new DateAccessException(e); + } + } + + public void update(String sql,Object... parameters)throws DateAccessException { + + update(sql,createPreparedStatementSetter(parameters)); + } + + public List query(String sql,PreparedStatementSetter pss,RowMapper rm) throws DateAccessException{ + ResultSet rs = null; + try(Connection con= ConnectionManager.getConnection(); + PreparedStatement pstmt = con.prepareStatement(sql)){ + + pss.setParameters(pstmt); + + rs = pstmt.executeQuery(); + + List result = new ArrayList(); + while(rs.next()){ + result.add(rm.mapRow(rs)); + } + + return result; + } catch (SQLException e) { + throw new DateAccessException(e); + }finally { + if(rs!=null) { + try { + rs.close(); + } catch (SQLException e) { + throw new DateAccessException(e); + } + } + } + } + public List query(String sql,RowMapper rm,Object... parameters) throws DateAccessException{ + return query(sql,createPreparedStatementSetter(parameters),rm); + } + + public T queryForObject(String sql,PreparedStatementSetter pss,RowMapper rm) throws DateAccessException{ + List result = query(sql,pss,rm); + if(result.isEmpty()) { + return null; + }else { + return result.get(0); + } + } + public T queryForObject(String sql,RowMapper rm,Object... parameters) throws DateAccessException{ + return queryForObject(sql,createPreparedStatementSetter(parameters),rm); + } + private PreparedStatementSetter createPreparedStatementSetter(Object...parameters) { + return new PreparedStatementSetter() { + public void setParameters(PreparedStatement pstmt)throws SQLException{ + for(int i=0;i { + T mapRow(ResultSet rs)throws SQLException; +} diff --git a/src/main/java/core/mvc/Controller.java b/src/main/java/core/mvc/Controller.java new file mode 100644 index 000000000..df7b7f2ea --- /dev/null +++ b/src/main/java/core/mvc/Controller.java @@ -0,0 +1,8 @@ +package core.mvc; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public interface Controller { + String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception; +} diff --git a/src/main/java/core/mvc/DispatcherServlet.java b/src/main/java/core/mvc/DispatcherServlet.java new file mode 100644 index 000000000..17102f9d2 --- /dev/null +++ b/src/main/java/core/mvc/DispatcherServlet.java @@ -0,0 +1,56 @@ +package core.mvc; + +import java.io.IOException; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@WebServlet(name = "dispatcher", urlPatterns = "/", loadOnStartup = 1) +public class DispatcherServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class); + private static final String DEFAULT_REDIRECT_PREFIX = "redirect:"; + + private RequestMapping rm; + + @Override + public void init() throws ServletException { + rm = new RequestMapping(); + rm.initMapping(); + } + + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String requestUri = req.getRequestURI(); + logger.debug("Method : {}, Request URI : {}", req.getMethod(), requestUri); + + Controller controller = rm.findController(requestUri); + try { + String viewName = controller.execute(req, resp); + if(viewName!=null) { + move(viewName, req, resp); + } + } catch (Throwable e) { + logger.error("Exception : {}", e); + throw new ServletException(e.getMessage()); + } + } + + private void move(String viewName, HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + if (viewName.startsWith(DEFAULT_REDIRECT_PREFIX)) { + resp.sendRedirect(viewName.substring(DEFAULT_REDIRECT_PREFIX.length())); + return; + } + + RequestDispatcher rd = req.getRequestDispatcher(viewName); + rd.forward(req, resp); + } +} diff --git a/src/main/java/core/mvc/ForwardController.java b/src/main/java/core/mvc/ForwardController.java new file mode 100644 index 000000000..83c9d89f2 --- /dev/null +++ b/src/main/java/core/mvc/ForwardController.java @@ -0,0 +1,20 @@ +package core.mvc; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class ForwardController implements Controller { + private String forwardUrl; + + public ForwardController(String forwardUrl) { + this.forwardUrl = forwardUrl; + if (forwardUrl == null) { + throw new NullPointerException("forwardUrl is null. 이동할 URL을 입력하세요."); + } + } + + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + return forwardUrl; + } +} diff --git a/src/main/java/core/mvc/RequestMapping.java b/src/main/java/core/mvc/RequestMapping.java new file mode 100644 index 000000000..be6344f63 --- /dev/null +++ b/src/main/java/core/mvc/RequestMapping.java @@ -0,0 +1,65 @@ +package core.mvc; + +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import next.controller.HomeController; +import next.controller.qna.AddAnswerController; +import next.controller.qna.CreateQuestionController; +import next.controller.qna.DeleteAnswerController; +import next.controller.qna.DeleteQuestionController; +import next.controller.qna.ShowController; +import next.controller.qna.UpdateAnswerController; +import next.controller.qna.UpdateFormAnswerController; +import next.controller.qna.UpdateFormQuestionController; +import next.controller.qna.UpdateQuestionController; +import next.controller.user.CreateUserController; +import next.controller.user.ListUserController; +import next.controller.user.LoginController; +import next.controller.user.LogoutController; +import next.controller.user.ProfileController; +import next.controller.user.UpdateFormUserController; +import next.controller.user.UpdateUserController; + +public class RequestMapping { + private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class); + private Map mappings = new HashMap<>(); + + void initMapping() { + + + mappings.put("/", new HomeController()); + mappings.put("/users/form", new ForwardController("/user/form.jsp")); + mappings.put("/users/loginForm", new ForwardController("/user/login.jsp")); + mappings.put("/users", new ListUserController()); + mappings.put("/users/login", new LoginController()); + mappings.put("/users/profile", new ProfileController()); + mappings.put("/users/logout", new LogoutController()); + mappings.put("/users/create", new CreateUserController()); + mappings.put("/users/updateForm", new UpdateFormUserController()); + mappings.put("/users/update", new UpdateUserController()); + mappings.put("/qna/show", new ShowController()); + mappings.put("/qna/form", new ForwardController("/qna/form.jsp")); + mappings.put("/qna/create", new CreateQuestionController()); + mappings.put("/qna/delete", new DeleteQuestionController()); + mappings.put("/qna/updateForm", new UpdateFormQuestionController()); + mappings.put("/qna/update", new UpdateQuestionController()); + mappings.put("/api/qna/addAnswer", new AddAnswerController()); + mappings.put("/api/qna/deleteAnswer", new DeleteAnswerController()); + mappings.put("/api/qna/updateFormAnswer", new UpdateFormAnswerController()); + mappings.put("/api/qna/updateAnswer", new UpdateAnswerController()); + + logger.info("Initialized Request Mapping!"); + } + + public Controller findController(String url) { + return mappings.get(url); + } + + void put(String url, Controller controller) { + mappings.put(url, controller); + } +} diff --git a/src/main/java/core/web/AbstractBaseServlet.java b/src/main/java/core/web/AbstractBaseServlet.java deleted file mode 100644 index 21dbe50a8..000000000 --- a/src/main/java/core/web/AbstractBaseServlet.java +++ /dev/null @@ -1,34 +0,0 @@ -package core.web; - -import java.io.OutputStreamWriter; -import java.io.Writer; - -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletResponse; - -import freemarker.cache.WebappTemplateLoader; -import freemarker.template.Configuration; -import freemarker.template.Template; - -public abstract class AbstractBaseServlet extends HttpServlet { - private static final long serialVersionUID = 1L; - - protected void process(String templatePath, HttpServletResponse resp) { - process(templatePath, new Object(), resp); - } - - protected void process(String templatePath, Object data, HttpServletResponse resp) { - Configuration cfg = new Configuration(Configuration.VERSION_2_3_23); - cfg.setDefaultEncoding("UTF-8"); - cfg.setTemplateLoader(new WebappTemplateLoader(getServletContext())); - Template template; - try { - template = cfg.getTemplate(templatePath); - Writer writer = new OutputStreamWriter(resp.getOutputStream()); - template.process(data, writer); - writer.flush(); - } catch (Exception e) { - throw new RuntimeException(e.getMessage()); - } - } -} diff --git a/src/main/java/core/web/filter/CharacterEncodingFilter.java b/src/main/java/core/web/filter/CharacterEncodingFilter.java index af0758338..e6b274f1b 100644 --- a/src/main/java/core/web/filter/CharacterEncodingFilter.java +++ b/src/main/java/core/web/filter/CharacterEncodingFilter.java @@ -12,23 +12,23 @@ @WebFilter("/*") public class CharacterEncodingFilter implements Filter { - private static final String DEFAULT_ENCODING = "UTF-8"; + private static final String DEFAULT_ENCODING = "UTF-8"; - @Override - public void init(FilterConfig filterConfig) throws ServletException { - } + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } - @Override - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws IOException, ServletException { - request.setCharacterEncoding(DEFAULT_ENCODING); - response.setCharacterEncoding(DEFAULT_ENCODING); - chain.doFilter(request, response); + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + request.setCharacterEncoding(DEFAULT_ENCODING); + response.setCharacterEncoding(DEFAULT_ENCODING); + chain.doFilter(request, response); - } + } - @Override - public void destroy() { - } + @Override + public void destroy() { + } } diff --git a/src/main/java/core/web/filter/ResourceFilter.java b/src/main/java/core/web/filter/ResourceFilter.java new file mode 100644 index 000000000..40611da03 --- /dev/null +++ b/src/main/java/core/web/filter/ResourceFilter.java @@ -0,0 +1,65 @@ +package core.web.filter; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@WebFilter("/*") +public class ResourceFilter implements Filter { + private static final Logger logger = LoggerFactory.getLogger(ResourceFilter.class); + private static final List resourcePrefixs = new ArrayList<>(); + static { + resourcePrefixs.add("/css"); + resourcePrefixs.add("/js"); + resourcePrefixs.add("/fonts"); + resourcePrefixs.add("/images"); + resourcePrefixs.add("/favicon.ico"); + } + + private RequestDispatcher defaultRequestDispatcher; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + this.defaultRequestDispatcher = filterConfig.getServletContext().getNamedDispatcher("default"); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) request; + String path = req.getRequestURI().substring(req.getContextPath().length()); + if (isResourceUrl(path)) { + logger.debug("path : {}", path); + defaultRequestDispatcher.forward(request, response); + } else { + chain.doFilter(request, response); + } + } + + private boolean isResourceUrl(String url) { + for (String prefix : resourcePrefixs) { + if (url.startsWith(prefix)) { + return true; + } + } + return false; + } + + @Override + public void destroy() { + } + +} diff --git a/src/main/java/next/controller/CreateUserController.java b/src/main/java/next/controller/CreateUserController.java deleted file mode 100644 index 9cbb43da3..000000000 --- a/src/main/java/next/controller/CreateUserController.java +++ /dev/null @@ -1,42 +0,0 @@ -package next.controller; - -import java.io.IOException; -import java.sql.SQLException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import core.web.AbstractBaseServlet; -import next.dao.UserDao; -import next.model.User; - -@WebServlet(value= {"/user", "/user/form"}) -public class CreateUserController extends AbstractBaseServlet { - private static final Logger LOGGER = LoggerFactory.getLogger(CreateUserController.class); - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - process("form.ftl", resp); - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - User user = new User( - req.getParameter("userId"), - req.getParameter("password"), - req.getParameter("name"), - req.getParameter("email")); - LOGGER.debug("User : {}", user); - UserDao userDao = new UserDao(); - try { - userDao.insert(user); - } catch (SQLException e) { - } - resp.sendRedirect("/"); - } -} diff --git a/src/main/java/next/controller/HomeConroller.java b/src/main/java/next/controller/HomeConroller.java deleted file mode 100644 index a0f0422a8..000000000 --- a/src/main/java/next/controller/HomeConroller.java +++ /dev/null @@ -1,18 +0,0 @@ -package next.controller; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import core.web.AbstractBaseServlet; - - @WebServlet("") -public class HomeConroller extends AbstractBaseServlet { - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - process("home.ftl", resp); - } -} diff --git a/src/main/java/next/controller/HomeController.java b/src/main/java/next/controller/HomeController.java new file mode 100644 index 000000000..fccc34b0d --- /dev/null +++ b/src/main/java/next/controller/HomeController.java @@ -0,0 +1,17 @@ +package next.controller; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import core.mvc.Controller; +import next.dao.QuestionDao; + +public class HomeController implements Controller { + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + QuestionDao questionDao = new QuestionDao(); + req.setAttribute("questions", questionDao.findAll()); + + return "/home.jsp"; + } +} diff --git a/src/main/java/next/controller/UserSessionUtils.java b/src/main/java/next/controller/UserSessionUtils.java new file mode 100644 index 000000000..7483cccda --- /dev/null +++ b/src/main/java/next/controller/UserSessionUtils.java @@ -0,0 +1,36 @@ +package next.controller; + +import javax.servlet.http.HttpSession; + +import next.model.User; + +public class UserSessionUtils { + public static final String USER_SESSION_KEY = "user"; + + public static User getUserFromSession(HttpSession session) { + Object user = session.getAttribute(USER_SESSION_KEY); + if (user == null) { + return null; + } + return (User) user; + } + + public static boolean isLogined(HttpSession session) { + if (getUserFromSession(session) == null) { + return false; + } + return true; + } + + public static boolean isSameUser(HttpSession session, User user) { + if (!isLogined(session)) { + return false; + } + + if (user == null) { + return false; + } + + return user.isSameUser(getUserFromSession(session)); + } +} diff --git a/src/main/java/next/controller/qna/AddAnswerController.java b/src/main/java/next/controller/qna/AddAnswerController.java new file mode 100644 index 000000000..0b6b685e0 --- /dev/null +++ b/src/main/java/next/controller/qna/AddAnswerController.java @@ -0,0 +1,50 @@ +package next.controller.qna; + +import java.io.PrintWriter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; +import next.dao.AnswerDao; +import next.dao.QuestionDao; +import next.model.Answer; + +public class AddAnswerController implements Controller { + private final static Logger log = LoggerFactory.getLogger(AddAnswerController.class); + + + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + if (!UserSessionUtils.isLogined(req.getSession())) { + throw new IllegalStateException(); + } + + Long questionId = Long.parseLong(req.getParameter("questionId")); + QuestionDao questionDao = new QuestionDao(); + log.debug("questionId : {}",questionId); + + Answer answer = new Answer(req.getParameter("writer"),req.getParameter("contents"),questionId); + log.debug("Answer : {}", answer); + AnswerDao answerDao = new AnswerDao(); + Answer savedAnswer = answerDao.insert(answer); + + + log.debug("SavedAnswer : {}", savedAnswer); + + ObjectMapper mapper = new ObjectMapper(); + + resp.setContentType("application/json;charset=UTF-8"); + PrintWriter out = resp.getWriter(); + out.print(mapper.writeValueAsString(savedAnswer)); + + return null; + } + +} diff --git a/src/main/java/next/controller/qna/CreateQuestionController.java b/src/main/java/next/controller/qna/CreateQuestionController.java new file mode 100644 index 000000000..15f17aa5c --- /dev/null +++ b/src/main/java/next/controller/qna/CreateQuestionController.java @@ -0,0 +1,31 @@ +package next.controller.qna; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; +import next.dao.QuestionDao; +import next.model.Question; + +public class CreateQuestionController implements Controller { + private static final Logger log = LoggerFactory.getLogger(CreateQuestionController.class); + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + + if (!UserSessionUtils.isLogined(req.getSession())) { + return "redirect:/users/loginForm"; + } + + Question question = new Question(req.getParameter("writer"),req.getParameter("title"),req.getParameter("contents")); + + QuestionDao questionDao = new QuestionDao(); + questionDao.insert(question); + + return "redirect:/"; + } + +} diff --git a/src/main/java/next/controller/qna/DeleteAnswerController.java b/src/main/java/next/controller/qna/DeleteAnswerController.java new file mode 100644 index 000000000..bf782ab2f --- /dev/null +++ b/src/main/java/next/controller/qna/DeleteAnswerController.java @@ -0,0 +1,61 @@ +package next.controller.qna; + +import java.io.PrintWriter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; +import next.dao.AnswerDao; +import next.dao.QuestionDao; +import next.model.Answer; +import next.model.Question; +import next.model.Result; + +public class DeleteAnswerController implements Controller { + private final static Logger log = LoggerFactory.getLogger(DeleteAnswerController.class); + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + if (!UserSessionUtils.isLogined(req.getSession())) { + return "redirect:/users/loginForm"; + } + Long answerId = Long.parseLong(req.getParameter("answerId")); + long questionId = Long.parseLong(req.getParameter("questionId")); + + QuestionDao questionDao = new QuestionDao(); + AnswerDao answerDao = new AnswerDao(); + Answer answer = answerDao.findById(answerId); + + if (!answer.isSameUser(UserSessionUtils.getUserFromSession(req.getSession()))) { + throw new IllegalStateException(); + } + + + log.debug("answerId : {}", answerId); + + + + + if(answer == null) + return null; + + log.debug("answerId : {}", answer.getAnswerId()); + + answerDao.delete(answerId); + + + ObjectMapper mapper = new ObjectMapper(); + + resp.setContentType("application/json;charset=UTF-8"); + PrintWriter out = resp.getWriter(); + out.print(mapper.writeValueAsString(Result.Ok())); + return null; + } + +} diff --git a/src/main/java/next/controller/qna/DeleteQuestionController.java b/src/main/java/next/controller/qna/DeleteQuestionController.java new file mode 100644 index 000000000..4fa253c3e --- /dev/null +++ b/src/main/java/next/controller/qna/DeleteQuestionController.java @@ -0,0 +1,45 @@ +package next.controller.qna; + +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; +import next.dao.AnswerDao; +import next.dao.QuestionDao; +import next.model.Answer; +import next.model.Question; + +public class DeleteQuestionController implements Controller { + + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + if (!UserSessionUtils.isLogined(req.getSession())) { + return "redirect:/users/loginForm"; + } + + Long questionId = Long.parseLong(req.getParameter("questionId")); + QuestionDao questionDao = new QuestionDao(); + + Question question = questionDao.findById(questionId); + if (!question.isSameUser(UserSessionUtils.getUserFromSession(req.getSession()))) { + throw new IllegalStateException("다른 사용자가 작성한 게시글은 삭제 할 수 없습니다."); + } + + + + AnswerDao answerDao = new AnswerDao(); + List answers = answerDao.findAll(questionId); + for(Answer answer : answers) { + answerDao.delete(answer.getAnswerId()); + } + + + questionDao.delete(questionId); + + return "redirect:/"; + } + +} diff --git a/src/main/java/next/controller/qna/ShowController.java b/src/main/java/next/controller/qna/ShowController.java new file mode 100644 index 000000000..cd21fc658 --- /dev/null +++ b/src/main/java/next/controller/qna/ShowController.java @@ -0,0 +1,29 @@ +package next.controller.qna; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import core.mvc.Controller; +import next.dao.AnswerDao; +import next.dao.QuestionDao; + +public class ShowController implements Controller { + private final static Logger log = LoggerFactory.getLogger(ShowController.class); + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + log.debug("questionId={}",req.getParameter("questionId")); + log.debug("answerId={}",req.getParameter("answerId")); + Long questionId = Long.parseLong(req.getParameter("questionId")); + QuestionDao questionDao = new QuestionDao(); + AnswerDao answerDao = new AnswerDao(); + + req.setAttribute("question", questionDao.findById(questionId)); + req.setAttribute("answers", answerDao.findAll(questionId)); + + return "/qna/show.jsp"; + } + +} diff --git a/src/main/java/next/controller/qna/UpdateAnswerController.java b/src/main/java/next/controller/qna/UpdateAnswerController.java new file mode 100644 index 000000000..2abecb998 --- /dev/null +++ b/src/main/java/next/controller/qna/UpdateAnswerController.java @@ -0,0 +1,30 @@ +package next.controller.qna; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import core.mvc.Controller; +import next.dao.AnswerDao; +import next.model.Answer; + +public class UpdateAnswerController implements Controller { + + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + + AnswerDao answerDao = new AnswerDao(); + System.out.println(req.getParameter("answerId")); + long answerId = Long.parseLong(req.getParameter("answerId")); + + + Answer answer = answerDao.findById(answerId); + + + Answer newAnswer = new Answer( answer.getWriter(), req.getParameter("contents"),answer.getAnswerId()); + answer.update(newAnswer); + answerDao.update(answer,answerId); + + return "redirect:/"; + } + +} diff --git a/src/main/java/next/controller/qna/UpdateFormAnswerController.java b/src/main/java/next/controller/qna/UpdateFormAnswerController.java new file mode 100644 index 000000000..69303c954 --- /dev/null +++ b/src/main/java/next/controller/qna/UpdateFormAnswerController.java @@ -0,0 +1,33 @@ +package next.controller.qna; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; +import next.dao.AnswerDao; +import next.model.Answer; + +public class UpdateFormAnswerController implements Controller { + + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + if (!UserSessionUtils.isLogined(req.getSession())) { + return "redirect:/users/loginForm"; + } + + AnswerDao answerDao = new AnswerDao(); + long answerId = Long.parseLong(req.getParameter("answerId")); + Answer answer = answerDao.findById(answerId); + + + + if (!answer.isSameUser(UserSessionUtils.getUserFromSession(req.getSession()))) { + throw new IllegalStateException("다른 사용자가 작성한 게시글은 수정 할 수 없습니다."); + } + req.setAttribute("answer", answer); + + return "/qna/AnswerRevise.jsp"; + } + +} diff --git a/src/main/java/next/controller/qna/UpdateFormQuestionController.java b/src/main/java/next/controller/qna/UpdateFormQuestionController.java new file mode 100644 index 000000000..3473998cb --- /dev/null +++ b/src/main/java/next/controller/qna/UpdateFormQuestionController.java @@ -0,0 +1,31 @@ +package next.controller.qna; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; +import next.dao.QuestionDao; +import next.model.Question; + +public class UpdateFormQuestionController implements Controller { + + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + if (!UserSessionUtils.isLogined(req.getSession())) { + return "redirect:/users/loginForm"; + } + + QuestionDao questionDao = new QuestionDao(); + long questionId = Long.parseLong(req.getParameter("questionId")); + Question question = questionDao.findById(questionId); + + + if (!question.isSameUser(UserSessionUtils.getUserFromSession(req.getSession()))) { + throw new IllegalStateException("다른 사용자가 작성한 게시글은 수정 할 수 없습니다."); + } + req.setAttribute("question", question); + return "/qna/QuestionRevise.jsp"; + } + +} diff --git a/src/main/java/next/controller/qna/UpdateQuestionController.java b/src/main/java/next/controller/qna/UpdateQuestionController.java new file mode 100644 index 000000000..e6b4e05e6 --- /dev/null +++ b/src/main/java/next/controller/qna/UpdateQuestionController.java @@ -0,0 +1,29 @@ +package next.controller.qna; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; +import next.dao.QuestionDao; +import next.model.Question; + +public class UpdateQuestionController implements Controller { + QuestionDao questionDao = new QuestionDao(); + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + if (!UserSessionUtils.isLogined(req.getSession())) { + return "redirect:/users/loginForm"; + } + long questionId = Long.parseLong(req.getParameter("questionId")); + Question question = questionDao.findById(questionId); + + + Question newQuestion = new Question( question.getWriter(),req.getParameter("title"), req.getParameter("contents")); + question.update(newQuestion); + questionDao.update(question,questionId); + + return "redirect:/"; + } + +} diff --git a/src/main/java/next/controller/user/CreateUserController.java b/src/main/java/next/controller/user/CreateUserController.java new file mode 100644 index 000000000..629be1ea2 --- /dev/null +++ b/src/main/java/next/controller/user/CreateUserController.java @@ -0,0 +1,34 @@ +package next.controller.user; + +import java.sql.SQLException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import core.mvc.Controller; +import next.dao.UserDao; +import next.model.User; + +public class CreateUserController implements Controller { + private static final Logger log = LoggerFactory.getLogger(CreateUserController.class); + + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + User user = new User(req.getParameter("userId"), req.getParameter("password"), req.getParameter("name"), + req.getParameter("email")); + log.debug("User : {}", user); + + UserDao userDao = new UserDao(); + + try{ + userDao.insert(user); + }catch(SQLException e){ + log.debug(e.getMessage()); + } + + return "redirect:/"; + } +} diff --git a/src/main/java/next/controller/user/ListUserController.java b/src/main/java/next/controller/user/ListUserController.java new file mode 100644 index 000000000..128742d33 --- /dev/null +++ b/src/main/java/next/controller/user/ListUserController.java @@ -0,0 +1,22 @@ +package next.controller.user; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; +import next.dao.UserDao; + +public class ListUserController implements Controller { + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + if (!UserSessionUtils.isLogined(req.getSession())) { + return "redirect:/users/loginForm"; + } + + UserDao userDao = new UserDao(); + + req.setAttribute("users", userDao.findAll()); + return "/user/list.jsp"; + } +} diff --git a/src/main/java/next/controller/user/LoginController.java b/src/main/java/next/controller/user/LoginController.java new file mode 100644 index 000000000..693d48b0b --- /dev/null +++ b/src/main/java/next/controller/user/LoginController.java @@ -0,0 +1,34 @@ +package next.controller.user; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; +import next.dao.UserDao; +import next.model.User; + +public class LoginController implements Controller { + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + String userId = req.getParameter("userId"); + String password = req.getParameter("password"); + + UserDao userDao = new UserDao(); + User user = userDao.findByUserId(userId); + + if (user == null) { + req.setAttribute("loginFailed", true); + return "/user/login.jsp"; + } + if (user.matchPassword(password)) { + HttpSession session = req.getSession(); + session.setAttribute(UserSessionUtils.USER_SESSION_KEY, user); + return "redirect:/"; + } else { + req.setAttribute("loginFailed", true); + return "/user/login.jsp"; + } + } +} diff --git a/src/main/java/next/controller/user/LogoutController.java b/src/main/java/next/controller/user/LogoutController.java new file mode 100644 index 000000000..08a8cee33 --- /dev/null +++ b/src/main/java/next/controller/user/LogoutController.java @@ -0,0 +1,17 @@ +package next.controller.user; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; + +public class LogoutController implements Controller { + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + HttpSession session = req.getSession(); + session.removeAttribute(UserSessionUtils.USER_SESSION_KEY); + return "redirect:/"; + } +} diff --git a/src/main/java/next/controller/user/ProfileController.java b/src/main/java/next/controller/user/ProfileController.java new file mode 100644 index 000000000..72ab1dfba --- /dev/null +++ b/src/main/java/next/controller/user/ProfileController.java @@ -0,0 +1,22 @@ +package next.controller.user; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import core.mvc.Controller; +import next.dao.UserDao; +import next.model.User; + +public class ProfileController implements Controller { + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + UserDao userDao =new UserDao(); + String userId = req.getParameter("userId"); + User user = userDao.findByUserId(userId); + if (user == null) { + throw new NullPointerException("사용자를 찾을 수 없습니다."); + } + req.setAttribute("user", user); + return "/user/profile.jsp"; + } +} diff --git a/src/main/java/next/controller/user/UpdateFormUserController.java b/src/main/java/next/controller/user/UpdateFormUserController.java new file mode 100644 index 000000000..51187658c --- /dev/null +++ b/src/main/java/next/controller/user/UpdateFormUserController.java @@ -0,0 +1,24 @@ +package next.controller.user; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; +import next.dao.UserDao; +import next.model.User; + +public class UpdateFormUserController implements Controller { + + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + UserDao userDao =new UserDao(); + String userId = req.getParameter("userId"); + User user = userDao.findByUserId(userId); + if (!UserSessionUtils.isSameUser(req.getSession(), user)) { + throw new IllegalStateException("다른 사용자의 정보를 수정할 수 없습니다."); + } + req.setAttribute("user", user); + return "/user/updateForm.jsp"; + } +} diff --git a/src/main/java/next/controller/user/UpdateUserController.java b/src/main/java/next/controller/user/UpdateUserController.java new file mode 100644 index 000000000..ab92ad0bd --- /dev/null +++ b/src/main/java/next/controller/user/UpdateUserController.java @@ -0,0 +1,32 @@ +package next.controller.user; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import core.mvc.Controller; +import next.controller.UserSessionUtils; +import next.dao.UserDao; +import next.model.User; + +public class UpdateUserController implements Controller { + private static final Logger log = LoggerFactory.getLogger(UpdateUserController.class); + + @Override + public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + UserDao userDao =new UserDao(); + String userId = req.getParameter("userId"); + User user = userDao.findByUserId(userId); + if (!UserSessionUtils.isSameUser(req.getSession(), user)) { + throw new IllegalStateException("다른 사용자의 정보를 수정할 수 없습니다."); + } + + User updateUser = new User(req.getParameter("userId"), req.getParameter("password"), req.getParameter("name"), + req.getParameter("email")); + log.debug("Update User : {}", updateUser); + userDao.update(updateUser); + return "redirect:/"; + } +} diff --git a/src/main/java/next/dao/AnswerDao.java b/src/main/java/next/dao/AnswerDao.java new file mode 100644 index 000000000..182a9ae75 --- /dev/null +++ b/src/main/java/next/dao/AnswerDao.java @@ -0,0 +1,77 @@ +package next.dao; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.core.PreparedStatementCreator; + +import core.jdbc.JdbcTemplate; +import core.jdbc.KeyHolder; +import next.controller.qna.DeleteAnswerController; +import next.model.Answer; +import next.model.Question; + +public class AnswerDao { + private final static Logger log = LoggerFactory.getLogger(DeleteAnswerController.class); + public List findAll(long questionId) throws SQLException { + + JdbcTemplate jdbcTemplate = new JdbcTemplate(); + + String sql = "SELECT answerId, writer, contents, createdDate, questionId FROM ANSWERS WHERE questionId=? ORDER BY answerId DESC"; + return jdbcTemplate.query(sql,(ResultSet rs)->{ + return new Answer(rs.getLong("answerId"),rs.getString("writer"),rs.getString("contents"),rs.getTimestamp("createdDate"),rs.getLong("questionId")); + + },questionId); + } + + public Answer findById(long answerId) throws SQLException { + JdbcTemplate jdbcTemplate = new JdbcTemplate(); + + String sql = "SELECT answerId, writer, contents, createdDate, questionId FROM ANSWERS WHERE answerId=?"; + return jdbcTemplate .queryForObject(sql,(ResultSet rs)->{ + return new Answer(rs.getLong("answerId"),rs.getString("writer"),rs.getString("contents"),rs.getTimestamp("createdDate"),rs.getLong("questionId"));},answerId); + + } + public void delete(Long answerId) { + JdbcTemplate jdbcTemplate =new JdbcTemplate(); + + String sql ="DELETE FROM ANSWERS WHERE answerId=?"; + jdbcTemplate.update(sql,answerId); + } + + public Answer insert(Answer answer) throws SQLException { + JdbcTemplate jdbcTemplate = new JdbcTemplate(); + String sql ="INSERT INTO ANSWERS (writer, contents, createdDate, questionId) VALUES (?, ?, ?, ?)"; + + PreparedStatementCreator psc = new PreparedStatementCreator() { + + @Override + public PreparedStatement createPreparedStatement(Connection con) throws SQLException { + PreparedStatement pstmt = con.prepareStatement(sql); + pstmt.setString(1, answer.getWriter()); + pstmt.setString(2, answer.getContents()); + pstmt.setTimestamp(3, new Timestamp(answer.getTimeFromCreatedDate())); + pstmt.setLong(4, answer.getQuestionId()); + return pstmt; + } + + }; + KeyHolder holder = new KeyHolder(); + jdbcTemplate.update(psc, holder); + return findById(holder.getId()); + + } + public void update(Answer answer,Long answerId) { + + JdbcTemplate jdbcTemplate = new JdbcTemplate(); + + String sql = "UPDATE ANSWERS set contents = ? WHERE answerId = ?"; + jdbcTemplate.update(sql, answer.getContents(), answer.getAnswerId()); + } +} diff --git a/src/main/java/next/dao/QuestionDao.java b/src/main/java/next/dao/QuestionDao.java new file mode 100644 index 000000000..b4c9593cd --- /dev/null +++ b/src/main/java/next/dao/QuestionDao.java @@ -0,0 +1,53 @@ +package next.dao; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import core.jdbc.JdbcTemplate; +import next.model.Question; + +public class QuestionDao { + @SuppressWarnings("unchecked") + public List findAll() throws SQLException { + + JdbcTemplate jdbcTemplate = new JdbcTemplate(); + + String sql = "SELECT questionId, writer, title, contents, createdDate, countOfAnswer FROM QUESTIONS"; + return (List) jdbcTemplate.query(sql,(ResultSet rs)->{ + return new Question(rs.getLong("questionId"),rs.getString("writer"),rs.getString("title"),rs.getString("contents"),rs.getTimestamp("createdDate"),rs.getInt("countOfAnswer")); + + }); + } + + public Question findById(Long questionId) throws SQLException { + JdbcTemplate jdbcTemplate = new JdbcTemplate(); + + String sql = "SELECT questionId, writer, title, contents, createdDate, countOfAnswer FROM QUESTIONS WHERE questionId=?"; + return (Question) jdbcTemplate .queryForObject(sql,(ResultSet rs)->{ + return new Question(rs.getLong("questionId"),rs.getString("writer"),rs.getString("title"),rs.getString("contents"),rs.getTimestamp("createdDate"),rs.getInt("countOfAnswer"));},questionId); + + } + + public void insert(Question question) { + JdbcTemplate jdbcTemplate = new JdbcTemplate(); + + String sql = "INSERT INTO QUESTIONS (writer, title, contents, createdDate, countOfAnswer) VALUES (?, ?, ?, ?, ?)"; + jdbcTemplate.update( sql, question.getWriter(),question.getTitle(),question.getContents(),question.getCreateDate(),question.getCountOfAnswer()); + + } + public void delete(Long questionId) { + JdbcTemplate jdbcTemplate =new JdbcTemplate(); + + String sql ="DELETE FROM QUESTIONS WHERE questionId=?"; + jdbcTemplate.update(sql,questionId); + } + + public void update(Question question,Long questionId) { + JdbcTemplate jdbcTemplate = new JdbcTemplate(); + + String sql = "UPDATE QUESTIONS set title = ?, contents = ? WHERE questionId = ?"; + jdbcTemplate.update(sql, question.getTitle(), question.getContents(), question.getQuestionId()); + } + +} \ No newline at end of file diff --git a/src/main/java/next/dao/Result.java b/src/main/java/next/dao/Result.java new file mode 100644 index 000000000..d1a8c3342 --- /dev/null +++ b/src/main/java/next/dao/Result.java @@ -0,0 +1,36 @@ +package next.dao; + +public class Result { + private boolean status; + private String message; + + private Result(boolean status) { + this(status, ""); + } + + private Result(boolean status, String message) { + this.status = status; + this.message = message; + } + + public static Result ok() { + return new Result(true); + } + + public static Result fail(String message) { + return new Result(false, message); + } + + public boolean isStatus() { + return status; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return "Result [status=" + status + ", message=" + message + "]"; + } +} diff --git a/src/main/java/next/dao/UserDao.java b/src/main/java/next/dao/UserDao.java index 17c15b892..3bc7755ed 100644 --- a/src/main/java/next/dao/UserDao.java +++ b/src/main/java/next/dao/UserDao.java @@ -1,70 +1,53 @@ package next.dao; -import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.List; -import core.jdbc.ConnectionManager; +import core.jdbc.JdbcTemplate; import next.model.User; public class UserDao { - public void insert(User user) throws SQLException { - Connection con = null; - PreparedStatement pstmt = null; - try { - con = ConnectionManager.getConnection(); - String sql = "INSERT INTO USERS VALUES (?, ?, ?, ?)"; - pstmt = con.prepareStatement(sql); - pstmt.setString(1, user.getUserId()); - pstmt.setString(2, user.getPassword()); - pstmt.setString(3, user.getName()); - pstmt.setString(4, user.getEmail()); - - pstmt.executeUpdate(); - } finally { - if (pstmt != null) { - pstmt.close(); - } - - if (con != null) { - con.close(); - } - } - } - - public User findByUserId(String userId) throws SQLException { - Connection con = null; - PreparedStatement pstmt = null; - ResultSet rs = null; - try { - con = ConnectionManager.getConnection(); - String sql = "SELECT userId, password, name, email FROM USERS WHERE userid=?"; - pstmt = con.prepareStatement(sql); - pstmt.setString(1, userId); - - rs = pstmt.executeQuery(); - - User user = null; - if (rs.next()) { - user = new User( - rs.getString("userId"), - rs.getString("password"), - rs.getString("name"), - rs.getString("email")); - } - - return user; - } finally { - if (rs != null) { - rs.close(); - } - if (pstmt != null) { - pstmt.close(); - } - if (con != null) { - con.close(); - } - } - } + public void insert(User user) throws SQLException { + JdbcTemplate jdbcTamplate = new JdbcTemplate(); + + + String sql ="INSERT INTO USERS VALUES (?, ?, ?, ?)"; + jdbcTamplate.update(sql,user.getUserId(),user.getPassword(),user.getName(),user.getEmail()); + } + + public void update(User user) throws SQLException { + JdbcTemplate jdbcTamplate = new JdbcTemplate(); + + + String sql ="UPDATE USERS set password=?,name=?,email = ? WHERE userId =?"; + jdbcTamplate.update(sql,user.getPassword(),user.getName(),user.getEmail(),user.getUserId()); + + } + + @SuppressWarnings("unchecked") + public List findAll() throws SQLException { + + JdbcTemplate jdbcTemplate = new JdbcTemplate(); + + String sql = "SELECT userId,password,name,email FROM USERS"; + return (List) jdbcTemplate.query(sql,(ResultSet rs)->{ + return new User(rs.getString("userId"),rs.getString("password"),rs.getString("name"),rs.getString("email")); + + }); + } + + public User findByUserId(String userId) throws SQLException { + JdbcTemplate jdbcTemplate = new JdbcTemplate(); + + String sql = "SELECT userId,password,name,email FROM USERS WHERE userid=?"; + return (User) jdbcTemplate .queryForObject(sql,(ResultSet rs)->{ + return new User(rs.getString("userId"),rs.getString("password"),rs.getString("name"),rs.getString("email")); + + },userId); + + + } + } diff --git a/src/main/java/next/model/Answer.java b/src/main/java/next/model/Answer.java new file mode 100644 index 000000000..d45c2d60f --- /dev/null +++ b/src/main/java/next/model/Answer.java @@ -0,0 +1,104 @@ +package next.model; + +import java.util.Date; + +public class Answer { + private long questionId; + private String writer; + private String contents; + private Date createDate; + private long answerId; + private int countOfAnswer; + public Answer(String writer,String contents,long questionId) { + this(0,writer,contents,new Date(),questionId); + } + + + public Answer(long answerId,String writer,String contents,Date createDate,long questionId) { + this.questionId = questionId; + this.writer = writer; + this.contents = contents; + this.createDate = createDate; + this.answerId = answerId; + } + + public long getQuestionId(){ + return questionId; + } + + + public String getWriter() { + return writer; + } + + public String getContents() { + return contents; + } + + public Date getCreateDate() { + return createDate; + } + + public long getTimeFromCreatedDate() { + return this.createDate.getTime(); + } + + public long getAnswerId() { + return answerId; + } + + public int getCountOfAnswer() { + return countOfAnswer; + } + + public void setCountOfAnswer(int count) { + this.countOfAnswer=count; + } + + @Override + public int hashCode() { + final int prime =31; + int result = 1; + + result = prime*result+(int)(questionId^(questionId>>>32)); + return result; + } + public void update(Answer newAnswer) { + this.contents = newAnswer.contents; + } + + @Override + public boolean equals(Object obj) { + if(this==obj) { + return true; + } + if(obj==null) { + return false; + } + if(this.getClass()!=obj.getClass()) { + return false; + } + Answer other = (Answer) obj; + if(questionId != other.questionId) { + return false; + }else { + return true; + } + + } + + + @Override + public String toString() { + return "Answer [answerId="+answerId+",writer ="+writer+"," + + "contents="+contents+",createdDate"+createDate+",questionId="+questionId; + } + + + public boolean isSameUser(User userFromSession) { + return userFromSession.isSameUser(this.writer); + } + + + +} diff --git a/src/main/java/next/model/Question.java b/src/main/java/next/model/Question.java new file mode 100644 index 000000000..66f61c8a4 --- /dev/null +++ b/src/main/java/next/model/Question.java @@ -0,0 +1,102 @@ +package next.model; + +import java.util.Date; + +public class Question { + private long questionId; + private String writer; + private String title; + private String contents; + private Date createDate; + private int countOfAnswer; + + public Question(String writer,String title,String contents) { + this(0,writer,title,contents,new Date(),0); + } + + public boolean isSameUser(User user) { + return user.isSameUser(this.writer); + } + + public Question(long questionId,String writer,String title,String contents,Date createDate,int countOfAnswer) { + this.questionId = questionId; + this.writer = writer; + this.title = title; + this.contents = contents; + this.createDate = createDate; + this.countOfAnswer = countOfAnswer; + } + + public long getQuestionId(){ + return questionId; + } + + + public String getWriter() { + return writer; + } + + + public String getTitle() { + return title; + } + + + public String getContents() { + return contents; + } + + public Date getCreateDate() { + return createDate; + } + + + public int getCountOfAnswer() { + return countOfAnswer; + } + + public void update(Question newQuestion) { + this.title = newQuestion.title; + this.contents = newQuestion.contents; + } + + @Override + public int hashCode() { + final int prime =31; + int result = 1; + + result = prime*result+(int)(questionId^(questionId>>>32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if(this==obj) { + return true; + } + if(obj==null) { + return false; + } + if(this.getClass()!=obj.getClass()) { + return false; + } + Question other = (Question) obj; + if(questionId != other.questionId) { + return false; + }else { + return true; + } + + } + + + @Override + public String toString() { + return "Question [questionId="+questionId+",writer ="+writer+",title="+title+"," + + "contents="+contents+",createdDate"+createDate+",countOfAnswer="+countOfAnswer; + } + + + + +} diff --git a/src/main/java/next/model/Result.java b/src/main/java/next/model/Result.java new file mode 100644 index 000000000..79cd838e5 --- /dev/null +++ b/src/main/java/next/model/Result.java @@ -0,0 +1,33 @@ +package next.model; + +public class Result { + private boolean status; + private String message; + + public Result(boolean status) { + this(status,""); + } + + public Result(boolean status,String message) { + this.status=status; + this.message=message; + } + + public static Result Ok() { + return new Result(true); + } + + public static Result Fail(String message) { + return new Result(false,message); + } + + public boolean isStatus() { + return this.status; + } + public String getmessage() { + return this.message; + } + public String toString() { + return "Result [Status = "+status+", message="+message+"]"; + } +} diff --git a/src/main/java/next/model/User.java b/src/main/java/next/model/User.java index 62e5ef69e..52acc03b8 100644 --- a/src/main/java/next/model/User.java +++ b/src/main/java/next/model/User.java @@ -1,73 +1,100 @@ package next.model; public class User { - private String userId; - private String password; - private String name; - private String email; + private String userId; + private String password; + private String name; + private String email; - public User(String userId, String password, String name, String email) { - this.userId = userId; - this.password = password; - this.name = name; - this.email = email; - } + public User(String userId, String password, String name, String email) { + this.userId = userId; + this.password = password; + this.name = name; + this.email = email; + } - public String getUserId() { - return userId; - } + public String getUserId() { + return userId; + } - public String getPassword() { - return password; - } + public String getPassword() { + return password; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public String getEmail() { - return email; - } + public String getEmail() { + return email; + } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((email == null) ? 0 : email.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((userId == null) ? 0 : userId.hashCode()); - return result; - } + public void update(User updateUser) { + this.password = updateUser.password; + this.name = updateUser.name; + this.email = updateUser.email; + } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - User other = (User) obj; - if (email == null) { - if (other.email != null) - return false; - } else if (!email.equals(other.email)) - return false; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - if (userId == null) { - if (other.userId != null) - return false; - } else if (!userId.equals(other.userId)) - return false; - return true; - } + public boolean matchPassword(String password) { + if (password == null) { + return false; + } - @Override - public String toString() { - return "User [userId=" + userId + ", name=" + name + ", email=" + email + "]"; - } + return this.password.equals(password); + } + + public boolean isSameUser(User user) { + return userId.equals(user.userId); + } + + + + + public boolean isSameUser(String newUserId) { + return userId.equals(newUserId); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((email == null) ? 0 : email.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((userId == null) ? 0 : userId.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; + User other = (User) obj; + if (email == null) { + if (other.email != null) + return false; + } else if (!email.equals(other.email)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (userId == null) { + if (other.userId != null) + return false; + } else if (!userId.equals(other.userId)) + return false; + return true; + } + + @Override + public String toString() { + return "User [userId=" + userId + ", name=" + name + ", email=" + email + "]"; + } + + } diff --git a/src/main/java/next/support/context/ContextLoaderListener.java b/src/main/java/next/support/context/ContextLoaderListener.java index a53fe8923..4e5728872 100644 --- a/src/main/java/next/support/context/ContextLoaderListener.java +++ b/src/main/java/next/support/context/ContextLoaderListener.java @@ -14,18 +14,18 @@ @WebListener public class ContextLoaderListener implements ServletContextListener { - private static final Logger logger = LoggerFactory.getLogger(ContextLoaderListener.class); - - @Override - public void contextInitialized(ServletContextEvent sce) { - ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); - populator.addScript(new ClassPathResource("jwp.sql")); - DatabasePopulatorUtils.execute(populator, ConnectionManager.getDataSource()); - - logger.info("Completed Load ServletContext!"); - } + private static final Logger logger = LoggerFactory.getLogger(ContextLoaderListener.class); - @Override - public void contextDestroyed(ServletContextEvent sce) { - } + @Override + public void contextInitialized(ServletContextEvent sce) { + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); + populator.addScript(new ClassPathResource("jwp.sql")); + DatabasePopulatorUtils.execute(populator, ConnectionManager.getDataSource()); + + logger.info("Completed Load ServletContext!"); + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + } } diff --git a/src/main/resources/jwp.sql b/src/main/resources/jwp.sql index 85a9d3885..cf19df195 100644 --- a/src/main/resources/jwp.sql +++ b/src/main/resources/jwp.sql @@ -9,4 +9,125 @@ CREATE TABLE USERS ( PRIMARY KEY (userId) ); -INSERT INTO USERS VALUES('admin', 'password', '자바지기', 'admin@slipp.net'); \ No newline at end of file +INSERT INTO USERS VALUES('admin', 'password', '자바지기', 'admin@slipp.net'); +INSERT INTO USERS VALUES('hgd', '1', '홍길동', 'hgd@slipp.net'); + +DROP TABLE IF EXISTS QUESTIONS; + +CREATE TABLE QUESTIONS ( + questionId bigint auto_increment, + writer varchar(30) NOT NULL, + title varchar(50) NOT NULL, + contents varchar(5000) NOT NULL, + createdDate timestamp NOT NULL, + countOfAnswer int, + PRIMARY KEY (questionId) +); + +DROP TABLE IF EXISTS ANSWERS; + +CREATE TABLE ANSWERS ( + answerId bigint auto_increment, + writer varchar(30) NOT NULL, + contents varchar(5000) NOT NULL, + createdDate timestamp NOT NULL, + questionId bigint NOT NULL, + PRIMARY KEY (answerId) +); + +INSERT INTO QUESTIONS (questionId, writer, title, contents, createdDate, countOfAnswer) VALUES +(1, '자바지기', +'국내에서 Ruby on Rails와 Play가 활성화되기 힘든 이유는 뭘까?', +'Ruby on Rails(이하 RoR)는 2006년 즈음에 정말 뜨겁게 달아올랐다가 금방 가라 앉았다. Play 프레임워크는 정말 한 순간 잠시 눈에 뜨이다가 사라져 버렸다. RoR과 Play 기반으로 개발을 해보면 정말 생산성이 높으며, 웹 프로그래밍이 재미있기까지 하다. Spring MVC + JPA(Hibernate) 기반으로 진행하면 설정할 부분도 많고, 기본으로 지원하지 않는 기능도 많아 RoR과 Play에서 기본적으로 지원하는 기능을 서비스하려면 추가적인 개발이 필요하다.', +CURRENT_TIMESTAMP(), 0); + +INSERT INTO QUESTIONS (questionId, writer, title, contents, createdDate, countOfAnswer) VALUES +(2, '김문수', +'runtime 에 reflect 발동 주체 객체가 뭔지 알 방법이 있을까요?', +'설계를 희한하게 하는 바람에 꼬인 문제같긴 합니다만. 여쭙습니다. +상황은 mybatis select 실행될 시에 return object 의 getter 가 호출되면서인데요. getter 안에 다른 property 에 의존중인 코드가 삽입되어 있어서, 만약 다른 mybatis select 구문에 해당 property 가 없다면 exception 이 발생하게 됩니다.', +CURRENT_TIMESTAMP(), 0); + +INSERT INTO QUESTIONS (questionId, writer, title, contents, createdDate, countOfAnswer) VALUES +(3, '자바지기', +'scala에서 named parameter를 활용한 test fixture 생성 방법', +'자바로 구현할 때 귀찮은 작업 중의 하나는 객체의 복잡도가 증가하는 경우 test fixture를 생성하는 것이 여간 귀찮은 작업이 아니다. +스칼라는 named parameter를 활용해 test fixture를 생성할 수 있다.', +CURRENT_TIMESTAMP(), 0); + + +INSERT INTO QUESTIONS (questionId, writer, title, contents, createdDate, countOfAnswer) VALUES +(4, '자바지기', +'DB 설계할 때 table id는 어떤 방식을 사용하나요?', +'어느 순간부터 DB id를 설계할 때 특별히 신경을 쓰지 않은 것 같네요. 최근에는 JPA 사용하면서 무의식적으로 auto increment를 사용하고 있어요. 물론 auto increment가 적합한 경우도 있겠지만 그렇지 않은 경우도 많다고 생각해요. 보통 DB 설계할 때 각 테이블의 id는 어떤 방식을 사용하나요? +UUID를 사용하는 것도 하나의 방식이 될 수 있을거 같은데요. UUID 사용에 따른 장단점은 JPA Implementation Patterns: Using UUIDs As Primary Keys 문서에서 다루고 있고, 단점을 극복하는 방법을 댓글에서 볼 수 있네요. +테이블 id를 설계할 때 어떤 방식으로 접근하나요? 저는 요즘 너무 아무 생각없이 id를 추가하고 있다는 마음이 들어 질문 남겨 봅니다.', +CURRENT_TIMESTAMP(), 0); + +INSERT INTO QUESTIONS (questionId, writer, title, contents, createdDate, countOfAnswer) VALUES +(5, 'johnburr', +'이클립스 JRE설정에 대해서 질문을 드립니다.', +'이곳에서 보면 이클립스의 jre에 대해서 3개의 설정이 나옵니다. +jre 버전 설정 +실행환경 설정(execution environment) +컴파일러 설정', +CURRENT_TIMESTAMP(), 0); + +INSERT INTO QUESTIONS (questionId, writer, title, contents, createdDate, countOfAnswer) VALUES +(6, '자바지기', +'프로그래머가 알아야할 기본 지식은 어디까지일까?', +'오늘 무엇인가 정리하다가 도대체 프로그래머가 알아야하는 기본 지식은 어디까지일까라는 의문이 들었다. 물론 컴퓨터 기본 구조, 네트워크, 자료 구조, 알고리즘, C, C++, 자바, 다양한 프레임워크 등등 모든 영역을 잘하면 좋겠지만 모든 영역을 학습하기에는 지금의 지식이 너무 방대하기 때문이다.', +CURRENT_TIMESTAMP(), 0); + +INSERT INTO QUESTIONS (questionId, writer, title, contents, createdDate, countOfAnswer) VALUES +(7, 'javajigi', +'javascript 학습하기 좋은 라이브러리를 추천한다면...', +'이번 slipp에서 진행하는 5번째 스터디 주제가 trello의 아키텍처를 분석하고, trello에서 사용하는 기술을 학습하는 과정이다. 이 아이디어로 스터디를 진행하게 된 계기는 http://www.mimul.com/pebble/default/2014/03/17/1395028081476.html 글을 보고 스터디 주제로 진행해 보면 좋겠다는 생각을 했다. +이번 스터디를 진행하면서 가장 힘든 점이 javascript라 생각한다. 지금까지 javascript를 사용해 왔지만 깊이 있게 사용한 경험은 없기 때문에 이번 기회에 틈틈히 학습해 보려고 생각하고 있다. 단, 학습 방법을 지금까지와는 다르게 오픈 소스 라이브러리 중에서 괜찮은 놈을 하나 골라 소스 코드를 읽으면서 학습하는 방식으로 진행해 보려고 한다. 아무래도 책 한권을 처음부터 읽으면서 단순 무식하게 공부하기 보다는 이 방식이 좋지 않을까라는 기대 때문이다. javascript의 개발 스타일도 이해할 수 있기 때문에 좋은 접근 방법이라 생각한다. +혹시 javascript를 학습하기 좋은 라이브러리가 있을까? 소스 코드 라인 수가 많지 않으면서 소스 코드 스타일에서도 배울 점이 많은 그런 라이브러리면 딱 좋겠다.', +CURRENT_TIMESTAMP(), 2); + +INSERT INTO ANSWERS (writer, contents, createdDate, questionId) VALUES +('eungju', +'http://underscorejs.org/docs/underscore.html Underscore.js 강추합니다! +쓸일도 많고, 코드도 길지 않고, 자바스크립트의 언어나 기본 API를 보완하는 기능들이라 자바스크립트 이해에 도움이 됩니다. 무엇보다 라이브러리 자체가 아주 유용합니다.', +CURRENT_TIMESTAMP(), 7); + +INSERT INTO ANSWERS (writer, contents, createdDate, questionId) VALUES +('Hanghee Yi', +'언더스코어 강력 추천드려요. +다만 최신 버전을 공부하는 것보다는 0.10.0 버전부터 보는게 더 좋더군요. +코드의 변천사도 알 수 있고, 최적화되지 않은 코드들이 기능은 그대로 두고 최적화되어 가는 걸 보면 재미가 있습니다 :)', +CURRENT_TIMESTAMP(), 7); + +INSERT INTO QUESTIONS (questionId, writer, title, contents, createdDate, countOfAnswer) VALUES +(8, '자바지기', +'anonymous inner class는 final 변수에만 접근해야 하는 이유는?', +'오늘 자바 8에 추가된 람다와 관련한 내용을 읽다가 다음과 같이 내용이 있어 궁금증이 생겼다. +람다 표현식에서 변수를 변경하는 작업은 스레드에 안전하지 않다. - 가장 빨리 만나는 자바8 28페이지... +람다 표현식을 이전 버전의 anonymous inner class와 같은 용도로 판단했을 때 기존의 anonymous inner class에서도 final 변수에만 접근할 수 있었다. +지금까지 anonymous inner class에서 final 변수로 정의하는 이유가 현재 method의 Context가 anonymous inner class 인스턴스까지 확대되기 때문에 anonymous inner class 내에서 값을 변경할 경우 그에 따른 side effect가 생길 가능성이 많아 final로 정의하는 것으로 생각했다. +그런데 위 내용은 스레드에 안전하지 않기 때문에 람다 표현식에서 변수 값을 변경하는 것을 막는다고 이야기하고 있다. 왜 스레드에 안전하지 않은 것일까?', +CURRENT_TIMESTAMP(), 3); + +INSERT INTO ANSWERS (writer, contents, createdDate, questionId) VALUES +('jhindhal.jhang', +'Thread safe 랑 final은 관계가 있는거지만 다르게 봐야 하는게 아닌가? +굳이 lambda로 변수를 쓸 때 final 지정을 하지 않은 변수 더라도 final효과처럼 사용 한다면 (읽기만 한다 던지...) 사용 가능 하니 +Final 과 꼭 lambda를 연관 하지 말고 thread safe하게 프로그래밍 하기 위해 final(또는 final처럼)을 해야 한다는 의미가 아닐까? 생각 하는데...', +CURRENT_TIMESTAMP(), 8); + +INSERT INTO ANSWERS (writer, contents, createdDate, questionId) VALUES +('강우', +'저도 잘은 모르겠지만, 그냥 몇글자 적어볼께요. +일단 변수의 생명 주기랑, 값이 아닌 레퍼런스에 의한 부수효과는 무시하고, +쓰레드 관점에서만 볼때에, +간단히 생각하면, 서블릿에서 인스턴스 변수를 사용하는 것은 쓰레드에 안전할까요? 안전하지 않을까요? +저는 같은 맥락인거 같은데 ^^;; +아 그러고 보니 "안정"이라고 되어있네요. 저건 다른 의미인가.. ^^;;', +CURRENT_TIMESTAMP(), 8); + +INSERT INTO ANSWERS (writer, contents, createdDate, questionId) VALUES +('Toby Lee', +'람다식에서 사용되는 변수라면 람다식 내부에서 정의된 로컬 변수이거나 람다식이 선언된 외부의 변수를 참조하는 것일텐데, 전자라면 아무리 변경해도 문제될 이유가 없고, 후자는 변경 자체가 허용이 안될텐데. 이 설명이 무슨 뜻인지 이해가 안 됨.', +CURRENT_TIMESTAMP(), 8); \ No newline at end of file diff --git a/src/test/java/core/template/FreemarkerTest.java b/src/test/java/core/template/FreemarkerTest.java deleted file mode 100644 index 2963ddf22..000000000 --- a/src/test/java/core/template/FreemarkerTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package core.template; - -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Test; - -import freemarker.cache.ClassTemplateLoader; -import freemarker.template.Configuration; -import freemarker.template.Template; - -public class FreemarkerTest { - @Test - public void run() throws Exception { - Configuration cfg = new Configuration(Configuration.VERSION_2_3_23); - cfg.setTemplateLoader(new ClassTemplateLoader(this.getClass(), "/")); - Template template = cfg.getTemplate("templates/helloworld.ftl"); - - Map data = new HashMap(); - data.put("message", "Hello World!"); - - List countries = new ArrayList(); - countries.add("Korea"); - countries.add("United States"); - countries.add("Germany"); - countries.add("France"); - - data.put("countries", countries); - - Writer out = new OutputStreamWriter(System.out); - template.process(data, out); - out.flush(); - } -} diff --git a/src/main/java/next/WebServerLauncher.java b/src/test/java/next/WebServerLauncher.java similarity index 74% rename from src/main/java/next/WebServerLauncher.java rename to src/test/java/next/WebServerLauncher.java index e950b4a3d..38d28eed9 100644 --- a/src/main/java/next/WebServerLauncher.java +++ b/src/test/java/next/WebServerLauncher.java @@ -7,9 +7,9 @@ import org.slf4j.LoggerFactory; public class WebServerLauncher { - private static final Logger logger = LoggerFactory.getLogger(WebServerLauncher.class); - - public static void main(String[] args) throws Exception { + private static final Logger logger = LoggerFactory.getLogger(WebServerLauncher.class); + + public static void main(String[] args) throws Exception { String webappDirLocation = "webapp/"; Tomcat tomcat = new Tomcat(); tomcat.setPort(8080); @@ -17,7 +17,10 @@ public static void main(String[] args) throws Exception { tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath()); logger.info("configuring app with basedir: {}", new File("./" + webappDirLocation).getAbsolutePath()); + + + tomcat.start(); tomcat.getServer().await(); } -} +} \ No newline at end of file diff --git a/src/test/java/next/dao/UserDaoTest.java b/src/test/java/next/dao/UserDaoTest.java index 54ef162de..a68f75a8c 100644 --- a/src/test/java/next/dao/UserDaoTest.java +++ b/src/test/java/next/dao/UserDaoTest.java @@ -1,21 +1,44 @@ package next.dao; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import java.util.List; + +import org.junit.Before; import org.junit.Test; +import org.springframework.core.io.ClassPathResource; +import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; +import core.jdbc.ConnectionManager; import next.model.User; public class UserDaoTest { + @Before + public void setup() { + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); + populator.addScript(new ClassPathResource("jwp.sql")); + DatabasePopulatorUtils.execute(populator, ConnectionManager.getDataSource()); + } + + @Test + public void crud() throws Exception { + User expected = new User("userId", "password", "name", "javajigi@email.com"); + UserDao userDao = new UserDao(); + userDao.insert(expected); + User actual = userDao.findByUserId(expected.getUserId()); + assertEquals(expected, actual); + + expected.update(new User("userId", "password2", "name2", "sanjigi@email.com")); + userDao.update(expected); + actual = userDao.findByUserId(expected.getUserId()); + assertEquals(expected, actual); + } - @Test - public void crud() throws Exception { - User expected = new User("userId", "password", "name", "javajigi@email.com"); - UserDao userDao = new UserDao(); - userDao.insert(expected); - - User actual = userDao.findByUserId(expected.getUserId()); - assertEquals(expected, actual); - } - -} + @Test + public void findAll() throws Exception { + UserDao userDao = new UserDao(); + List users = userDao.findAll(); + assertEquals(1, users.size()); + } +} \ No newline at end of file diff --git a/sync_branch.sh b/sync_branch.sh new file mode 100755 index 000000000..3ab0ace04 --- /dev/null +++ b/sync_branch.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +REPOSITORY_DIR=~/jwp-workspace/cherry-pick/jwp-basic + +BRANCHES=("step0-getting-started" "step1-user-completed-no-database" "step2-user-with-mvc-framework" "step3-user-completed-database" "step4-qna-getting-started" "step5-qna-with-ajax" "step6-qna-with-mvc-framework" "step7-self-check" "step8-self-check-completed" "step9-mvc-framework-completed" "step10-di-getting-started" "step11-1st-di-framework" "step12-2nd-di-framework" "step13-3rd-di-framework" "step14-di-framework-completed" "step15-spring-orm-framework") +COMMIT_REVISION=a33b298 + +rm -rf $REPOSITORY_DIR + +git clone https://github.com/slipp/jwp-basic.git + +cd $REPOSITORY_DIR +pwd + +for BRANCH_NAME in "${BRANCHES[@]}"; do + git cherry-pick --quit + echo $BRANCH_NAME + git checkout -b $BRANCH_NAME origin/$BRANCH_NAME + git cherry-pick $COMMIT_REVISION + git push origin $BRANCH_NAME +done + +echo "Finished." \ No newline at end of file diff --git a/webapp/css/bootstrap.min.css b/webapp/css/bootstrap.min.css new file mode 100644 index 000000000..a9f35ceed --- /dev/null +++ b/webapp/css/bootstrap.min.css @@ -0,0 +1,5 @@ +/*! + * Bootstrap v3.2.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;width:100% \9;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;width:100% \9;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}mark,.mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#777;opacity:1}.form-control:-ms-input-placeholder{color:#777}.form-control::-webkit-input-placeholder{color:#777}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px;line-height:1.42857143 \0}input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;min-height:20px;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{position:absolute;margin-top:4px \9;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],input[type=radio].disabled,input[type=checkbox].disabled,fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm,.form-horizontal .form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg,.form-horizontal .form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:25px;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn:focus,.btn:active:focus,.btn.active:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn>input[type=radio],[data-toggle=buttons]>.btn>input[type=checkbox]{position:absolute;z-index:-1;filter:alpha(opacity=0);opacity:0}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#777}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#777}.navbar-inverse .navbar-nav>li>a{color:#777}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#777}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#777}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#428bca;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar[aria-valuenow="1"],.progress-bar[aria-valuenow="2"]{min-width:30px}.progress-bar[aria-valuenow="0"]{min-width:30px;color:#777;background-color:transparent;background-image:none;-webkit-box-shadow:none;box-shadow:none}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{color:#777;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#428bca}.panel-primary>.panel-heading .badge{color:#428bca;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate3d(0,-25%,0);-o-transform:translate3d(0,-25%,0);transform:translate3d(0,-25%,0)}.modal.in .modal-dialog{-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-size:12px;line-height:1.4;visibility:visible;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{display:table;content:" "}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed;-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} \ No newline at end of file diff --git a/webapp/css/styles.css b/webapp/css/styles.css new file mode 100644 index 000000000..e9980b373 --- /dev/null +++ b/webapp/css/styles.css @@ -0,0 +1,203 @@ +/* +A custom Bootstrap 3.2 'Google Plus style' theme +from http://bootply.com + +This CSS code should follow the 'bootstrap.css' +in your HTML file. + +license: MIT +author: bootply.com +*/ + +@import url(http://fonts.googleapis.com/css?family=Roboto:400); +body { + background-color:#e0e0e0; + -webkit-font-smoothing: antialiased; + font: normal 14px Roboto,arial,sans-serif; +} +.navbar-default {background-color:#f4f4f4;margin-top:50px;border-width:0;z-index:5;} +.navbar-default .navbar-nav > .active > a,.navbar-default .navbar-nav > li:hover > a {border:0 solid #4285f4;border-bottom-width:2px;font-weight:800;background-color:transparent;} +.navbar-default .dropdown-menu {background-color:#ffffff;} +.navbar-default .dropdown-menu li > a {padding-left:30px;} + +.header {background-color:#ffffff;border-width:0;} +.header .navbar-collapse {background-color:#ffffff;} +.btn,.form-control,.panel,.list-group,.well {border-radius:1px;box-shadow:0 0 0;} +.form-control {border-color:#d7d7d7;} +.btn-primary {border-color:transparent;} +.btn-primary,.label-primary,.list-group-item.active, .list-group-item.active:hover, .list-group-item.active:focus {background-color:#4285f4;} +.btn-plus {background-color:#ffffff;border-width:1px;border-color:#dddddd;box-shadow:1px 1px 0 #999999;border-radius:3px;color:#666666;text-shadow:0 0 1px #bbbbbb;} +.well,.panel {border-color:#d2d2d2;box-shadow:0 1px 0 #cfcfcf;border-radius:3px;} +.btn-success,.label-success,.progress-bar-success{background-color:#65b045;} +.btn-info,.label-info,.progress-bar-info{background-color:#a0c3ff;border-color:#a0c3ff;} +.btn-danger,.label-danger,.progress-bar-danger{background-color:#dd4b39;} +.btn-warning,.label-warning,.progress-bar-warning{background-color:#f4b400;color:#444444;} + +hr {border-color:#ececec;} +button { + outline: 0; +} +textarea { + resize: none; + outline: 0; +} +.panel .btn i,.btn span{ + color:#666666; +} +.panel .panel-heading { + background-color:#ffffff; + font-weight:700; + font-size:16px; + color:#262626; + border-color:#ffffff; +} +.panel .panel-heading a { + font-weight:400; + font-size:11px; +} +.panel .panel-default { + border-color:#cccccc; +} +.panel .panel-thumbnail { + padding:0; +} +.panel .img-circle { + width:50px; + height:50px; +} +.list-group-item:first-child,.list-group-item:last-child { + border-radius:0; +} +h3,h4,h5 { + border:0 solid #efefef; + border-bottom-width:1px; + padding-bottom:10px; +} +.modal-dialog { + width: 450px; +} +.modal-footer { + border-width:0; +} +.dropdown-menu { + background-color:#f4f4f4; + border-color:#f0f0f0; + border-radius:0; + margin-top:-1px; +} +/* end theme */ + +/* template layout*/ +#subnav { + position:fixed; + width:100%; +} + +@media (max-width: 768px) { + #subnav { + padding-top: 6px; + } +} + +#main { + padding-top:120px; +} + +.content-main { + position:relative; + padding:1em; + padding-right: 1em; + border-bottom:1px +} +.qna-header { + position:relative;padding:1em +} + +.article { + position:relative;padding:.6em 0 .8em +} + +.article-header{ + display:table;width:100%; + padding-bottom:.6em; + border-bottom:1px dashed #dadada +} +.article-header-text,.article-header-thumb{display:table-cell;vertical-align:middle} +.article-header-thumb{width:48px} +.article-author-thumb{width:40px;height:40px;-webkit-border-radius:3px;border-radius:3px} +.article-author-name{font-weight:bold;font-size:1.1em} +.article-author-fbgroup{display:inline-block;margin-left:.8em;font-style:italic;font-size:1em;color:#666;} +.article-author-fbgroup a{display:inline-block;color:#333;font-weight:bold;} +@media (max-width: 480px){.article-author-fbgroup a{overflow:hidden;max-width:8em;white-space:nowrap;-o-text-overflow:ellipsis;text-overflow:ellipsis} +}.article-header-time{display:block;font-size:.8em;color:#666;} +.article-header-time:hover{text-decoration:none;} +.article-header-time:hover .icon-link{color:#3aa} +.article-doc,.article-util{padding-left:48px;} +@media (max-width: 480px){.article-doc,.article-util,.article-doc,.article-util{padding-left:0} +}.article-doc img{max-width:100%} +.article-doc blockquote{margin-left:0;margin-right:0;border-left:4px solid #efefef;padding-left:.5em} +.article-util form{display:inline-block} +.article-util-list a,.article-util-list button{color:#999;padding:.4em;-webkit-border-radius:3px;border-radius:3px;border:0;background-color:transparent;white-space:nowrap;} +.article-util-list a:hover,.article-util-list button:hover{text-decoration:none;background-color:#dadada} +.article-util-list{margin:0;padding:0;list-style:none;color:#999;} +.article-util-list li{display:inline-block;} +.article-util-list li:before{content:'•';margin:0 -.4em} +.article-util-list li:first-child:before{display:none} +.article-util-list .btn-like-article{color:#44ca7f;} +.article-util-list .btn-like-article:hover{background-color:#e3f7ec} +.article-util-list .btn-dislike-article{color:#be6060;} +.article-util-list .btn-dislike-article:hover{background-color:#f9f1f1} +.article-util-list .link-answer-article{color:#5989b6;} +.article-util-list .link-answer-article:hover{background-color:#e7eef4} +.article-util-list .foundicon-thumb-up,.article-util-list .foundicon-thumb-down{position:relative;top:2px}.article-util form{display:inline-block} + +.qna-list h1 small { + font-size:.4em +} +.qna-list .list { + list-style:none; + margin:0; + padding:0; + border-top:1px solid #dadada; + font-size:14px; +} + +@media (max-width: 768px) { + .qna-list .list{ margin:0 -1em } +} + +.qna-list .list > li { + position:relative; + padding:1em; + padding-left:4em; + border-bottom:1px solid #eaeaea +} +.qna-list .list .main .subject{display:block;font-size:1.2em;line-height:1.4em;} +.qna-list .list .main .subject a{display:block;color:#000} +.qna-list .list .tags{font-size:.9em;color:#999} +.qna-list .list .tag:before{content:', '} +.qna-list .list .tag:first-child:before{content:''} +.qna-list .list .auth-info{margin-top:.8em;color:#999;} +.qna-list .list .auth-info .type{padding-right:.4em;} +@media (max-width: 480px){.qna-list .list .auth-info .type{display:none} +}.qna-list .list .auth-info .time{font-size:.9em} +.qna-list .list .reply{position:absolute;left:0;top:.8em;width:4em;text-align:center;} +.qna-list .list .reply .icon-reply{position:absolute;left:0;top:0;font-size:2em;color:#eee;} +@media (max-width: 979px){.qna-list .list .reply .icon-reply{left:.5em} +}.qna-list .list .reply .point{position:relative;z-index:1;color:#aaa;font-size:2em;line-height:2em;letter-spacing:-.2em} +.qna-header{border-bottom:4px solid #efefef} +.qna-title{margin-bottom:0} +.qna-nav{padding-bottom:.67em;} +.qna-nav .divider{padding-left:.4em;padding-right:.4em;font-size:.8em;color:#dadada} +.qna-comment .article{border-bottom:1px solid #dfdfdf;} +.qna-comment .article:first-child{border-top:1px solid #dfdfdf} +.qna-comment .article.best-article{border-bottom-width:4px;} +.qna-comment .article.best-article .btn-like-article{top:108px} +.qna-comment-slipp,.qna-comment-fb{margin-top:2em;border-top:4px solid #efefef} +.qna-comment-count{margin:0;padding:1em 0 0;font-weight:bold;font-size:1.2em} + +.qna-write { + padding-top: 1.4em; + padding-right: 2.5em; +} + diff --git a/webapp/favicon.ico b/webapp/favicon.ico new file mode 100644 index 000000000..5cd1446a1 Binary files /dev/null and b/webapp/favicon.ico differ diff --git a/webapp/fonts/glyphicons-halflings-regular.eot b/webapp/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 000000000..b93a4953f Binary files /dev/null and b/webapp/fonts/glyphicons-halflings-regular.eot differ diff --git a/webapp/fonts/glyphicons-halflings-regular.svg b/webapp/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 000000000..94fb5490a --- /dev/null +++ b/webapp/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/webapp/fonts/glyphicons-halflings-regular.ttf b/webapp/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 000000000..1413fc609 Binary files /dev/null and b/webapp/fonts/glyphicons-halflings-regular.ttf differ diff --git a/webapp/fonts/glyphicons-halflings-regular.woff b/webapp/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 000000000..9e612858f Binary files /dev/null and b/webapp/fonts/glyphicons-halflings-regular.woff differ diff --git a/webapp/fonts/glyphicons-halflings-regular.woff2 b/webapp/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 000000000..64539b54c Binary files /dev/null and b/webapp/fonts/glyphicons-halflings-regular.woff2 differ diff --git a/webapp/form.ftl b/webapp/form.ftl deleted file mode 100644 index 46882cc4d..000000000 --- a/webapp/form.ftl +++ /dev/null @@ -1,74 +0,0 @@ - - - - -SLiPP :: 회원가입 - - - - - - - - - - - -
-
-
-
- - -
- - - - - - - - - - - - - - - - - -
사용자 아이디
비밀번호
이름
이메일
- -
-
-
-
- - \ No newline at end of file diff --git a/webapp/home.ftl b/webapp/home.ftl deleted file mode 100644 index 75f92d9e4..000000000 --- a/webapp/home.ftl +++ /dev/null @@ -1,75 +0,0 @@ - - - - -SLiPP - - - - - - - - - - - -
-
-

SLiPP

-

Sustaninable Life, Programming, Programmer

-
-
- -
-
-
- - - - - - - - - - - - - - - - - - - -
사용자 아이디이름이메일
javajigi박재성javajigi@slipp.net수정
sanjigi산지기sanjigi@slipp.net수정
-
-
-
- - \ No newline at end of file diff --git a/webapp/home.jsp b/webapp/home.jsp new file mode 100644 index 000000000..560fbd5cf --- /dev/null +++ b/webapp/home.jsp @@ -0,0 +1,61 @@ +<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> + + + + + <%@ include file="/include/header.jspf" %> + + +<%@ include file="/include/navigation.jspf" %> + +
+
+
+
+
+
+ + +<%@ include file="/include/footer.jspf" %> + + \ No newline at end of file diff --git a/webapp/images/80-text.png b/webapp/images/80-text.png new file mode 100644 index 000000000..eed03ac6c Binary files /dev/null and b/webapp/images/80-text.png differ diff --git a/webapp/include/footer.jspf b/webapp/include/footer.jspf new file mode 100644 index 000000000..f6dc0e95a --- /dev/null +++ b/webapp/include/footer.jspf @@ -0,0 +1,5 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + diff --git a/webapp/include/header.jspf b/webapp/include/header.jspf new file mode 100644 index 000000000..9e4fd6a15 --- /dev/null +++ b/webapp/include/header.jspf @@ -0,0 +1,10 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + +SLiPP Java Web Programming + + + + \ No newline at end of file diff --git a/webapp/include/navigation.jspf b/webapp/include/navigation.jspf new file mode 100644 index 000000000..24eef01f8 --- /dev/null +++ b/webapp/include/navigation.jspf @@ -0,0 +1,67 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + + diff --git a/webapp/js/bootstrap.min.js b/webapp/js/bootstrap.min.js new file mode 100644 index 000000000..7c1561a8b --- /dev/null +++ b/webapp/js/bootstrap.min.js @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.2.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.2.0",d.prototype.close=function(b){function c(){f.detach().trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",c).emulateTransitionEnd(150):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.2.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),d[e](null==f[b]?this.options[b]:f[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b).on("keydown.bs.carousel",a.proxy(this.keydown,this)),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.2.0",c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.to=function(b){var c=this,d=this.getItemIndex(this.$active=this.$element.find(".item.active"));return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=e[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:g});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,f&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(e)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:g});return a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one("bsTransitionEnd",function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger(m)),f&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(b=!b),e||d.data("bs.collapse",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};c.VERSION="3.2.0",c.DEFAULTS={toggle:!0},c.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},c.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var c=a.Event("show.bs.collapse");if(this.$element.trigger(c),!c.isDefaultPrevented()){var d=this.$parent&&this.$parent.find("> .panel > .in");if(d&&d.length){var e=d.data("bs.collapse");if(e&&e.transitioning)return;b.call(d,"hide"),e||d.data("bs.collapse",null)}var f=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[f](0),this.transitioning=1;var g=function(){this.$element.removeClass("collapsing").addClass("collapse in")[f](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return g.call(this);var h=a.camelCase(["scroll",f].join("-"));this.$element.one("bsTransitionEnd",a.proxy(g,this)).emulateTransitionEnd(350)[f](this.$element[0][h])}}},c.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},c.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var d=a.fn.collapse;a.fn.collapse=b,a.fn.collapse.Constructor=c,a.fn.collapse.noConflict=function(){return a.fn.collapse=d,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(c){var d,e=a(this),f=e.attr("data-target")||c.preventDefault()||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),g=a(f),h=g.data("bs.collapse"),i=h?"toggle":e.data(),j=e.attr("data-parent"),k=j&&a(j);h&&h.transitioning||(k&&k.find('[data-toggle="collapse"][data-parent="'+j+'"]').not(e).addClass("collapsed"),e[g.hasClass("in")?"addClass":"removeClass"]("collapsed")),b.call(g,i)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.2.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('