├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .flowconfig ├── .gitignore ├── .jscsrc ├── .npmrc ├── .nvmrc ├── .travis.yml ├── LICENSE ├── README.md ├── bin └── buildHtml.js ├── config ├── flow │ ├── definitions │ │ └── react.js │ └── flow-typed │ │ ├── README.md │ │ └── npm │ │ ├── enzyme_v2.x.x.js │ │ ├── react-redux_v4.x.x.js │ │ └── redux_v3.x.x.js ├── webpack.config.base.js ├── webpack.config.development.js └── webpack.config.production.js ├── dev-server.js ├── package.json ├── src └── client │ ├── assets │ ├── images │ │ └── favicon.ico │ ├── index.html │ ├── javascripts │ │ ├── app │ │ │ ├── App.js │ │ │ ├── DevTools.js │ │ │ ├── Root.js │ │ │ ├── config.js │ │ │ ├── index.js │ │ │ ├── reducer.js │ │ │ ├── routes.js │ │ │ └── store │ │ │ │ ├── configureStore.development.js │ │ │ │ ├── configureStore.js │ │ │ │ └── configureStore.production.js │ │ ├── components │ │ │ └── NotFound │ │ │ │ ├── NotFound.js │ │ │ │ ├── NotFound.spec.js │ │ │ │ └── index.js │ │ ├── features │ │ │ └── friends │ │ │ │ ├── components │ │ │ │ ├── AddFriendInput │ │ │ │ │ ├── AddFriendInput.js │ │ │ │ │ ├── AddFriendInput.scss │ │ │ │ │ └── index.js │ │ │ │ ├── FriendList │ │ │ │ │ ├── FriendList.js │ │ │ │ │ ├── FriendList.scss │ │ │ │ │ └── index.js │ │ │ │ ├── FriendListApp.scss │ │ │ │ ├── FriendListItem │ │ │ │ │ ├── FriendListItem.js │ │ │ │ │ ├── FriendListItem.scss │ │ │ │ │ ├── fonts │ │ │ │ │ │ └── opensans-regular-webfont.woff │ │ │ │ │ ├── images │ │ │ │ │ │ └── icon-user.png │ │ │ │ │ └── index.js │ │ │ │ ├── FriendsLayout.js │ │ │ │ └── FriendsView.js │ │ │ │ ├── friends.js │ │ │ │ └── index.js │ │ ├── models │ │ │ └── friends.js │ │ └── utils │ │ │ └── .gitkeep │ └── styles │ │ ├── bootstrap.min.css │ │ └── styles.scss │ └── scripts │ ├── development.js │ └── production.js └── test ├── e2e └── .gitkeep └── unit ├── actions └── FriendsActionsSpec.js ├── containers └── FriendListAppSpec.js ├── cssNullCompiler.js └── testHelper.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["es2015", { "modules": false }], 4 | "react", 5 | "stage-0" 6 | ], 7 | "plugins": [ 8 | "transform-runtime", 9 | "transform-decorators-legacy", 10 | "transform-flow-strip-types", 11 | "react-hot-loader/babel" 12 | ], 13 | "env": { 14 | "production": { 15 | "plugins": ["transform-react-remove-prop-types", "transform-react-constant-elements"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain 2 | # consistent coding styles between different editors and IDEs. 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | insert_final_newline = false 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | config/flow 2 | dev-server.js 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "parser": "babel-eslint", 3 | 4 | "extends": ["eslint:recommended", "plugin:react/recommended"], 5 | 6 | "parserOptions": { 7 | "ecmaVersion": 6, 8 | "sourceType": "module", 9 | "ecmaFeatures": { 10 | "impliedStrict": true, 11 | "jsx": true, 12 | "experimentalObjectRestSpread": true 13 | } 14 | }, 15 | 16 | "env": { 17 | "browser": true, 18 | "node": true, 19 | "es6": true, 20 | "mocha": true 21 | }, 22 | 23 | "plugins": [ 24 | "react", 25 | "flowtype" 26 | ], 27 | 28 | "globals": { 29 | "define": true 30 | }, 31 | 32 | "settings": { 33 | "flowtype": { 34 | "onlyFilesWithFlowAnnotation": true 35 | } 36 | }, 37 | 38 | "rules": { 39 | "strict": ["error", "global"], 40 | "no-unused-vars": ["error", { "vars": "all", "args": "all", "caughtErrors": "none" }], 41 | "no-console": ["error", { allow: ["warn", "error"] }], 42 | "camelcase": ["error", { "properties": "always" }], 43 | "consistent-return": "error", 44 | "arrow-spacing": "error", 45 | "arrow-parens": ["error", "always"], 46 | "arrow-body-style": ["error", "as-needed"], 47 | "semi": ["error", "always"], 48 | "no-confusing-arrow": ["error", { "allowParens": false }], 49 | "no-constant-condition": "error", 50 | "no-labels": "error", 51 | "no-multiple-empty-lines": ["error", { max: 1, maxEOF: 1 }], 52 | "func-style": "off", 53 | 54 | // ESLint-plugin-React 55 | // https://github.com/yannickcr/eslint-plugin-react 56 | 57 | "react/forbid-prop-types": ["error", { "forbid": ["any"] }], 58 | "react/jsx-boolean-value": "warn", 59 | "react/jsx-closing-bracket-location": "off", 60 | "react/jsx-curly-spacing": "warn", 61 | "react/jsx-indent-props": "off", 62 | "react/jsx-key": "warn", 63 | "react/jsx-max-props-per-line": "off", 64 | "react/jsx-no-bind": "off", 65 | "react/jsx-no-literals": "off", 66 | "react/jsx-pascal-case": "warn", 67 | "react/jsx-sort-prop-types": "off", 68 | "react/jsx-sort-props": "off", 69 | "react/jsx-wrap-multilines": "error", 70 | "react/no-multi-comp": "warn", 71 | "react/no-set-state": "off", 72 | "react/prefer-es6-class": "warn", 73 | "react/self-closing-comp": "warn", 74 | "react/sort-comp": "warn", 75 | "react/sort-prop-types": "warn", 76 | 77 | // ESLint-plugin-Flowtype 78 | // https://github.com/gajus/eslint-plugin-flowtype#configuration 79 | 80 | // marks Flow type identifiers as defined 81 | 'flowtype/define-flow-type': "error", 82 | // requires that all function parameters have type annotations 83 | 'flowtype/require-parameter-type': "off", 84 | // requires that functions have return type annotation 85 | 'flowtype/require-return-type': "off", 86 | // makes sure that files have a valid @flow annotation 87 | 'flowtype/require-valid-file-annotation': "error", 88 | // enforces consistent spacing after the type annotation colon 89 | 'flowtype/space-after-type-colon': ["error", 'always'], 90 | // enforces consistent spacing before the type annotation colon 91 | 'flowtype/space-before-type-colon': ["error", 'never'], 92 | // enforces a consistent naming pattern for type aliases 93 | 'flowtype/type-id-match': "off", 94 | // marks Flow type alias declarations as used 95 | 'flowtype/use-flow-type': "off", 96 | // checks for simple Flow syntax errors 97 | 'flowtype/valid-syntax': "error" 98 | } 99 | }; 100 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [include] 2 | 3 | [ignore] 4 | /build/.* 5 | 6 | # Including these files causes issues 7 | .*/node_modules/fbjs/.* 8 | .*/node_modules/jsonlint/.* 9 | 10 | [libs] 11 | # Official "flow-typed" repository definitions 12 | config/flow/flow-typed/npm 13 | 14 | # Custom definitions 15 | config/flow/definitions/ 16 | 17 | [options] 18 | module.use_strict=true 19 | 20 | esproposal.class_static_fields=enable 21 | esproposal.class_instance_fields=enable 22 | 23 | [version] 24 | ^0.31 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | *.iml 4 | node_modules 5 | build 6 | *.log* 7 | npm-debug.log 8 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "airbnb", 3 | "disallowCommaBeforeLineBreak": false, 4 | "requireTrailingComma": false, 5 | "maximumLineLength": 120 6 | } 7 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact=true 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v6.4.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | 5 | node_js: 6 | - 7 7 | - 6 8 | - 4 9 | 10 | cache: 11 | directories: 12 | - node_modules 13 | 14 | install: 15 | - npm i -g npm@latest 16 | - npm install 17 | 18 | script: 19 | - npm run test 20 | - npm run lint 21 | - npm run jscs 22 | - npm run prebuild 23 | - npm run build 24 | - npm run build:html 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Nick S. Plekhanov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React + Redux w/ ES6 Starter Project 2 | 3 | **:tada: A Completely updated version of my initial boilerplate :rocket:** 4 | 5 | *Note: If you still want to use a previous version, please checkout `old-original-structure` branch.* 6 | 7 | A boilerplate using the power and simplicity of React, Redux, Webpack 2 + HMR, and ES6 + JSX via Babel. Includes `Webpack's Tree Shaking` configuration. It's suitable for scalable applications and organized using the custom variation of [the Ducks pattern](https://github.com/nicksp/ducks-modular-redux) — approach when each module's entry file (`feature-name.js`) contains all of its related constants, actions/action creators, selectors and its reducer. 8 | 9 | The provided boilerplate is powered by the following technology stack: 10 | 11 | - [x] [React](https://facebook.github.io/react/) and [JSX](https://facebook.github.io/jsx/) — a virtual DOM JavaScript library for rendering UI. It's about rendering view as a function of state, making JavaScript-driven UI declarative the way HTML is declarative. 12 | - [x] [Redux](http://redux.js.org/) — an incredibly simple way of modelling your data app state, with great community support 13 | - [x] [Webpack 2](https://gist.github.com/sokra/27b24881210b56bbaff7) and [dev middleware](https://github.com/webpack/webpack-dev-middleware) — client-side module builder and module loader 14 | - [x] [React Hot Loader 3](https://github.com/gaearon/react-hot-boilerplate/pull/61) — combines the best of React Hot Loader and React Transform and fixes some [long-standing issues](https://twitter.com/dan_abramov/status/722040946075045888) 15 | - [ ] [React Router v3](https://github.com/reactjs/react-router/blob/next/CHANGES.md) — to allow [dynamic routing](https://github.com/reactjs/react-router/blob/master/docs/guides/DynamicRouting.md) 16 | - [x] [React Router Redux](https://github.com/reactjs/react-router-redux) — simple bindings to keep React Router and Redux in sync 17 | - [x] [Reselect](https://github.com/reactjs/reselect) — provides a way to access Redux state in components and build composable selectors that are automatically memoized 18 | - [x] [Flow](https://flowtype.org/docs/getting-started.html) — static type checker for JavaScript aimed at catching common bugs in JavaScript programs. The flow type annotations get ripped out of the source by the webpack build step. You have no obligation to use flow within your code and can even uninstall the dependency (`flow-bin`) without breaking the project. 19 | - [x] [npm](https://www.npmjs.com/) — package manager and task runner 20 | - [x] [Babel 6](http://babeljs.io/) — transpiler from ES6 / JSX to ES5 21 | - [x] [PostCSS](http://postcss.org/) — ecosystem of custom plugins and tools aimed at transforming extended syntaxes and features into modern, browser-friendly CSS 22 | - [x] [CSS Modules](https://github.com/css-modules/css-modules) — guarantee that all the styles for a single component, designed to fix the problem of the global scope in CSS 23 | - [x] [Redux DevTools](https://github.com/gaearon/redux-devtools) — a live-editing environment for your Redux apps (and as a [browser extension](https://github.com/zalmoxisus/redux-devtools-extension)) 24 | - [x] [webpack-dashboard](https://github.com/FormidableLabs/webpack-dashboard) — CLI dashboard for your Webpack dev server 25 | - [ ] [React Intl](https://github.com/yahoo/react-intl) — internationalization for React projects 26 | - [x] [ESLint](http://eslint.org/docs/user-guide/configuring) — reporter for syntax and style issues 27 | - [x] [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) & [eslint-plugin-flowtype](https://github.com/gajus/eslint-plugin-flowtype) — additional React/Flow type specific linting rules for ESLint 28 | - [x] [Sass](http://sass-lang.com/) — compiler of CSS styles with variables, mixins, and more 29 | - [x] [Mocha](https://mochajs.org/) — well-known and flexible test framework that you can use to run your JavaScript tests on the server or in the browser 30 | - [ ] [Enzyme](http://airbnb.io/enzyme/) — makes unit testing React components an absolute pleasure 31 | - [x] [Chai](http://chaijs.com/) — BDD assertion library that works along with `Mocha` 32 | - [x] [Sentry](https://sentry.io/) — real-time error tracking for your app 33 | 34 | ## Getting Started 35 | 36 | ### Prerequisites 37 | 38 | Support for Node.js > 5 39 | 40 | ### Installation 41 | 42 | ```sh 43 | $ git clone https://github.com/nicksp/redux-webpack-es6-boilerplate.git app-name 44 | $ cd app-name 45 | $ npm install 46 | ``` 47 | 48 | ### White Label It 49 | 50 | - Update name, description, author, repository in `package.json` 51 | - Update app title in [`src/client/assets/index.html`](src/client/assets/index.html) 52 | 53 | 54 | ## Development 55 | 56 | There are two ways in which you can build and run the web app: 57 | 58 | * Build once for (ready for ***Production***): 59 | * `$ npm run build` 60 | * `$ npm run build:serve` 61 | 62 | The last command will boot up HTTP server on `3003` port and serve `build/client` directory in a default browser 63 | 64 | * Hot reloading via webpack middlewares: 65 | * `$ npm start` 66 | * Point your browser to http://localhost:3000/, page hot reloads automatically when there are changes 67 | 68 | ## Testing 69 | 70 | **(TBD)** 71 | 72 | To execute all unit tests, use: 73 | 74 | ```sh 75 | $ npm run test 76 | ``` 77 | 78 | To run unit tests continuously during development (watch tests), use: 79 | 80 | ```sh 81 | $ npm run test:watch 82 | ``` 83 | 84 | ## Expose App on Your Local Dev Machine 85 | 86 | Assign yourself a unique publicly accessible url that will proxy all requests to your locally running webserver. 87 | 88 | ```sh 89 | $ npm install -g localtunnel 90 | $ npm start 91 | $ npm run tunnel # run in a new tab 92 | ``` 93 | 94 | You will receive a url, for example `https://tbst.localtunnel.me`, that you can share with anyone for as long as your local instance of `lt` remains active. Any requests will be routed to your local service at the specified port. 95 | 96 | ## Error Tracking and Insights with Sentry 97 | 98 | In order to get info on errors that happened in production, we integrate [Sentry](https://sentry.io/for/javascript/) into our application to track errors and get context on what happened. 99 | 100 | To use it on your side, configure it first: 101 | 102 | * Create account at [https://sentry.io/signup/](https://sentry.io/signup/) 103 | * Add new project for your app on Sentry website 104 | * In `/src/client/assets/javascripts/app/config.js` file assign `SENTRY_KEY` and `SENTRY_APP` constants values that you got after adding a new project 105 | * Don't forget to define `Allowed Domains` section under your `Project Settings` on Sentry website to track errors from required domains 106 | 107 | ## Debugging 108 | 109 | For debugging purposes please use: 110 | - [Redux DevTools 111 | ](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) plugin for Chrome to simplify debugging React apps. 112 | - [React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi) 113 | 114 | ## FAQ 115 | 116 | ### What's this for? 117 | 118 | This starter kit implements best practices like testing (`unit testing`), minification, bundling, and so on. It saves you from the long, painful process of wiring it all together into an automated dev environment and build process. 119 | 120 | ### What's happening under the hood when I run `npm start`? 121 | 122 | Webpack serves your app in memory when you run `npm start`. No physical files are written. However, the web root is `/src`, so you can reference files under /src in index.html. When the app is built using `npm run build`, physical files are written to `/build` folder and the app is served from `/build`. 123 | 124 | ### How is Sass being processed? 125 | 126 | We're handling it differently in DEV vs PROD. 127 | 128 | When you run `npm start`: 129 | 130 | 1. The sass-loader compiles Sass into CSS 131 | 2. Webpack bundles the compiled CSS into app.js. Sounds weird, but it works! 132 | 3. app.js contains code that loads styles into the <head> section of index.html via JavaScript. This is why there is no stylesheet reference in index.html. In fact, if you disable JavaScript in your browser, you'll see the styles don't load either. 133 | 134 | The approach above supports hot reloading, which is great for development. However, it also create a flash of unstyled content on load because you have to wait for the JavaScript to parse and load styles before they're applied. So for the production build, we use a different approach: 135 | 136 | When you run `npm run build`: 137 | 138 | 1. The sass-loader compiles Sass into CSS 139 | 2. The [extract-text-webpack-plugin](https://github.com/webpack/extract-text-webpack-plugin) extracts the compiled Sass into app.css 140 | 3. buildHtml.js adds a reference to the stylesheet to the head of index.html. 141 | 142 | ### How do I deploy this? 143 | 144 | `npm run build`. This will prepare and build the project for production use. It does the following: 145 | 146 | - Minifies all JS and CSS 147 | - Inline base64 URLs for images and fonts if their size is less than specified limit 148 | - Sets NODE_ENV to `production` so that React is built in production mode 149 | - Places the resulting built project files into `/build` directory. (This is the folder you'll expose to the world). 150 | 151 | ## TODO 152 | 153 | - [ ] Watch `index.html` for changes 154 | - [ ] Setup test environment for React components using Enzyme, Mocha and Karma 155 | - [ ] Add support for React Intl 156 | - [ ] Add support for dynamic routing (`code splitting`) 157 | - [ ] Update `FAQ` section to reflect latest greatest changes 158 | - [ ] Add more Flow type annotations incrementally to allow Flow to validate more code, and gradually increase Flow’s coverage of the codebase 159 | - [ ] Integrate Material Design or Bootstrap 160 | - [ ] Check if PostCSS integration works 161 | - [ ] Apply more best practices to how code is organized and written 162 | - [ ] Add section about available `npm` scripts 163 | - [ ] Any more ideas? 164 | 165 | ## License 166 | 167 | [MIT License](https://nicksp.mit-license.org/), 2016 168 | 169 | Brought to you by Nick S. Plekhanov 170 | -------------------------------------------------------------------------------- /bin/buildHtml.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This script copies src/client/assets/index.html into build/client/index.html 3 | * This is useful for our built production code. 4 | */ 5 | 6 | /*eslint-disable no-console */ 7 | 8 | const fs = require('fs'); 9 | const colors = require('colors'); 10 | const cheerio = require('cheerio'); 11 | 12 | fs.readFile('src/client/assets/index.html', 'utf8', (err, markup) => { 13 | if (err) { 14 | return console.error(err); 15 | } 16 | 17 | const $ = cheerio.load(markup); 18 | 19 | $('head').append(''); 20 | 21 | fs.writeFile('build/client/index.html', $.html(), 'utf8', (err) => { 22 | if (err) { 23 | return console.error(err); 24 | } 25 | }); 26 | 27 | console.log('index.html written to /build/client'.green); 28 | }); 29 | -------------------------------------------------------------------------------- /config/flow/definitions/react.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | // Note: we already have the definitions from 4 | // https://github.com/facebook/flow/blob/master/lib/react.js 5 | // so the below are merely helpful extensions 6 | 7 | import React from 'react'; 8 | 9 | declare type $React$Element = React.Element<*>; 10 | 11 | declare type $React$Node = string | number | $React$Element | Array<$React$Element>; 12 | 13 | declare type $React$Child = $React$Node | boolean | void | null; 14 | 15 | declare type $React$Children = $React$Child | Array<$React$Children>; 16 | -------------------------------------------------------------------------------- /config/flow/flow-typed/README.md: -------------------------------------------------------------------------------- 1 | If you are working with **third-party** modules, you will need to install type definitions before you can import them. The best way to get third-party type definitions is using [`flow-typed`](https://github.com/flowtype/flow-typed). 2 | 3 | ```sh 4 | $ npm install -g flow-typed 5 | ``` 6 | 7 | You can search and install type definitions using this binary (`flow-typed` cli) from inside `/config/flow` directory. 8 | 9 | ```sh 10 | $ flow-typed search redux 11 | $ flow-typed install -f 0.31 redux 12 | ``` 13 | -------------------------------------------------------------------------------- /config/flow/flow-typed/npm/enzyme_v2.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: a0675fccfa57a0b329975d30430b8b96 2 | // flow-typed version: f622abbe3e/enzyme_v2.x.x/flow_>=v0.23.x 3 | 4 | declare module 'enzyme' { 5 | declare type PredicateFunction = (wrapper: Wrapper) => boolean; 6 | declare type NodeOrNodes = React$Element | Array>; 7 | declare class Wrapper> { 8 | find(selector: string): ReturnClass; 9 | findWhere(predicate: PredicateFunction): ReturnClass; 10 | filter(selector: string): ReturnClass; 11 | filterWhere(predicate: PredicateFunction): ReturnClass; 12 | contains(nodeOrNodes: NodeOrNodes): boolean; 13 | equals(node: React$Element): boolean; 14 | hasClass(className: string): boolean; 15 | is(selector: string): boolean; 16 | not(selector: string): boolean; 17 | children(): ReturnClass; 18 | childAt(index: number): ReturnClass; 19 | type(): string | Function; 20 | text(): string; 21 | html(): string; 22 | update(): this; 23 | } 24 | declare class ReactWrapper extends Wrapper {} 25 | declare class ShallowWrapper extends Wrapper { 26 | shallow(options?: { context?: Object }): ShallowWrapper; 27 | } 28 | declare class CheerioWrapper extends Wrapper {} 29 | declare function shallow(node: React$Element, options?: { context?: Object }): ShallowWrapper; 30 | declare function mount(node: React$Element, options?: { context?: Object, attachTo?: HTMLElement, childContextTypes?: Object }): ReactWrapper; 31 | declare function render(node: React$Element, options?: { context?: Object }): CheerioWrapper; 32 | } 33 | -------------------------------------------------------------------------------- /config/flow/flow-typed/npm/react-redux_v4.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 708adb773a9ad8abf8edbbb240cc59b4 2 | // flow-typed version: f86b0822d6/react-redux_v4.x.x/flow_>=v0.30.x 3 | 4 | /* @flow */ 5 | type ConnectAll = , SP, DP, Dispatch: Function>( 6 | mapStateToProps: (state: Object, ownProps: $Diff<$Diff<$Diff, SP>, D>) => SP, 7 | mapDispatchToProps: (dispatch: Dispatch, ownProps: $Diff<$Diff<$Diff, SP>, D>) => DP, 8 | mergeProps: null | void, 9 | options?: {pure?: boolean, withRef?: boolean} 10 | ) => (component: Class) => Class, SP>, S>>; 11 | 12 | type ConnectAllStateless = ( 13 | mapStateToProps: (state: Object, ownProps: $Diff<$Diff, SP>) => SP, 14 | mapDispatchToProps: (dispatch: Dispatch, ownProps: $Diff<$Diff, SP>) => DP, 15 | mergeProps: null | void, 16 | options?: {pure?: boolean, withRef?: boolean} 17 | ) => (component: (props: P) => any) => Class, SP>, void>>; 18 | 19 | type ConnectMerged = , SP, DP, MP, Dispatch: Function>( 20 | mapStateToProps: (state: Object, ownProps: $Diff<$Diff, D>) => SP, 21 | mapDispatchToProps: (dispatch: Dispatch, ownProps: $Diff<$Diff, D>) => DP, 22 | mergeProps: (stateProps: SP, dispatchProps: DP, ownProps: $Diff<$Diff, D>) => MP, 23 | options?: {pure?: boolean, withRef?: boolean} 24 | ) => (component: Class) => Class, S>>; 25 | 26 | type ConnectMergedStateless = ( 27 | mapStateToProps: (state: Object, ownProps: $Diff) => SP, 28 | mapDispatchToProps: (dispatch: Dispatch, ownProps: $Diff) => DP, 29 | mergeProps: (stateProps: SP, dispatchProps: DP, ownProps: $Diff) => MP, 30 | options?: {pure?: boolean, withRef?: boolean} 31 | ) => (component: (props: P) => any) => Class, void>>; 32 | 33 | type ConnectNoState = , DP, Dispatch: Function>( 34 | mapStateToProps: null | void, 35 | mapDispatchToProps: (dispatch: Dispatch, ownProps: $Diff<$Diff, D>) => DP, 36 | mergeProps: null | void, 37 | options?: {pure?: boolean, withRef?: boolean} 38 | ) => (component: Class) => Class, S>>; 39 | 40 | type ConnectNoStateStatless = ( 41 | mapStateToProps: null | void, 42 | mapDispatchToProps: (dispatch: Dispatch, ownProps: $Diff) => DP, 43 | mergeProps: null | void, 44 | options?: {pure?: boolean, withRef?: boolean} 45 | ) => (component: (props: P) => any) => Class, void>>; 46 | 47 | type ConnectDispatch = , SP, Dispatch: Function>( 48 | mapStateToProps: (state: Object, ownProps: $Diff<$Diff<$Diff, SP>, D>) => SP, 49 | mapDispatchToProps: null | void, 50 | mergeProps: null | void, 51 | options?: {pure?: boolean, withRef?: boolean} 52 | ) => (component: Class) => Class, SP>, S>>; 53 | 54 | type ConnectDispatchStateless = ( 55 | mapStateToProps: (state: Object, ownProps: $Diff<$Diff, SP>) => SP, 56 | mapDispatchToProps: null | void, 57 | mergeProps: null | void, 58 | options?: {pure?: boolean, withRef?: boolean} 59 | ) => (component: (props: P) => any) => Class, SP>, void>>; 60 | 61 | type ConnectDefault = , Dispatch: Function>() => 62 | (component: Class) => Class, S>>; 63 | 64 | type ConnectDefaultStateless = () => 65 |

(component: (props: P) => any) => Class, void>>; 66 | 67 | declare module 'react-redux' { 68 | declare var exports: { 69 | connect: ConnectAll 70 | & ConnectAllStateless 71 | & ConnectMerged 72 | & ConnectMergedStateless 73 | & ConnectNoState 74 | & ConnectNoStateStatless 75 | & ConnectDispatch 76 | & ConnectDispatchStateless 77 | & ConnectDefault 78 | & ConnectDefaultStateless; 79 | Provider: ReactClass<{store: Object, children?: any}>; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /config/flow/flow-typed/npm/redux_v3.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 3b60d0484a561f2e7c43ac2a5eb28d87 2 | // flow-typed version: f622abbe3e/redux_v3.x.x/flow_>=v0.23.x 3 | 4 | declare module 'redux' { 5 | declare type State = any; 6 | declare type Action = Object; 7 | declare type AsyncAction = any; 8 | declare type Reducer = (state: S, action: A) => S; 9 | declare type BaseDispatch = (a: Action) => Action; 10 | declare type Dispatch = (a: Action | AsyncAction) => any; 11 | declare type ActionCreator = (...args: any) => Action | AsyncAction; 12 | declare type MiddlewareAPI = { dispatch: Dispatch, getState: () => State }; 13 | declare type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch; 14 | declare type Store = { 15 | dispatch: Dispatch, 16 | getState: () => State, 17 | subscribe: (listener: () => void) => () => void, 18 | replaceReducer: (reducer: Reducer) => void 19 | }; 20 | declare type StoreCreator = (reducer: Reducer, initialState: ?State) => Store; 21 | declare type StoreEnhancer = (next: StoreCreator) => StoreCreator; 22 | declare type ActionCreatorOrObjectOfACs = ActionCreator | { [key: string]: ActionCreator }; 23 | declare type Reducers = { [key: string]: Reducer }; 24 | declare class Redux { 25 | bindActionCreators(actionCreators: actionCreators, dispatch: Dispatch): actionCreators; 26 | combineReducers(reducers: Reducers): Reducer; 27 | createStore(reducer: Reducer, initialState?: State, enhancer?: StoreEnhancer): Store; 28 | applyMiddleware(...middlewares: Array): StoreEnhancer; 29 | compose(...functions: Array): Function; 30 | } 31 | declare var exports: Redux; 32 | } 33 | -------------------------------------------------------------------------------- /config/webpack.config.base.js: -------------------------------------------------------------------------------- 1 | // Common Webpack configuration used by webpack.config.development and webpack.config.production 2 | 3 | const path = require('path'); 4 | const webpack = require('webpack'); 5 | const autoprefixer = require('autoprefixer'); 6 | 7 | module.exports = { 8 | output: { 9 | filename: 'js/[name].js', 10 | path: path.resolve(__dirname, '../build/client'), 11 | publicPath: '/' 12 | }, 13 | resolve: { 14 | modules: [ 15 | path.join(__dirname, '../src/client/scripts'), 16 | path.join(__dirname, '../src/client/assets'), 17 | path.join(__dirname, '../src/client/assets/javascripts'), 18 | 'node_modules' 19 | ], 20 | alias: { 21 | models: path.join(__dirname, '../src/client/assets/javascripts/models') 22 | }, 23 | extensions: ['.js', '.jsx', '.json', '.scss'] 24 | }, 25 | plugins: [ 26 | new webpack.ProvidePlugin({ 27 | 'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch' // fetch API 28 | }), 29 | // Shared code 30 | new webpack.optimize.CommonsChunkPlugin({ 31 | name: 'vendor', 32 | filename: 'js/vendor.bundle.js', 33 | minChunks: Infinity 34 | }) 35 | ], 36 | module: { 37 | loaders: [ 38 | // JavaScript / ES6 39 | { 40 | test: /\.jsx?$/, 41 | include: path.resolve(__dirname, '../src/client/assets/javascripts'), 42 | loader: 'babel' 43 | }, 44 | // Images 45 | // Inline base64 URLs for <=8k images, direct URLs for the rest 46 | { 47 | test: /\.(png|jpg|jpeg|gif|svg)$/, 48 | loader: 'url', 49 | query: { 50 | limit: 8192, 51 | name: 'images/[name].[ext]?[hash]' 52 | } 53 | }, 54 | // Fonts 55 | { 56 | test: /\.(woff|woff2|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/, 57 | loader: 'url', 58 | query: { 59 | limit: 8192, 60 | name: 'fonts/[name].[ext]?[hash]' 61 | } 62 | } 63 | ] 64 | }, 65 | postcss: function () { 66 | return [ 67 | autoprefixer({ 68 | browsers: ['last 2 versions'] 69 | }) 70 | ]; 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /config/webpack.config.development.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge'); 2 | const webpack = require('webpack'); 3 | const config = require('./webpack.config.base'); 4 | const path = require('path'); 5 | 6 | 7 | const GLOBALS = { 8 | 'process.env': { 9 | 'NODE_ENV': JSON.stringify('development') 10 | }, 11 | __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'true')) 12 | }; 13 | 14 | module.exports = merge(config, { 15 | debug: true, 16 | cache: true, 17 | devtool: 'cheap-module-eval-source-map', 18 | entry: { 19 | application: [ 20 | 'webpack-hot-middleware/client', 21 | 'react-hot-loader/patch', 22 | 'development' 23 | ], 24 | vendor: ['react', 'react-dom', 'react-redux', 'react-router', 'react-router-redux', 'redux'] 25 | }, 26 | plugins: [ 27 | new webpack.HotModuleReplacementPlugin(), 28 | new webpack.DefinePlugin(GLOBALS) 29 | ], 30 | module: { 31 | loaders: [ 32 | // Sass 33 | { 34 | test: /\.scss$/, 35 | include: [ 36 | path.resolve(__dirname, '../src/client/assets/javascripts'), 37 | path.resolve(__dirname, '../src/client/assets/styles'), 38 | path.resolve(__dirname, '../src/client/scripts') 39 | ], 40 | loaders: [ 41 | 'style', 42 | 'css', 43 | 'postcss', 44 | { loader: 'sass', query: { outputStyle: 'expanded' } } 45 | ] 46 | }, 47 | // Sass + CSS Modules 48 | // { 49 | // test: /\.scss$/, 50 | // include: /src\/client\/assets\/javascripts/, 51 | // loaders: [ 52 | // 'style', 53 | // { 54 | // loader: 'css', 55 | // query: { 56 | // modules: true, 57 | // importLoaders: 1, 58 | // localIdentName: '[path][name]__[local]--[hash:base64:5]' 59 | // } 60 | // }, 61 | // 'postcss', 62 | // { loader: 'sass', query: { outputStyle: 'expanded' } } 63 | // ] 64 | // }, 65 | // CSS 66 | { 67 | test: /\.css$/, 68 | loader: 'style!css!postcss' 69 | } 70 | ] 71 | } 72 | }); 73 | -------------------------------------------------------------------------------- /config/webpack.config.production.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const merge = require('webpack-merge'); 3 | const webpack = require('webpack'); 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 6 | const config = require('./webpack.config.base'); 7 | 8 | const GLOBALS = { 9 | 'process.env': { 10 | 'NODE_ENV': JSON.stringify('production') 11 | }, 12 | __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false')) 13 | }; 14 | 15 | module.exports = merge(config, { 16 | debug: false, 17 | devtool: 'cheap-module-source-map', 18 | entry: { 19 | application: 'production', 20 | vendor: ['react', 'react-dom', 'react-redux', 'react-router', 'react-router-redux', 'redux'] 21 | }, 22 | plugins: [ 23 | new CopyWebpackPlugin([ 24 | { 25 | from: path.join(__dirname, '../src/client/assets/images'), 26 | to: 'images' 27 | } 28 | ]), 29 | // Avoid publishing files when compilation fails 30 | new webpack.NoErrorsPlugin(), 31 | new webpack.DefinePlugin(GLOBALS), 32 | new webpack.optimize.DedupePlugin(), 33 | new webpack.optimize.UglifyJsPlugin({ 34 | compress: { 35 | warnings: false, 36 | 'screw_ie8': true 37 | }, 38 | output: { 39 | comments: false 40 | }, 41 | sourceMap: false 42 | }), 43 | new webpack.LoaderOptionsPlugin({ 44 | minimize: true, 45 | debug: false 46 | }), 47 | new ExtractTextPlugin({ 48 | filename: 'css/app.css', 49 | allChunks: true 50 | }) 51 | ], 52 | module: { 53 | noParse: /\.min\.js$/, 54 | loaders: [ 55 | // Sass 56 | { 57 | test: /\.scss$/, 58 | include: [ 59 | path.resolve(__dirname, '../src/client/assets/javascripts'), 60 | path.resolve(__dirname, '../src/client/assets/styles'), 61 | path.resolve(__dirname, '../src/client/scripts') 62 | ], 63 | loader: ExtractTextPlugin.extract({ 64 | fallbackLoader: 'style', 65 | loader: [ 66 | { loader: 'css', query: { sourceMap: true } }, 67 | 'postcss', 68 | { loader: 'sass', query: { outputStyle: 'compressed' } } 69 | ] 70 | }) 71 | }, 72 | // Sass + CSS Modules 73 | // { 74 | // test: /\.scss$/, 75 | // include: /src\/client\/assets\/javascripts/, 76 | // loader: ExtractTextPlugin.extract({ 77 | // fallbackLoader: 'style', 78 | // loader: [ 79 | // { 80 | // loader: 'css', 81 | // query: { 82 | // modules: true, 83 | // importLoaders: 1, 84 | // localIdentName: '[path][name]__[local]--[hash:base64:5]' 85 | // } 86 | // }, 87 | // 'postcss', 88 | // { loader: 'sass', query: { outputStyle: 'compressed' } } 89 | // ] 90 | // }) 91 | // }, 92 | // CSS 93 | { 94 | test: /\.css$/, 95 | loader: ExtractTextPlugin.extract({ 96 | fallbackLoader: 'style', 97 | loader: ['css', 'postcss'] 98 | }) 99 | } 100 | ] 101 | }, 102 | }); 103 | -------------------------------------------------------------------------------- /dev-server.js: -------------------------------------------------------------------------------- 1 | // Creates a hot reloading development environment 2 | 3 | const path = require('path'); 4 | const express = require('express'); 5 | const webpack = require('webpack'); 6 | const webpackDevMiddleware = require('webpack-dev-middleware'); 7 | const webpackHotMiddleware = require('webpack-hot-middleware'); 8 | const DashboardPlugin = require('webpack-dashboard/plugin'); 9 | const config = require('./config/webpack.config.development'); 10 | 11 | const app = express(); 12 | const compiler = webpack(config); 13 | 14 | // Apply CLI dashboard for your webpack dev server 15 | compiler.apply(new DashboardPlugin()); 16 | 17 | const host = process.env.HOST || 'localhost'; 18 | const port = process.env.PORT || 3000; 19 | 20 | function log() { 21 | arguments[0] = '\nWebpack: ' + arguments[0]; 22 | console.log.apply(console, arguments); 23 | } 24 | 25 | app.use(webpackDevMiddleware(compiler, { 26 | noInfo: true, 27 | publicPath: config.output.publicPath, 28 | stats: { 29 | colors: true 30 | }, 31 | historyApiFallback: true 32 | })); 33 | 34 | app.use(webpackHotMiddleware(compiler)); 35 | 36 | app.get('*', (req, res) => { 37 | res.sendFile(path.join(__dirname, './src/client/assets/index.html')); 38 | }); 39 | 40 | app.listen(port, host, (err) => { 41 | if (err) { 42 | log(err); 43 | return; 44 | } 45 | 46 | log('🚧 App is listening at http://%s:%s', host, port); 47 | }); 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-webpack-es6-boilerplate", 3 | "description": "A starter project for modern React apps with Redux", 4 | "version": "1.1.1", 5 | "author": "Nick S. Plekhanov ", 6 | "license": "MIT", 7 | "keywords": [ 8 | "react", 9 | "redux", 10 | "es6", 11 | "hmr", 12 | "hot", 13 | "babel", 14 | "webpack", 15 | "sentry", 16 | "architecture", 17 | "webpack-dev-middleware", 18 | "webpack-hot-middleware", 19 | "boilerplate", 20 | "starter" 21 | ], 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/nicksp/redux-webpack-es6-boilerplate.git" 25 | }, 26 | "bugs": "https://github.com/nicksp/redux-webpack-es6-boilerplate/issues", 27 | "scripts": { 28 | "clean:build": "rimraf build", 29 | "build:html": "node ./bin/buildHtml.js", 30 | "prestart": "npm run clean:build", 31 | "start": "webpack-dashboard -c cyan -- node dev-server.js", 32 | "prebuild": "npm run clean:build", 33 | "build": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.production.js --progress", 34 | "postbuild": "npm run build:html", 35 | "build:serve": "http-server build/client -p 3003 --cors -o", 36 | "lint": "eslint config src/js/** --ext .js", 37 | "jscs": "jscs src/js/", 38 | "typecheck": "flow", 39 | "test": "mocha --compilers js:babel-core/register,css:./test/unit/cssNullCompiler.js --require ./test/unit/testHelper.js --recursive ./test/unit", 40 | "test:watch": "npm run test -- --watch", 41 | "tunnel": "lt --port 3000" 42 | }, 43 | "devDependencies": { 44 | "babel-cli": "6.14.0", 45 | "babel-core": "6.14.0", 46 | "babel-eslint": "6.1.2", 47 | "babel-loader": "6.2.5", 48 | "babel-plugin-transform-decorators-legacy": "1.3.4", 49 | "babel-plugin-transform-flow-strip-types": "6.14.0", 50 | "babel-plugin-transform-react-constant-elements": "6.9.1", 51 | "babel-plugin-transform-react-remove-prop-types": "0.2.9", 52 | "babel-plugin-transform-runtime": "6.15.0", 53 | "babel-preset-es2015": "6.14.0", 54 | "babel-preset-react": "6.11.1", 55 | "babel-preset-stage-0": "6.5.0", 56 | "chai": "3.5.0", 57 | "chai-jquery": "2.0.0", 58 | "cheerio": "0.22.0", 59 | "colors": "1.1.2", 60 | "copy-webpack-plugin": "3.0.1", 61 | "cross-env": "2.0.1", 62 | "css-loader": "0.24.0", 63 | "eslint": "3.4.0", 64 | "eslint-plugin-flowtype": "2.11.4", 65 | "eslint-plugin-react": "6.2.0", 66 | "extract-text-webpack-plugin": "2.0.0-beta.3", 67 | "file-loader": "0.9.0", 68 | "flow-bin": "0.31.1", 69 | "http-server": "0.9.0", 70 | "jquery": "3.1.0", 71 | "jscs": "3.0.7", 72 | "jsdom": "9.4.5", 73 | "mocha": "3.0.2", 74 | "node-sass": "3.8.0", 75 | "postcss-loader": "0.11.1", 76 | "react-addons-test-utils": "15.3.1", 77 | "redbox-react": "1.3.0", 78 | "redux-devtools": "3.3.1", 79 | "redux-devtools-dock-monitor": "1.1.1", 80 | "redux-devtools-log-monitor": "1.0.11", 81 | "redux-immutable-state-invariant": "1.2.3", 82 | "redux-slider-monitor": "1.0.7", 83 | "rimraf": "2.5.4", 84 | "sass-loader": "4.0.1", 85 | "style-loader": "0.13.1", 86 | "url-loader": "0.5.7", 87 | "webpack": "2.1.0-beta.21", 88 | "webpack-dashboard": "0.1.8", 89 | "webpack-dev-middleware": "1.6.1", 90 | "webpack-hot-middleware": "2.12.2", 91 | "webpack-merge": "0.14.1" 92 | }, 93 | "dependencies": { 94 | "autoprefixer": "6.4.1", 95 | "babel-runtime": "6.11.6", 96 | "classnames": "2.2.5", 97 | "express": "4.14.0", 98 | "lodash": "4.15.0", 99 | "raven-js": "3.6.1", 100 | "react": "15.3.1", 101 | "react-dom": "15.3.1", 102 | "react-hot-loader": "3.0.0-beta.2", 103 | "react-redux": "4.4.5", 104 | "react-router": "2.7.0", 105 | "react-router-redux": "4.0.5", 106 | "redux": "3.5.2", 107 | "redux-logger": "2.6.1", 108 | "redux-promise": "0.5.3", 109 | "reselect": "2.5.3" 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/client/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicksp/redux-webpack-es6-boilerplate/3383b0dc44f125fbaf513079b3e8b96ae13c6ac0/src/client/assets/images/favicon.ico -------------------------------------------------------------------------------- /src/client/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Redux minimal boilerplate 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/app/App.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | const App = (props) => ( 4 |
5 | {React.cloneElement({...props}.children, {...props})} 6 |
7 | ); 8 | 9 | App.propTypes = { 10 | children: PropTypes.element.isRequired 11 | }; 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/app/DevTools.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createDevTools } from 'redux-devtools'; 3 | 4 | // Monitors are separate packages, and you can make a custom one 5 | import LogMonitor from 'redux-devtools-log-monitor'; 6 | import DockMonitor from 'redux-devtools-dock-monitor'; 7 | import SliderMonitor from 'redux-slider-monitor'; 8 | 9 | // createDevTools takes a monitor and produces a DevTools component 10 | export default createDevTools( 11 | 14 | 15 | 16 | 17 | ); 18 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/app/Root.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React, { PropTypes } from 'react'; 4 | import { Provider } from 'react-redux'; 5 | import { Router } from 'react-router'; 6 | 7 | import routes from './routes'; 8 | import { SENTRY_URL } from './config'; 9 | 10 | // If you use React Router, make this component 11 | // render with your routes. Currently, 12 | // only synchronous routes are hot reloaded, and 13 | // you will see a warning from on every reload. 14 | // You can ignore this warning. For details, see: 15 | // https://github.com/reactjs/react-router/issues/2182 16 | 17 | window.Raven && Raven.config(SENTRY_URL).install(); 18 | 19 | const Root = ({ store, history }) => { 20 | let ComponentEl = ( 21 | 22 | 23 | 24 | ); 25 | 26 | if (process.env.NODE_ENV !== 'production') { 27 | const DevTools = require('./DevTools').default; 28 | 29 | ComponentEl = ( 30 | 31 |
32 | 33 | {!window.devToolsExtension ? : null} 34 |
35 |
36 | ); 37 | } 38 | 39 | return ComponentEl; 40 | }; 41 | 42 | Root.propTypes = { 43 | history: PropTypes.object.isRequired, 44 | store: PropTypes.object.isRequired 45 | }; 46 | 47 | export default Root; 48 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/app/config.js: -------------------------------------------------------------------------------- 1 | const SENTRY_KEY = '488193c1894241789631f5a36188e3a5'; 2 | const SENTRY_APP = '96144'; 3 | export const SENTRY_URL = `https://${SENTRY_KEY}@sentry.io/${SENTRY_APP}`; 4 | 5 | export function logException(ex, context) { 6 | Raven.captureException(ex, { 7 | extra: context 8 | }); 9 | /*eslint no-console:0*/ 10 | window && window.console && console.error && console.error(ex); 11 | } 12 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/app/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { browserHistory } from 'react-router'; 4 | import { syncHistoryWithStore } from 'react-router-redux'; 5 | import { AppContainer } from 'react-hot-loader'; 6 | import Redbox from 'redbox-react'; 7 | 8 | import Root from './Root'; 9 | import configureStore from './store/configureStore'; 10 | 11 | import 'styles/bootstrap.min.css'; 12 | import 'styles/styles.scss'; 13 | 14 | const store = configureStore(); 15 | const history = syncHistoryWithStore(browserHistory, store); 16 | 17 | // Get the DOM Element that will host our React application 18 | const rootEl = document.getElementById('app'); 19 | 20 | // Render the React application to the DOM 21 | render( 22 | 23 | 24 | , 25 | rootEl 26 | ); 27 | 28 | if (module.hot) { 29 | /** 30 | * Warning from React Router, caused by react-hot-loader. 31 | * The warning can be safely ignored, so filter it from the console. 32 | * Otherwise you'll see it every time something changes. 33 | * See https://github.com/gaearon/react-hot-loader/issues/298 34 | */ 35 | const orgError = console.error; // eslint-disable-line no-console 36 | console.error = (message) => { // eslint-disable-line no-console 37 | if (message && message.indexOf('You cannot change ;') === -1) { 38 | // Log the error as normally 39 | orgError.apply(console, [message]); 40 | } 41 | }; 42 | 43 | module.hot.accept('./Root', () => { 44 | // If you use Webpack 2 in ES modules mode, you can 45 | // use here rather than require() a . 46 | const NextApp = require('./Root').default; 47 | 48 | render( 49 | 50 | 51 | , 52 | rootEl 53 | ); 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/app/reducer.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { routerReducer as routing } from 'react-router-redux'; 3 | 4 | import friends, { NAME as friendsName } from 'features/friends'; 5 | 6 | export default combineReducers({ 7 | routing, 8 | [friendsName]: friends 9 | }); 10 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/app/routes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route, IndexRoute, Redirect } from 'react-router'; 3 | 4 | import App from './App'; 5 | import FriendsView from 'features/friends/components/FriendsView'; 6 | import NotFoundView from 'components/NotFound'; 7 | 8 | export default ( 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/app/store/configureStore.development.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import { persistState } from 'redux-devtools'; 3 | import promiseMiddleware from 'redux-promise'; 4 | import createLogger from 'redux-logger'; 5 | 6 | import rootReducer from '../reducer'; 7 | import DevTools from '../DevTools'; 8 | 9 | /** 10 | * Entirely optional. 11 | * This tiny library adds some functionality to your DevTools, 12 | * by logging actions/state to your console. Used in conjunction 13 | * with your standard DevTools monitor gives you great flexibility. 14 | */ 15 | const logger = createLogger(); 16 | 17 | const middlewares = [promiseMiddleware, logger, require('redux-immutable-state-invariant')()]; 18 | 19 | // By default we try to read the key from ?debug_session= in the address bar 20 | const getDebugSessionKey = function () { 21 | const matches = window.location.href.match(/[?&]debug_session=([^&]+)\b/); 22 | return (matches && matches.length) ? matches[1] : null; 23 | }; 24 | 25 | const enhancer = compose( 26 | applyMiddleware(...middlewares), 27 | window.devToolsExtension ? window.devToolsExtension() : DevTools.instrument(), 28 | // Optional. Lets you write ?debug_session= in address bar to persist debug sessions 29 | persistState(getDebugSessionKey()) 30 | ); 31 | 32 | export default function configureStore(initialState) { 33 | const store = createStore(rootReducer, initialState, enhancer); 34 | 35 | // Enable hot module replacement for reducers (requires Webpack or Browserify HMR to be enabled) 36 | if (module.hot) { 37 | module.hot.accept('../reducer', () => { 38 | const nextReducer = require('../reducer').default; 39 | store.replaceReducer(nextReducer); 40 | }); 41 | } 42 | 43 | return store; 44 | } 45 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/app/store/configureStore.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV === 'production') { 2 | module.exports = require('./configureStore.production').default; 3 | } 4 | else { 5 | module.exports = require('./configureStore.development').default; 6 | } 7 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/app/store/configureStore.production.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import promiseMiddleware from 'redux-promise'; 3 | 4 | import rootReducer from '../reducer'; 5 | 6 | const enhancer = compose( 7 | applyMiddleware(promiseMiddleware) 8 | )(createStore); 9 | 10 | export default function configureStore(initialState) { 11 | return enhancer(rootReducer, initialState); 12 | } 13 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/components/NotFound/NotFound.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Link } from 'react-router'; 3 | 4 | export default class NotFound extends Component { 5 | render() { 6 | return ( 7 |
8 |

This is a demo 404 page!

9 |
10 | Back To Home View 11 |
12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/components/NotFound/NotFound.spec.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicksp/redux-webpack-es6-boilerplate/3383b0dc44f125fbaf513079b3e8b96ae13c6ac0/src/client/assets/javascripts/components/NotFound/NotFound.spec.js -------------------------------------------------------------------------------- /src/client/assets/javascripts/components/NotFound/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './NotFound'; 2 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/AddFriendInput/AddFriendInput.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | 3 | import './AddFriendInput.scss'; 4 | 5 | export default class AddFriendInput extends Component { 6 | static propTypes = { 7 | addFriend: PropTypes.func.isRequired, 8 | name: PropTypes.string 9 | }; 10 | 11 | constructor(props, context) { 12 | super(props, context); 13 | 14 | this.state = { 15 | name: this.props.name || '' 16 | }; 17 | 18 | this.handleChange = this.handleChange.bind(this); 19 | this.handleSubmit = this.handleSubmit.bind(this); 20 | } 21 | 22 | handleChange(e) { 23 | this.setState({ name: e.target.value }); 24 | } 25 | 26 | handleSubmit(e) { 27 | const name = e.target.value.trim(); 28 | if (e.which === 13) { 29 | this.props.addFriend(name); 30 | this.setState({ name: '' }); 31 | } 32 | } 33 | 34 | render() { 35 | return ( 36 | 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/AddFriendInput/AddFriendInput.scss: -------------------------------------------------------------------------------- 1 | .addFriendInput { 2 | border-radius: 0; 3 | border-color: #ABAAAA; 4 | border-left: 0; 5 | border-right: 0; 6 | } 7 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/AddFriendInput/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './AddFriendInput'; 2 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/FriendList/FriendList.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | 3 | import FriendListItem from '../FriendListItem'; 4 | import './FriendList.scss'; 5 | 6 | export default class FriendList extends Component { 7 | static propTypes = { 8 | actions: PropTypes.object.isRequired, 9 | friends: PropTypes.array.isRequired 10 | }; 11 | 12 | renderList() { 13 | return this.props.friends.map((friend) => 14 | ( 15 | 21 | ) 22 | ); 23 | } 24 | 25 | render() { 26 | return ( 27 |
    28 | {this.renderList()} 29 |
30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/FriendList/FriendList.scss: -------------------------------------------------------------------------------- 1 | .friendList { 2 | padding-left: 0; 3 | margin-bottom: 0; 4 | } 5 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/FriendList/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './FriendList'; 2 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/FriendListApp.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F4F3F0; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | } 7 | 8 | .friendListApp { 9 | width: 300px; 10 | padding-top: 18px; 11 | background-color: #5C75B0; 12 | border: 1px solid #E3E3E3; 13 | } 14 | 15 | .friendListApp h1 { 16 | color: white; 17 | font-size: 16px; 18 | line-height: 20px; 19 | margin-bottom: 10px; 20 | margin-top: 0; 21 | padding-left: 10px; 22 | font-family: Helvetica; 23 | } 24 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/FriendListItem/FriendListItem.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import classnames from 'classnames'; 3 | 4 | import './FriendListItem.scss'; 5 | 6 | export default class FriendListItem extends Component { 7 | static propTypes = { 8 | deleteFriend: PropTypes.func.isRequired, 9 | id: PropTypes.number.isRequired, 10 | name: PropTypes.string.isRequired, 11 | starFriend: PropTypes.func.isRequired, 12 | starred: PropTypes.bool 13 | }; 14 | 15 | render() { 16 | return ( 17 |
  • 18 |
    19 |
    {this.props.name}
    20 |
    xx friends in common
    21 |
    22 |
    23 | 26 | 29 |
    30 |
  • 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/FriendListItem/FriendListItem.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "open_sansregular"; 3 | src: url("./fonts/opensans-regular-webfont.woff") format("woff"); 4 | font-weight: normal; 5 | font-style: normal; 6 | } 7 | 8 | .friendListItem { 9 | list-style: none; 10 | background: url(./images/icon-user.png) no-repeat left 10px top 10px; 11 | font-family: "open_sansregular", Arial; 12 | padding: 20px 10px 20px 60px; 13 | background-color: white; 14 | border-bottom: 1px solid #E3E3E3; 15 | display: flex; 16 | } 17 | 18 | .friendInfos { 19 | flex: 1 0 auto; 20 | } 21 | 22 | .friendInfos span { 23 | font-weight: bold; 24 | } 25 | 26 | .friendActions { 27 | flex: 0 0 90px; 28 | } 29 | 30 | .btnAction, .btnAction:active, .btnAction:focus, .btnAction:hover { 31 | margin-right: 5px; 32 | color: #5C75B0; 33 | } 34 | 35 | button:focus { 36 | outline: 0 !important; 37 | } 38 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/FriendListItem/fonts/opensans-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicksp/redux-webpack-es6-boilerplate/3383b0dc44f125fbaf513079b3e8b96ae13c6ac0/src/client/assets/javascripts/features/friends/components/FriendListItem/fonts/opensans-regular-webfont.woff -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/FriendListItem/images/icon-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicksp/redux-webpack-es6-boilerplate/3383b0dc44f125fbaf513079b3e8b96ae13c6ac0/src/client/assets/javascripts/features/friends/components/FriendListItem/images/icon-user.png -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/FriendListItem/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './FriendListItem'; 2 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/FriendsLayout.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | 3 | import AddFriendInput from './AddFriendInput'; 4 | import FriendList from './FriendList'; 5 | import './FriendListApp.scss'; 6 | 7 | export default class FriendsLayout extends Component { 8 | static propTypes = { 9 | actions: PropTypes.object.isRequired, 10 | friends: PropTypes.object.isRequired 11 | }; 12 | 13 | render() { 14 | const { friends: { friendsById }, actions } = this.props; 15 | 16 | return ( 17 |
    18 |

    Best Rappers List

    19 | 20 | 21 |
    22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/components/FriendsView.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { bindActionCreators } from 'redux'; 4 | 5 | import { actionCreators as friendsActions, selector } from '../'; 6 | import FriendsLayout from './FriendsLayout'; 7 | 8 | @connect(selector, (dispatch) => ({ 9 | actions: bindActionCreators(friendsActions, dispatch) 10 | })) 11 | export default class FriendsView extends Component { 12 | render() { 13 | return ( 14 |
    15 | 16 |
    17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/friends.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { createStructuredSelector } from 'reselect'; 4 | import assign from 'lodash/assign'; 5 | 6 | import { State } from 'models/friends'; 7 | 8 | // Action Types 9 | 10 | // Define types in the form of 'npm-module-or-myapp/feature-name/ACTION_TYPE_NAME' 11 | const ADD_FRIEND = 'redux-app/friends/ADD_FRIEND'; 12 | const STAR_FRIEND = 'redux-app/friends/STAR_FRIEND'; 13 | const DELETE_FRIEND = 'redux-app/friends/DELETE_FRIEND'; 14 | 15 | // This will be used in our root reducer and selectors 16 | 17 | export const NAME = 'friends'; 18 | 19 | // Define the initial state for `friends` module 20 | 21 | const initialState: State = { 22 | friends: [0, 1, 2, 3, 4], 23 | friendsById: [ 24 | { 25 | id: 0, 26 | name: 'Notorious B.I.G.' 27 | }, 28 | { 29 | id: 1, 30 | name: 'Tupac Shakur' 31 | }, 32 | { 33 | id: 2, 34 | name: 'Dr. Dre' 35 | }, 36 | { 37 | id: 3, 38 | name: 'Big Pun' 39 | }, 40 | { 41 | id: 4, 42 | name: 'Rakim' 43 | } 44 | ] 45 | }; 46 | 47 | // Reducer 48 | 49 | /** 50 | * Another clever approach of writing reducers: 51 | * 52 | * export default function(state = initialState, action) { 53 | * const actions = { 54 | * [ACTION_TYPE]: () => [action.payload.data, ...state] 55 | * }; 56 | * 57 | * return (_.isFunction(actions[action.type])) ? actions[action.type]() : state 58 | * } 59 | */ 60 | 61 | export default function reducer(state: State = initialState, action: any = {}): State { 62 | switch (action.type) { 63 | case ADD_FRIEND: { 64 | const len = state.friends.length ? state.friends.length : 1; 65 | const newId = (state.friends[len - 1] + 1) || 0; 66 | return { 67 | ...state, 68 | friends: state.friends.concat(newId), 69 | friendsById: [ 70 | ...state.friendsById, 71 | { 72 | id: newId, 73 | name: action.name 74 | } 75 | ] 76 | }; 77 | } 78 | 79 | case DELETE_FRIEND: 80 | return { 81 | ...state, 82 | friends: state.friends.filter((id) => id !== action.id), 83 | friendsById: state.friendsById.filter((friend) => friend.id !== action.id) 84 | }; 85 | 86 | case STAR_FRIEND: 87 | return { 88 | ...state, 89 | friendsById: state.friendsById.map((friend) => { 90 | if (friend.id !== action.id) { 91 | return friend; 92 | } 93 | 94 | return assign({}, friend, { 95 | starred: !friend.starred 96 | }); 97 | }) 98 | }; 99 | 100 | default: 101 | return state; 102 | } 103 | } 104 | 105 | // Action Creators 106 | 107 | function addFriend(name: string) { 108 | return { 109 | type: ADD_FRIEND, 110 | name 111 | }; 112 | } 113 | 114 | // or in a form of arrow function 115 | 116 | // const addFriend = (name: string) => ({ 117 | // type: ADD_FRIEND, 118 | // name 119 | // }); 120 | 121 | function deleteFriend(id: number) { 122 | return { 123 | type: DELETE_FRIEND, 124 | id 125 | }; 126 | } 127 | 128 | function starFriend(id: number) { 129 | return { 130 | type: STAR_FRIEND, 131 | id 132 | }; 133 | } 134 | 135 | // Selectors 136 | 137 | const friends = (state) => state[NAME]; 138 | 139 | export const selector = createStructuredSelector({ 140 | friends 141 | }); 142 | 143 | export const actionCreators = { 144 | addFriend, 145 | deleteFriend, 146 | starFriend 147 | }; 148 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/features/friends/index.js: -------------------------------------------------------------------------------- 1 | // Feature/Module index is responsible for maintaining its public API 2 | // This is the exposed surface where modules can interface with each other. 3 | 4 | export { 5 | default, 6 | actionCreators, 7 | selector, 8 | NAME 9 | } from './friends'; 10 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/models/friends.js: -------------------------------------------------------------------------------- 1 | type FriendById = { 2 | id?: number, 3 | name: string 4 | }; 5 | 6 | // This is the model of our module state 7 | export type State = { 8 | friends: number[], 9 | friendsById: Array 10 | }; 11 | -------------------------------------------------------------------------------- /src/client/assets/javascripts/utils/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicksp/redux-webpack-es6-boilerplate/3383b0dc44f125fbaf513079b3e8b96ae13c6ac0/src/client/assets/javascripts/utils/.gitkeep -------------------------------------------------------------------------------- /src/client/assets/styles/bootstrap.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v4.0.0-alpha.2 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */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,menu,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-color:transparent}a:active{outline:0}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;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;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;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{*,::after,::before{text-shadow:none!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}html{-webkit-box-sizing:border-box;box-sizing:border-box}*,::after,::before{-webkit-box-sizing:inherit;box-sizing:inherit}@-ms-viewport{width:device-width}@viewport{width:device-width}html{font-size:16px;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:1rem;line-height:1.5;color:#373a3c;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #818a91}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}a{color:#0275d8;text-decoration:none}a:focus,a:hover{color:#014c8c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}pre{margin-top:0;margin-bottom:1rem}figure{margin:0 0 1rem}img{vertical-align:middle}[role=button]{cursor:pointer}[role=button],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{background-color:transparent}caption{padding-top:.75rem;padding-bottom:.75rem;color:#818a91;text-align:left;caption-side:bottom}th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,select,textarea{margin:0;line-height:inherit;border-radius:0}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit}input[type=search]{-webkit-box-sizing:inherit;box-sizing:inherit;-webkit-appearance:none}output{display:inline-block}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1{font-size:2.5rem}h2{font-size:2rem}h3{font-size:1.75rem}h4{font-size:1.5rem}h5{font-size:1.25rem}h6{font-size:1rem}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.75rem}.h4{font-size:1.5rem}.h5{font-size:1.25rem}.h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300}.display-2{font-size:5.5rem;font-weight:300}.display-3{font-size:4.5rem;font-weight:300}.display-4{font-size:3.5rem;font-weight:300}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:5px}.dl-horizontal{margin-right:-1.875rem;margin-left:-1.875rem}.dl-horizontal::after{display:table;clear:both;content:""}.initialism{font-size:90%;text-transform:uppercase}.blockquote{padding:.5rem 1rem;margin-bottom:1rem;font-size:1.25rem;border-left:.25rem solid #eceeef}.blockquote-footer{display:block;font-size:80%;line-height:1.5;color:#818a91}.blockquote-footer::before{content:"\2014 \00A0"}.blockquote-reverse{padding-right:1rem;padding-left:0;text-align:right;border-right:.25rem solid #eceeef;border-left:0}.blockquote-reverse .blockquote-footer::before{content:""}.blockquote-reverse .blockquote-footer::after{content:"\00A0 \2014"}.carousel-inner>.carousel-item>a>img,.carousel-inner>.carousel-item>img,.img-fluid{display:block;max-width:100%;height:auto}.img-rounded{border-radius:.3rem}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:.25rem;line-height:1.5;background-color:#fff;border:1px solid #ddd;border-radius:.25rem;-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%}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#818a91}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:.2rem .4rem;font-size:90%;color:#bd4147;background-color:#f7f7f9;border-radius:.25rem}kbd{padding:.2rem .4rem;font-size:90%;color:#fff;background-color:#333;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;margin-top:0;margin-bottom:1rem;font-size:90%;line-height:1.5;color:#373a3c}pre code{padding:0;font-size:inherit;color:inherit;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:.9375rem;padding-left:.9375rem;margin-right:auto;margin-left:auto}.container::after{display:table;clear:both;content:""}@media (min-width:544px){.container{max-width:576px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:940px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{padding-right:.9375rem;padding-left:.9375rem;margin-right:auto;margin-left:auto}.container-fluid::after{display:table;clear:both;content:""}.row{margin-right:-.9375rem;margin-left:-.9375rem}.row::after{display:table;clear:both;content:""}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.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-md-1,.col-md-10,.col-md-11,.col-md-12,.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-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.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-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:.9375rem;padding-left:.9375rem}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-1{width:8.333333%}.col-xs-2{width:16.666667%}.col-xs-3{width:25%}.col-xs-4{width:33.333333%}.col-xs-5{width:41.666667%}.col-xs-6{width:50%}.col-xs-7{width:58.333333%}.col-xs-8{width:66.666667%}.col-xs-9{width:75%}.col-xs-10{width:83.333333%}.col-xs-11{width:91.666667%}.col-xs-12{width:100%}.col-xs-pull-0{right:auto}.col-xs-pull-1{right:8.333333%}.col-xs-pull-2{right:16.666667%}.col-xs-pull-3{right:25%}.col-xs-pull-4{right:33.333333%}.col-xs-pull-5{right:41.666667%}.col-xs-pull-6{right:50%}.col-xs-pull-7{right:58.333333%}.col-xs-pull-8{right:66.666667%}.col-xs-pull-9{right:75%}.col-xs-pull-10{right:83.333333%}.col-xs-pull-11{right:91.666667%}.col-xs-pull-12{right:100%}.col-xs-push-0{left:auto}.col-xs-push-1{left:8.333333%}.col-xs-push-2{left:16.666667%}.col-xs-push-3{left:25%}.col-xs-push-4{left:33.333333%}.col-xs-push-5{left:41.666667%}.col-xs-push-6{left:50%}.col-xs-push-7{left:58.333333%}.col-xs-push-8{left:66.666667%}.col-xs-push-9{left:75%}.col-xs-push-10{left:83.333333%}.col-xs-push-11{left:91.666667%}.col-xs-push-12{left:100%}.col-xs-offset-0{margin-left:0}.col-xs-offset-1{margin-left:8.333333%}.col-xs-offset-2{margin-left:16.666667%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-4{margin-left:33.333333%}.col-xs-offset-5{margin-left:41.666667%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-7{margin-left:58.333333%}.col-xs-offset-8{margin-left:66.666667%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-10{margin-left:83.333333%}.col-xs-offset-11{margin-left:91.666667%}.col-xs-offset-12{margin-left:100%}@media (min-width:544px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-1{width:8.333333%}.col-sm-2{width:16.666667%}.col-sm-3{width:25%}.col-sm-4{width:33.333333%}.col-sm-5{width:41.666667%}.col-sm-6{width:50%}.col-sm-7{width:58.333333%}.col-sm-8{width:66.666667%}.col-sm-9{width:75%}.col-sm-10{width:83.333333%}.col-sm-11{width:91.666667%}.col-sm-12{width:100%}.col-sm-pull-0{right:auto}.col-sm-pull-1{right:8.333333%}.col-sm-pull-2{right:16.666667%}.col-sm-pull-3{right:25%}.col-sm-pull-4{right:33.333333%}.col-sm-pull-5{right:41.666667%}.col-sm-pull-6{right:50%}.col-sm-pull-7{right:58.333333%}.col-sm-pull-8{right:66.666667%}.col-sm-pull-9{right:75%}.col-sm-pull-10{right:83.333333%}.col-sm-pull-11{right:91.666667%}.col-sm-pull-12{right:100%}.col-sm-push-0{left:auto}.col-sm-push-1{left:8.333333%}.col-sm-push-2{left:16.666667%}.col-sm-push-3{left:25%}.col-sm-push-4{left:33.333333%}.col-sm-push-5{left:41.666667%}.col-sm-push-6{left:50%}.col-sm-push-7{left:58.333333%}.col-sm-push-8{left:66.666667%}.col-sm-push-9{left:75%}.col-sm-push-10{left:83.333333%}.col-sm-push-11{left:91.666667%}.col-sm-push-12{left:100%}.col-sm-offset-0{margin-left:0}.col-sm-offset-1{margin-left:8.333333%}.col-sm-offset-2{margin-left:16.666667%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-4{margin-left:33.333333%}.col-sm-offset-5{margin-left:41.666667%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-7{margin-left:58.333333%}.col-sm-offset-8{margin-left:66.666667%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-10{margin-left:83.333333%}.col-sm-offset-11{margin-left:91.666667%}.col-sm-offset-12{margin-left:100%}}@media (min-width:768px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-1{width:8.333333%}.col-md-2{width:16.666667%}.col-md-3{width:25%}.col-md-4{width:33.333333%}.col-md-5{width:41.666667%}.col-md-6{width:50%}.col-md-7{width:58.333333%}.col-md-8{width:66.666667%}.col-md-9{width:75%}.col-md-10{width:83.333333%}.col-md-11{width:91.666667%}.col-md-12{width:100%}.col-md-pull-0{right:auto}.col-md-pull-1{right:8.333333%}.col-md-pull-2{right:16.666667%}.col-md-pull-3{right:25%}.col-md-pull-4{right:33.333333%}.col-md-pull-5{right:41.666667%}.col-md-pull-6{right:50%}.col-md-pull-7{right:58.333333%}.col-md-pull-8{right:66.666667%}.col-md-pull-9{right:75%}.col-md-pull-10{right:83.333333%}.col-md-pull-11{right:91.666667%}.col-md-pull-12{right:100%}.col-md-push-0{left:auto}.col-md-push-1{left:8.333333%}.col-md-push-2{left:16.666667%}.col-md-push-3{left:25%}.col-md-push-4{left:33.333333%}.col-md-push-5{left:41.666667%}.col-md-push-6{left:50%}.col-md-push-7{left:58.333333%}.col-md-push-8{left:66.666667%}.col-md-push-9{left:75%}.col-md-push-10{left:83.333333%}.col-md-push-11{left:91.666667%}.col-md-push-12{left:100%}.col-md-offset-0{margin-left:0}.col-md-offset-1{margin-left:8.333333%}.col-md-offset-2{margin-left:16.666667%}.col-md-offset-3{margin-left:25%}.col-md-offset-4{margin-left:33.333333%}.col-md-offset-5{margin-left:41.666667%}.col-md-offset-6{margin-left:50%}.col-md-offset-7{margin-left:58.333333%}.col-md-offset-8{margin-left:66.666667%}.col-md-offset-9{margin-left:75%}.col-md-offset-10{margin-left:83.333333%}.col-md-offset-11{margin-left:91.666667%}.col-md-offset-12{margin-left:100%}}@media (min-width:992px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-1{width:8.333333%}.col-lg-2{width:16.666667%}.col-lg-3{width:25%}.col-lg-4{width:33.333333%}.col-lg-5{width:41.666667%}.col-lg-6{width:50%}.col-lg-7{width:58.333333%}.col-lg-8{width:66.666667%}.col-lg-9{width:75%}.col-lg-10{width:83.333333%}.col-lg-11{width:91.666667%}.col-lg-12{width:100%}.col-lg-pull-0{right:auto}.col-lg-pull-1{right:8.333333%}.col-lg-pull-2{right:16.666667%}.col-lg-pull-3{right:25%}.col-lg-pull-4{right:33.333333%}.col-lg-pull-5{right:41.666667%}.col-lg-pull-6{right:50%}.col-lg-pull-7{right:58.333333%}.col-lg-pull-8{right:66.666667%}.col-lg-pull-9{right:75%}.col-lg-pull-10{right:83.333333%}.col-lg-pull-11{right:91.666667%}.col-lg-pull-12{right:100%}.col-lg-push-0{left:auto}.col-lg-push-1{left:8.333333%}.col-lg-push-2{left:16.666667%}.col-lg-push-3{left:25%}.col-lg-push-4{left:33.333333%}.col-lg-push-5{left:41.666667%}.col-lg-push-6{left:50%}.col-lg-push-7{left:58.333333%}.col-lg-push-8{left:66.666667%}.col-lg-push-9{left:75%}.col-lg-push-10{left:83.333333%}.col-lg-push-11{left:91.666667%}.col-lg-push-12{left:100%}.col-lg-offset-0{margin-left:0}.col-lg-offset-1{margin-left:8.333333%}.col-lg-offset-2{margin-left:16.666667%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-4{margin-left:33.333333%}.col-lg-offset-5{margin-left:41.666667%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-7{margin-left:58.333333%}.col-lg-offset-8{margin-left:66.666667%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-10{margin-left:83.333333%}.col-lg-offset-11{margin-left:91.666667%}.col-lg-offset-12{margin-left:100%}}@media (min-width:1200px){.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{float:left}.col-xl-1{width:8.333333%}.col-xl-2{width:16.666667%}.col-xl-3{width:25%}.col-xl-4{width:33.333333%}.col-xl-5{width:41.666667%}.col-xl-6{width:50%}.col-xl-7{width:58.333333%}.col-xl-8{width:66.666667%}.col-xl-9{width:75%}.col-xl-10{width:83.333333%}.col-xl-11{width:91.666667%}.col-xl-12{width:100%}.col-xl-pull-0{right:auto}.col-xl-pull-1{right:8.333333%}.col-xl-pull-2{right:16.666667%}.col-xl-pull-3{right:25%}.col-xl-pull-4{right:33.333333%}.col-xl-pull-5{right:41.666667%}.col-xl-pull-6{right:50%}.col-xl-pull-7{right:58.333333%}.col-xl-pull-8{right:66.666667%}.col-xl-pull-9{right:75%}.col-xl-pull-10{right:83.333333%}.col-xl-pull-11{right:91.666667%}.col-xl-pull-12{right:100%}.col-xl-push-0{left:auto}.col-xl-push-1{left:8.333333%}.col-xl-push-2{left:16.666667%}.col-xl-push-3{left:25%}.col-xl-push-4{left:33.333333%}.col-xl-push-5{left:41.666667%}.col-xl-push-6{left:50%}.col-xl-push-7{left:58.333333%}.col-xl-push-8{left:66.666667%}.col-xl-push-9{left:75%}.col-xl-push-10{left:83.333333%}.col-xl-push-11{left:91.666667%}.col-xl-push-12{left:100%}.col-xl-offset-0{margin-left:0}.col-xl-offset-1{margin-left:8.333333%}.col-xl-offset-2{margin-left:16.666667%}.col-xl-offset-3{margin-left:25%}.col-xl-offset-4{margin-left:33.333333%}.col-xl-offset-5{margin-left:41.666667%}.col-xl-offset-6{margin-left:50%}.col-xl-offset-7{margin-left:58.333333%}.col-xl-offset-8{margin-left:66.666667%}.col-xl-offset-9{margin-left:75%}.col-xl-offset-10{margin-left:83.333333%}.col-xl-offset-11{margin-left:91.666667%}.col-xl-offset-12{margin-left:100%}}.table{width:100%;max-width:100%;margin-bottom:1rem}.table td,.table th{padding:.75rem;line-height:1.5;vertical-align:top;border-top:1px solid #eceeef}.table thead th{vertical-align:bottom;border-bottom:2px solid #eceeef}.table tbody+tbody{border-top:2px solid #eceeef}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #eceeef}.table-bordered td,.table-bordered th{border:1px solid #eceeef}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover tbody tr:hover{background-color:#f5f5f5}.table-active,.table-active>td,.table-active>th{background-color:#f5f5f5}.table-hover .table-active:hover{background-color:#e8e8e8}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:#e8e8e8}.table-success,.table-success>td,.table-success>th{background-color:#dff0d8}.table-hover .table-success:hover{background-color:#d0e9c6}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#d0e9c6}.table-info,.table-info>td,.table-info>th{background-color:#d9edf7}.table-hover .table-info:hover{background-color:#c4e3f3}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#c4e3f3}.table-warning,.table-warning>td,.table-warning>th{background-color:#fcf8e3}.table-hover .table-warning:hover{background-color:#faf2cc}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#faf2cc}.table-danger,.table-danger>td,.table-danger>th{background-color:#f2dede}.table-hover .table-danger:hover{background-color:#ebcccc}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#ebcccc}.table-responsive{display:block;width:100%;min-height:.01%;overflow-x:auto}.thead-inverse th{color:#fff;background-color:#373a3c}.thead-default th{color:#55595c;background-color:#eceeef}.table-inverse{color:#eceeef;background-color:#373a3c}.table-inverse.table-bordered{border:0}.table-inverse td,.table-inverse th,.table-inverse thead th{border-color:#55595c}.table-reflow thead{float:left}.table-reflow tbody{display:block;white-space:nowrap}.table-reflow td,.table-reflow th{border-top:1px solid #eceeef;border-left:1px solid #eceeef}.table-reflow td:last-child,.table-reflow th:last-child{border-right:1px solid #eceeef}.table-reflow tbody:last-child tr:last-child td,.table-reflow tbody:last-child tr:last-child th,.table-reflow tfoot:last-child tr:last-child td,.table-reflow tfoot:last-child tr:last-child th,.table-reflow thead:last-child tr:last-child td,.table-reflow thead:last-child tr:last-child th{border-bottom:1px solid #eceeef}.table-reflow tr{float:left}.table-reflow tr td,.table-reflow tr th{display:block!important;border:1px solid #eceeef}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#55595c;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:.25rem}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{border-color:#66afe9;outline:0}.form-control::-webkit-input-placeholder{color:#999;opacity:1}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999;opacity:1}.form-control::placeholder{color:#999;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#eceeef;opacity:1}.form-control:disabled{cursor:not-allowed}.form-control-file,.form-control-range{display:block}.form-control-label{padding:.375rem .75rem;margin-bottom:0}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:2.25rem}.input-group-sm input[type=date].form-control,.input-group-sm input[type=time].form-control,.input-group-sm input[type=datetime-local].form-control,.input-group-sm input[type=month].form-control,input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:1.8625rem}.input-group-lg input[type=date].form-control,.input-group-lg input[type=time].form-control,.input-group-lg input[type=datetime-local].form-control,.input-group-lg input[type=month].form-control,input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:3.166667rem}}.form-control-static{min-height:2.25rem;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0}.form-control-static.form-control-lg,.form-control-static.form-control-sm,.input-group-lg>.form-control-static.form-control,.input-group-lg>.form-control-static.input-group-addon,.input-group-lg>.input-group-btn>.form-control-static.btn,.input-group-sm>.form-control-static.form-control,.input-group-sm>.form-control-static.input-group-addon,.input-group-sm>.input-group-btn>.form-control-static.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{padding:.275rem .75rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{padding:.75rem 1.25rem;font-size:1.25rem;line-height:1.333333;border-radius:.3rem}.form-group{margin-bottom:1rem}.checkbox,.radio{position:relative;display:block;margin-bottom:.75rem}.checkbox label,.radio label{padding-left:1.25rem;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox label input:only-child,.radio label input:only-child{position:static}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:.25rem;margin-left:-1.25rem}.checkbox+.checkbox,.radio+.radio{margin-top:-.25rem}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:1.25rem;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:.75rem}input[type=checkbox].disabled,input[type=checkbox]:disabled,input[type=radio].disabled,input[type=radio]:disabled{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label{cursor:not-allowed}.form-control-danger,.form-control-success,.form-control-warning{padding-right:2.25rem;background-repeat:no-repeat;background-position:center right .5625rem;-webkit-background-size:1.4625rem 1.4625rem;background-size:1.4625rem 1.4625rem}.has-success .checkbox,.has-success .checkbox-inline,.has-success .form-control-label,.has-success .radio,.has-success .radio-inline,.has-success .text-help,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#5cb85c}.has-success .form-control{border-color:#5cb85c}.has-success .input-group-addon{color:#5cb85c;background-color:#eaf6ea;border-color:#5cb85c}.has-success .form-control-feedback{color:#5cb85c}.has-success .form-control-success{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjNWNiODVjIiBkPSJNMjMzLjggNjEwYy0xMy4zIDAtMjYtNi0zNC0xNi44TDkwLjUgNDQ4LjhDNzYuMyA0MzAgODAgNDAzLjMgOTguOCAzODljMTguOC0xNC4yIDQ1LjUtMTAuNCA1OS44IDguNGw3MiA5NUw0NTEuMyAyNDJjMTIuNS0yMCAzOC44LTI2LjIgNTguOC0xMy43IDIwIDEyLjQgMjYgMzguNyAxMy43IDU4LjhMMjcwIDU5MGMtNy40IDEyLTIwLjIgMTkuNC0zNC4zIDIwaC0yeiIvPjwvc3ZnPg==)}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .form-control-label,.has-warning .radio,.has-warning .radio-inline,.has-warning .text-help,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#f0ad4e}.has-warning .form-control{border-color:#f0ad4e}.has-warning .input-group-addon{color:#f0ad4e;background-color:#fff;border-color:#f0ad4e}.has-warning .form-control-feedback{color:#f0ad4e}.has-warning .form-control-warning{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjZjBhZDRlIiBkPSJNNjAzIDY0MC4ybC0yNzguNS01MDljLTMuOC02LjYtMTAuOC0xMC42LTE4LjUtMTAuNnMtMTQuNyA0LTE4LjUgMTAuNkw5IDY0MC4yYy0zLjcgNi41LTMuNiAxNC40LjIgMjAuOCAzLjggNi41IDEwLjggMTAuNCAxOC4zIDEwLjRoNTU3YzcuNiAwIDE0LjYtNCAxOC40LTEwLjQgMy41LTYuNCAzLjYtMTQuNCAwLTIwLjh6bS0yNjYuNC0zMGgtNjEuMlY1NDloNjEuMnY2MS4yem0wLTEwN2gtNjEuMlYzMDRoNjEuMnYxOTl6Ii8+PC9zdmc+)}.has-danger .checkbox,.has-danger .checkbox-inline,.has-danger .form-control-label,.has-danger .radio,.has-danger .radio-inline,.has-danger .text-help,.has-danger.checkbox label,.has-danger.checkbox-inline label,.has-danger.radio label,.has-danger.radio-inline label{color:#d9534f}.has-danger .form-control{border-color:#d9534f}.has-danger .input-group-addon{color:#d9534f;background-color:#fdf7f7;border-color:#d9534f}.has-danger .form-control-feedback{color:#d9534f}.has-danger .form-control-danger{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjZDk1MzRmIiBkPSJNNDQ3IDU0NC40Yy0xNC40IDE0LjQtMzcuNiAxNC40LTUyIDBsLTg5LTkyLjctODkgOTIuN2MtMTQuNSAxNC40LTM3LjcgMTQuNC01MiAwLTE0LjQtMTQuNC0xNC40LTM3LjYgMC01Mmw5Mi40LTk2LjMtOTIuNC05Ni4zYy0xNC40LTE0LjQtMTQuNC0zNy42IDAtNTJzMzcuNi0xNC4zIDUyIDBsODkgOTIuOCA4OS4yLTkyLjdjMTQuNC0xNC40IDM3LjYtMTQuNCA1MiAwIDE0LjMgMTQuNCAxNC4zIDM3LjYgMCA1MkwzNTQuNiAzOTZsOTIuNCA5Ni40YzE0LjQgMTQuNCAxNC40IDM3LjYgMCA1MnoiLz48L3N2Zz4=)}@media (min-width:544px){.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 .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .form-control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.btn{display:inline-block;padding:.375rem 1rem;font-size:1rem;font-weight:400;line-height:1.5;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;border:1px solid transparent;border-radius:.25rem}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:focus,.btn:hover{text-decoration:none}.btn.focus{text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0}.btn.disabled,.btn:disabled{cursor:not-allowed;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary:hover{color:#fff;background-color:#025aa5;border-color:#01549b}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#025aa5;border-color:#01549b}.btn-primary.active,.btn-primary:active,.open>.btn-primary.dropdown-toggle{color:#fff;background-color:#025aa5;background-image:none;border-color:#01549b}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.btn-primary.dropdown-toggle.focus,.open>.btn-primary.dropdown-toggle:focus,.open>.btn-primary.dropdown-toggle:hover{color:#fff;background-color:#014682;border-color:#01315a}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary:disabled.focus,.btn-primary:disabled:focus{background-color:#0275d8;border-color:#0275d8}.btn-primary.disabled:hover,.btn-primary:disabled:hover{background-color:#0275d8;border-color:#0275d8}.btn-secondary{color:#373a3c;background-color:#fff;border-color:#ccc}.btn-secondary:hover{color:#373a3c;background-color:#e6e6e6;border-color:#adadad}.btn-secondary.focus,.btn-secondary:focus{color:#373a3c;background-color:#e6e6e6;border-color:#adadad}.btn-secondary.active,.btn-secondary:active,.open>.btn-secondary.dropdown-toggle{color:#373a3c;background-color:#e6e6e6;background-image:none;border-color:#adadad}.btn-secondary.active.focus,.btn-secondary.active:focus,.btn-secondary.active:hover,.btn-secondary:active.focus,.btn-secondary:active:focus,.btn-secondary:active:hover,.open>.btn-secondary.dropdown-toggle.focus,.open>.btn-secondary.dropdown-toggle:focus,.open>.btn-secondary.dropdown-toggle:hover{color:#373a3c;background-color:#d4d4d4;border-color:#8c8c8c}.btn-secondary.disabled.focus,.btn-secondary.disabled:focus,.btn-secondary:disabled.focus,.btn-secondary:disabled:focus{background-color:#fff;border-color:#ccc}.btn-secondary.disabled:hover,.btn-secondary:disabled:hover{background-color:#fff;border-color:#ccc}.btn-info{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#2aabd2}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#2aabd2}.btn-info.active,.btn-info:active,.open>.btn-info.dropdown-toggle{color:#fff;background-color:#31b0d5;background-image:none;border-color:#2aabd2}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.btn-info.dropdown-toggle.focus,.open>.btn-info.dropdown-toggle:focus,.open>.btn-info.dropdown-toggle:hover{color:#fff;background-color:#269abc;border-color:#1f7e9a}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info:disabled.focus,.btn-info:disabled:focus{background-color:#5bc0de;border-color:#5bc0de}.btn-info.disabled:hover,.btn-info:disabled:hover{background-color:#5bc0de;border-color:#5bc0de}.btn-success{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#419641}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#419641}.btn-success.active,.btn-success:active,.open>.btn-success.dropdown-toggle{color:#fff;background-color:#449d44;background-image:none;border-color:#419641}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.btn-success.dropdown-toggle.focus,.open>.btn-success.dropdown-toggle:focus,.open>.btn-success.dropdown-toggle:hover{color:#fff;background-color:#398439;border-color:#2d672d}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success:disabled.focus,.btn-success:disabled:focus{background-color:#5cb85c;border-color:#5cb85c}.btn-success.disabled:hover,.btn-success:disabled:hover{background-color:#5cb85c;border-color:#5cb85c}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#eb9316}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#eb9316}.btn-warning.active,.btn-warning:active,.open>.btn-warning.dropdown-toggle{color:#fff;background-color:#ec971f;background-image:none;border-color:#eb9316}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.btn-warning.dropdown-toggle.focus,.open>.btn-warning.dropdown-toggle:focus,.open>.btn-warning.dropdown-toggle:hover{color:#fff;background-color:#d58512;border-color:#b06d0f}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning:disabled.focus,.btn-warning:disabled:focus{background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning.disabled:hover,.btn-warning:disabled:hover{background-color:#f0ad4e;border-color:#f0ad4e}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#c12e2a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#c12e2a}.btn-danger.active,.btn-danger:active,.open>.btn-danger.dropdown-toggle{color:#fff;background-color:#c9302c;background-image:none;border-color:#c12e2a}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.btn-danger.dropdown-toggle.focus,.open>.btn-danger.dropdown-toggle:focus,.open>.btn-danger.dropdown-toggle:hover{color:#fff;background-color:#ac2925;border-color:#8b211e}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger:disabled.focus,.btn-danger:disabled:focus{background-color:#d9534f;border-color:#d9534f}.btn-danger.disabled:hover,.btn-danger:disabled:hover{background-color:#d9534f;border-color:#d9534f}.btn-primary-outline{color:#0275d8;background-color:transparent;background-image:none;border-color:#0275d8}.btn-primary-outline.active,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline:focus,.open>.btn-primary-outline.dropdown-toggle{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary-outline:hover{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary-outline.disabled.focus,.btn-primary-outline.disabled:focus,.btn-primary-outline:disabled.focus,.btn-primary-outline:disabled:focus{border-color:#43a7fd}.btn-primary-outline.disabled:hover,.btn-primary-outline:disabled:hover{border-color:#43a7fd}.btn-secondary-outline{color:#ccc;background-color:transparent;background-image:none;border-color:#ccc}.btn-secondary-outline.active,.btn-secondary-outline.focus,.btn-secondary-outline:active,.btn-secondary-outline:focus,.open>.btn-secondary-outline.dropdown-toggle{color:#fff;background-color:#ccc;border-color:#ccc}.btn-secondary-outline:hover{color:#fff;background-color:#ccc;border-color:#ccc}.btn-secondary-outline.disabled.focus,.btn-secondary-outline.disabled:focus,.btn-secondary-outline:disabled.focus,.btn-secondary-outline:disabled:focus{border-color:#fff}.btn-secondary-outline.disabled:hover,.btn-secondary-outline:disabled:hover{border-color:#fff}.btn-info-outline{color:#5bc0de;background-color:transparent;background-image:none;border-color:#5bc0de}.btn-info-outline.active,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline:focus,.open>.btn-info-outline.dropdown-toggle{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info-outline:hover{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info-outline.disabled.focus,.btn-info-outline.disabled:focus,.btn-info-outline:disabled.focus,.btn-info-outline:disabled:focus{border-color:#b0e1ef}.btn-info-outline.disabled:hover,.btn-info-outline:disabled:hover{border-color:#b0e1ef}.btn-success-outline{color:#5cb85c;background-color:transparent;background-image:none;border-color:#5cb85c}.btn-success-outline.active,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline:focus,.open>.btn-success-outline.dropdown-toggle{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success-outline:hover{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success-outline.disabled.focus,.btn-success-outline.disabled:focus,.btn-success-outline:disabled.focus,.btn-success-outline:disabled:focus{border-color:#a3d7a3}.btn-success-outline.disabled:hover,.btn-success-outline:disabled:hover{border-color:#a3d7a3}.btn-warning-outline{color:#f0ad4e;background-color:transparent;background-image:none;border-color:#f0ad4e}.btn-warning-outline.active,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline:focus,.open>.btn-warning-outline.dropdown-toggle{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning-outline:hover{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning-outline.disabled.focus,.btn-warning-outline.disabled:focus,.btn-warning-outline:disabled.focus,.btn-warning-outline:disabled:focus{border-color:#f8d9ac}.btn-warning-outline.disabled:hover,.btn-warning-outline:disabled:hover{border-color:#f8d9ac}.btn-danger-outline{color:#d9534f;background-color:transparent;background-image:none;border-color:#d9534f}.btn-danger-outline.active,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline:focus,.open>.btn-danger-outline.dropdown-toggle{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger-outline:hover{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger-outline.disabled.focus,.btn-danger-outline.disabled:focus,.btn-danger-outline:disabled.focus,.btn-danger-outline:disabled:focus{border-color:#eba5a3}.btn-danger-outline.disabled:hover,.btn-danger-outline:disabled:hover{border-color:#eba5a3}.btn-link{font-weight:400;color:#0275d8;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link:disabled{background-color:transparent}.btn-link,.btn-link:active,.btn-link:focus{border-color:transparent}.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#014c8c;text-decoration:underline;background-color:transparent}.btn-link:disabled:focus,.btn-link:disabled:hover{color:#818a91;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:.75rem 1.25rem;font-size:1.25rem;line-height:1.333333;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .75rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].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}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height;-o-transition-property:height;transition-property:height}.dropdown,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-right:.25rem;margin-left:.25rem;vertical-align:middle;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-left:.3em solid transparent}.dropdown-toggle:focus{outline:0}.dropup .dropdown-toggle::after{border-top:0;border-bottom:.3em solid}.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:1rem;color:#373a3c;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-divider{height:1px;margin:.5rem 0;overflow:hidden;background-color:#e5e5e5}.dropdown-item{display:block;width:100%;padding:3px 20px;clear:both;font-weight:400;line-height:1.5;color:#373a3c;text-align:inherit;white-space:nowrap;background:0 0;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#2b2d2f;text-decoration:none;background-color:#f5f5f5}.dropdown-item.active,.dropdown-item.active:focus,.dropdown-item.active:hover{color:#fff;text-decoration:none;background-color:#0275d8;outline:0}.dropdown-item.disabled,.dropdown-item.disabled:focus,.dropdown-item.disabled:hover{color:#818a91}.dropdown-item.disabled:focus,.dropdown-item.disabled:hover{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:.875rem;line-height:1.5;color:#818a91;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:.3em solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:2}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:2}.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::after{display:table;clear:both;content:""}.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:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-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-lg.btn-group>.btn+.dropdown-toggle,.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn .caret{margin-left:0}.btn-group-lg>.btn .caret,.btn-lg .caret{border-width:.3em .3em 0;border-bottom-width:0}.dropup .btn-group-lg>.btn .caret,.dropup .btn-lg .caret{border-width:0 .3em .3em}.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::after{display:table;clear:both;content:""}.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:.25rem;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:.25rem}.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}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:active,.input-group .form-control:focus,.input-group .form-control:hover{z-index:3}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn: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:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1;color:#55595c;text-align:center;background-color:#eceeef;border:1px solid #ccc;border-radius:.25rem}.input-group-addon.form-control-sm,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:.275rem .75rem;font-size:.875rem;border-radius:.2rem}.input-group-addon.form-control-lg,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:.75rem 1.25rem;font-size:1.25rem;border-radius:.3rem}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{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-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){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:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{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:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:3}.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{z-index:2;margin-left:-1px}.input-group-btn:last-child>.btn-group:active,.input-group-btn:last-child>.btn-group:focus,.input-group-btn:last-child>.btn-group:hover,.input-group-btn:last-child>.btn:active,.input-group-btn:last-child>.btn:focus,.input-group-btn:last-child>.btn:hover{z-index:3}.c-input{position:relative;display:inline;padding-left:1.5rem;color:#555;cursor:pointer}.c-input>input{position:absolute;z-index:-1;opacity:0}.c-input>input:checked~.c-indicator{color:#fff;background-color:#0074d9}.c-input>input:focus~.c-indicator{-webkit-box-shadow:0 0 0 .075rem #fff,0 0 0 .2rem #0074d9;box-shadow:0 0 0 .075rem #fff,0 0 0 .2rem #0074d9}.c-input>input:active~.c-indicator{color:#fff;background-color:#84c6ff}.c-input+.c-input{margin-left:1rem}.c-indicator{position:absolute;top:0;left:0;display:block;width:1rem;height:1rem;font-size:65%;line-height:1rem;color:#eee;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#eee;background-repeat:no-repeat;background-position:center center;-webkit-background-size:50% 50%;background-size:50% 50%}.c-checkbox .c-indicator{border-radius:.25rem}.c-checkbox input:checked~.c-indicator{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgOCA4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA4IDgiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iI0ZGRkZGRiIgZD0iTTYuNCwxTDUuNywxLjdMMi45LDQuNUwyLjEsMy43TDEuNCwzTDAsNC40bDAuNywwLjdsMS41LDEuNWwwLjcsMC43bDAuNy0wLjdsMy41LTMuNWwwLjctMC43TDYuNCwxTDYuNCwxeiINCgkvPg0KPC9zdmc+DQo=)}.c-checkbox input:indeterminate~.c-indicator{background-color:#0074d9;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iOHB4IiBoZWlnaHQ9IjhweCIgdmlld0JveD0iMCAwIDggOCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOCA4IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik0wLDN2Mmg4VjNIMHoiLz4NCjwvc3ZnPg0K)}.c-radio .c-indicator{border-radius:50%}.c-radio input:checked~.c-indicator{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgOCA4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA4IDgiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iI0ZGRkZGRiIgZD0iTTQsMUMyLjMsMSwxLDIuMywxLDRzMS4zLDMsMywzczMtMS4zLDMtM1M1LjcsMSw0LDF6Ii8+DQo8L3N2Zz4NCg==)}.c-inputs-stacked .c-input{display:inline}.c-inputs-stacked .c-input::after{display:block;margin-bottom:.25rem;content:""}.c-inputs-stacked .c-input+.c-input{margin-left:0}.c-select{display:inline-block;max-width:100%;-webkit-appearance:none;padding:.375rem 1.75rem .375rem .75rem;padding-right:.75rem\9;color:#55595c;vertical-align:middle;background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAUCAMAAACzvE1FAAAADFBMVEUzMzMzMzMzMzMzMzMKAG/3AAAAA3RSTlMAf4C/aSLHAAAAPElEQVR42q3NMQ4AIAgEQTn//2cLdRKppSGzBYwzVXvznNWs8C58CiussPJj8h6NwgorrKRdTvuV9v16Afn0AYFOB7aYAAAAAElFTkSuQmCC) no-repeat right .75rem center;background-image:none\9;-webkit-background-size:8px 10px;background-size:8px 10px;border:1px solid #ccc;-moz-appearance:none}.c-select:focus{border-color:#51a7e8;outline:0}.c-select::-ms-expand{opacity:0}.c-select-sm{padding-top:3px;padding-bottom:3px;font-size:12px}.c-select-sm:not([multiple]){height:26px;min-height:26px}.file{position:relative;display:inline-block;height:2.5rem;cursor:pointer}.file input{min-width:14rem;margin:0;filter:alpha(opacity=0);opacity:0}.file-custom{position:absolute;top:0;right:0;left:0;z-index:5;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#555;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#fff;border:1px solid #ddd;border-radius:.25rem}.file-custom::after{content:"Choose file..."}.file-custom::before{position:absolute;top:-.075rem;right:-.075rem;bottom:-.075rem;z-index:6;display:block;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#555;content:"Browse";background-color:#eee;border:1px solid #ddd;border-radius:0 .25rem .25rem 0}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:inline-block}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#818a91}.nav-link.disabled,.nav-link.disabled:focus,.nav-link.disabled:hover{color:#818a91;cursor:not-allowed;background-color:transparent}.nav-inline .nav-item{display:inline-block}.nav-inline .nav-item+.nav-item,.nav-inline .nav-link+.nav-link{margin-left:1rem}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs::after{display:table;clear:both;content:""}.nav-tabs .nav-item{float:left;margin-bottom:-1px}.nav-tabs .nav-item+.nav-item{margin-left:.2rem}.nav-tabs .nav-link{display:block;padding:.5em 1em;border:1px solid transparent;border-radius:.25rem .25rem 0 0}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#eceeef #eceeef #ddd}.nav-tabs .nav-link.disabled,.nav-tabs .nav-link.disabled:focus,.nav-tabs .nav-link.disabled:hover{color:#818a91;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.open .nav-link,.nav-tabs .nav-item.open .nav-link:focus,.nav-tabs .nav-item.open .nav-link:hover,.nav-tabs .nav-link.active,.nav-tabs .nav-link.active:focus,.nav-tabs .nav-link.active:hover{color:#55595c;background-color:#fff;border-color:#ddd #ddd transparent}.nav-pills::after{display:table;clear:both;content:""}.nav-pills .nav-item{float:left}.nav-pills .nav-item+.nav-item{margin-left:.2rem}.nav-pills .nav-link{display:block;padding:.5em 1em;border-radius:.25rem}.nav-pills .nav-item.open .nav-link,.nav-pills .nav-item.open .nav-link:focus,.nav-pills .nav-item.open .nav-link:hover,.nav-pills .nav-link.active,.nav-pills .nav-link.active:focus,.nav-pills .nav-link.active:hover{color:#fff;cursor:default;background-color:#0275d8}.nav-stacked .nav-item{display:block;float:none}.nav-stacked .nav-item+.nav-item{margin-top:.2rem;margin-left:0}.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;padding:.5rem 1rem}.navbar::after{display:table;clear:both;content:""}@media (min-width:544px){.navbar{border-radius:.25rem}}.navbar-full{z-index:1000}@media (min-width:544px){.navbar-full{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:544px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0}.navbar-fixed-bottom{bottom:0}.navbar-sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1030;width:100%}@media (min-width:544px){.navbar-sticky-top{border-radius:0}}.navbar-brand{float:left;padding-top:.25rem;padding-bottom:.25rem;margin-right:1rem;font-size:1.25rem}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}.navbar-divider{float:left;width:1px;padding-top:.425rem;padding-bottom:.425rem;margin-right:1rem;margin-left:1rem;overflow:hidden}.navbar-divider::before{content:"\00a0"}.navbar-toggler{padding:.5rem .75rem;font-size:1.25rem;line-height:1;background:0 0;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}@media (min-width:544px){.navbar-toggleable-xs{display:block!important}}@media (min-width:768px){.navbar-toggleable-sm{display:block!important}}@media (min-width:992px){.navbar-toggleable-md{display:block!important}}.navbar-nav .nav-item{float:left}.navbar-nav .nav-link{display:block;padding-top:.425rem;padding-bottom:.425rem}.navbar-nav .nav-link+.nav-link{margin-left:1rem}.navbar-nav .nav-item+.nav-item{margin-left:1rem}.navbar-light .navbar-brand{color:rgba(0,0,0,.8)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.8)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.6)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .active>.nav-link:focus,.navbar-light .navbar-nav .active>.nav-link:hover,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.active:focus,.navbar-light .navbar-nav .nav-link.active:hover,.navbar-light .navbar-nav .nav-link.open,.navbar-light .navbar-nav .nav-link.open:focus,.navbar-light .navbar-nav .nav-link.open:hover,.navbar-light .navbar-nav .open>.nav-link,.navbar-light .navbar-nav .open>.nav-link:focus,.navbar-light .navbar-nav .open>.nav-link:hover{color:rgba(0,0,0,.8)}.navbar-light .navbar-divider{background-color:rgba(0,0,0,.075)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .active>.nav-link:focus,.navbar-dark .navbar-nav .active>.nav-link:hover,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.active:focus,.navbar-dark .navbar-nav .nav-link.active:hover,.navbar-dark .navbar-nav .nav-link.open,.navbar-dark .navbar-nav .nav-link.open:focus,.navbar-dark .navbar-nav .nav-link.open:hover,.navbar-dark .navbar-nav .open>.nav-link,.navbar-dark .navbar-nav .open>.nav-link:focus,.navbar-dark .navbar-nav .open>.nav-link:hover{color:#fff}.navbar-dark .navbar-divider{background-color:rgba(255,255,255,.075)}.card{position:relative;display:block;margin-bottom:.75rem;background-color:#fff;border:1px solid #e5e5e5;border-radius:.25rem}.card-block{padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card>.list-group:first-child .list-group-item:first-child{border-radius:.25rem .25rem 0 0}.card>.list-group:last-child .list-group-item:last-child{border-radius:0 0 .25rem .25rem}.card-header{padding:.75rem 1.25rem;background-color:#f5f5f5;border-bottom:1px solid #e5e5e5}.card-header:first-child{border-radius:.25rem .25rem 0 0}.card-footer{padding:.75rem 1.25rem;background-color:#f5f5f5;border-top:1px solid #e5e5e5}.card-footer:last-child{border-radius:0 0 .25rem .25rem}.card-primary{background-color:#0275d8;border-color:#0275d8}.card-success{background-color:#5cb85c;border-color:#5cb85c}.card-info{background-color:#5bc0de;border-color:#5bc0de}.card-warning{background-color:#f0ad4e;border-color:#f0ad4e}.card-danger{background-color:#d9534f;border-color:#d9534f}.card-primary-outline{background-color:transparent;border-color:#0275d8}.card-secondary-outline{background-color:transparent;border-color:#ccc}.card-info-outline{background-color:transparent;border-color:#5bc0de}.card-success-outline{background-color:transparent;border-color:#5cb85c}.card-warning-outline{background-color:transparent;border-color:#f0ad4e}.card-danger-outline{background-color:transparent;border-color:#d9534f}.card-inverse .card-footer,.card-inverse .card-header{border-bottom:1px solid rgba(255,255,255,.2)}.card-inverse .card-blockquote,.card-inverse .card-footer,.card-inverse .card-header,.card-inverse .card-title{color:#fff}.card-inverse .card-blockquote>footer,.card-inverse .card-link,.card-inverse .card-text{color:rgba(255,255,255,.65)}.card-inverse .card-link:focus,.card-inverse .card-link:hover{color:#fff}.card-blockquote{padding:0;margin-bottom:0;border-left:0}.card-img{border-radius:.25rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img-top{border-radius:.25rem .25rem 0 0}.card-img-bottom{border-radius:0 0 .25rem .25rem}@media (min-width:544px){.card-deck{display:table;table-layout:fixed;border-spacing:1.25rem 0}.card-deck .card{display:table-cell;width:1%;vertical-align:top}.card-deck-wrapper{margin-right:-1.25rem;margin-left:-1.25rem}}@media (min-width:544px){.card-group{display:table;width:100%;table-layout:fixed}.card-group .card{display:table-cell;vertical-align:top}.card-group .card+.card{margin-left:0;border-left:0}.card-group .card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group .card:first-child .card-img-top{border-top-right-radius:0}.card-group .card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group .card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group .card:last-child .card-img-top{border-top-left-radius:0}.card-group .card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group .card:not(:first-child):not(:last-child){border-radius:0}.card-group .card:not(:first-child):not(:last-child) .card-img-bottom,.card-group .card:not(:first-child):not(:last-child) .card-img-top{border-radius:0}}@media (min-width:544px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#eceeef;border-radius:.25rem}.breadcrumb::after{display:table;clear:both;content:""}.breadcrumb>li{float:left}.breadcrumb>li+li::before{padding-right:.5rem;padding-left:.5rem;color:#818a91;content:"/"}.breadcrumb>.active{color:#818a91}.pagination{display:inline-block;padding-left:0;margin-top:1rem;margin-bottom:1rem;border-radius:.25rem}.page-item{display:inline}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link,.page-item.active .page-link:focus,.page-item.active .page-link:hover{z-index:2;color:#fff;cursor:default;background-color:#0275d8;border-color:#0275d8}.page-item.disabled .page-link,.page-item.disabled .page-link:focus,.page-item.disabled .page-link:hover{color:#818a91;cursor:not-allowed;background-color:#fff;border-color:#ddd}.page-link{position:relative;float:left;padding:.5rem .75rem;margin-left:-1px;line-height:1.5;color:#0275d8;text-decoration:none;background-color:#fff;border:1px solid #ddd}.page-link:focus,.page-link:hover{color:#014c8c;background-color:#eceeef;border-color:#ddd}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.333333}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.275rem .75rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.pager{padding-left:0;margin-top:1rem;margin-bottom:1rem;text-align:center;list-style:none}.pager::after{display:table;clear:both;content:""}.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:focus,.pager li>a:hover{text-decoration:none;background-color:#eceeef}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover{color:#818a91;cursor:not-allowed;background-color:#fff}.pager .disabled>span{color:#818a91;cursor:not-allowed;background-color:#fff}.pager-next>a,.pager-next>span{float:right}.pager-prev>a,.pager-prev>span{float:left}.label{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.label:empty{display:none}.btn .label{position:relative;top:-1px}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.label-default{background-color:#818a91}.label-default[href]:focus,.label-default[href]:hover{background-color:#687077}.label-primary{background-color:#0275d8}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#025aa5}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#eceeef;border-radius:.3rem}@media (min-width:544px){.jumbotron{padding:4rem 2rem}}.jumbotron-hr{border-top-color:#d0d5d8}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{padding:15px;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:35px}.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d0e9c6}.alert-success hr{border-top-color:#c1e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bcdff1}.alert-info hr{border-top-color:#a6d5ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faf2cc}.alert-warning hr{border-top-color:#f7ecb5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebcccc}.alert-danger hr{border-top-color:#e4b9b9}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:block;width:100%;height:1rem;margin-bottom:1rem}.progress[value]{-webkit-appearance:none;color:#0074d9;border:0;-moz-appearance:none;appearance:none}.progress[value]::-webkit-progress-bar{background-color:#eee;border-radius:.25rem}.progress[value]::-webkit-progress-value::before{content:attr(value)}.progress[value]::-webkit-progress-value{background-color:#0074d9;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.progress[value="100"]::-webkit-progress-value{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}@media screen and (min-width:0\0){.progress{background-color:#eee;border-radius:.25rem}.progress-bar{display:inline-block;height:1rem;text-indent:-999rem;background-color:#0074d9;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.progress[width^="0"]{min-width:2rem;color:#818a91;background-color:transparent;background-image:none}.progress[width="100%"]{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}}.progress-striped[value]::-webkit-progress-value{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: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:1rem 1rem;background-size:1rem 1rem}.progress-striped[value]::-moz-progress-bar{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);background-size:1rem 1rem}@media screen and (min-width:0\0){.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:1rem 1rem;background-size:1rem 1rem}}.progress-animated[value]::-webkit-progress-value{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-animated[value]::-moz-progress-bar{animation:progress-bar-stripes 2s linear infinite}@media screen and (min-width:0\0){.progress-animated .progress-bar-striped{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}}.progress-success[value]::-webkit-progress-value{background-color:#5cb85c}.progress-success[value]::-moz-progress-bar{background-color:#5cb85c}@media screen and (min-width:0\0){.progress-success .progress-bar{background-color:#5cb85c}}.progress-info[value]::-webkit-progress-value{background-color:#5bc0de}.progress-info[value]::-moz-progress-bar{background-color:#5bc0de}@media screen and (min-width:0\0){.progress-info .progress-bar{background-color:#5bc0de}}.progress-warning[value]::-webkit-progress-value{background-color:#f0ad4e}.progress-warning[value]::-moz-progress-bar{background-color:#f0ad4e}@media screen and (min-width:0\0){.progress-warning .progress-bar{background-color:#f0ad4e}}.progress-danger[value]::-webkit-progress-value{background-color:#d9534f}.progress-danger[value]::-moz-progress-bar{background-color:#d9534f}@media screen and (min-width:0\0){.progress-danger .progress-bar{background-color:#d9534f}}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right{padding-left:10px}.media-left{padding-right:10px}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:0}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-flush .list-group-item{border-width:1px 0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}a.list-group-item,button.list-group-item{width:100%;color:#555;text-align:inherit}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#818a91;cursor:not-allowed;background-color:#eceeef}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#818a91}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#0275d8;border-color:#0275d8}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#a8d6fe}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{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}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9{padding-bottom:42.857143%}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.embed-responsive-1by1{padding-bottom:100%}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;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:transform .3s ease-out,-o-transform .3s ease-out;transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out,-o-transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(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 rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.in{opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header::after{display:table;clear:both;content:""}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.5}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer::after{display:table;clear:both;content:""}.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:544px){.modal-dialog{width:600px;margin:30px auto}.modal-sm{width:300px}}@media (min-width:768px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:.875rem;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;opacity:0;line-break:auto}.tooltip.in{opacity:.9}.tooltip.bs-tether-element-attached-bottom,.tooltip.tooltip-top{padding:5px 0;margin-top:-3px}.tooltip.bs-tether-element-attached-bottom .tooltip-arrow,.tooltip.tooltip-top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.bs-tether-element-attached-left,.tooltip.tooltip-right{padding:0 5px;margin-left:3px}.tooltip.bs-tether-element-attached-left .tooltip-arrow,.tooltip.tooltip-right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.bs-tether-element-attached-top,.tooltip.tooltip-bottom{padding:5px 0;margin-top:3px}.tooltip.bs-tether-element-attached-top .tooltip-arrow,.tooltip.tooltip-bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bs-tether-element-attached-right,.tooltip.tooltip-left{padding:0 5px;margin-left:-3px}.tooltip.bs-tether-element-attached-right .tooltip-arrow,.tooltip.tooltip-left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:.875rem;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;line-break:auto}.popover.bs-tether-element-attached-bottom,.popover.popover-top{margin-top:-10px}.popover.bs-tether-element-attached-bottom .popover-arrow,.popover.popover-top .popover-arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.bs-tether-element-attached-bottom .popover-arrow::after,.popover.popover-top .popover-arrow::after{bottom:1px;margin-left:-10px;content:"";border-top-color:#fff;border-bottom-width:0}.popover.bs-tether-element-attached-left,.popover.popover-right{margin-left:10px}.popover.bs-tether-element-attached-left .popover-arrow,.popover.popover-right .popover-arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.bs-tether-element-attached-left .popover-arrow::after,.popover.popover-right .popover-arrow::after{bottom:-10px;left:1px;content:"";border-right-color:#fff;border-left-width:0}.popover.bs-tether-element-attached-top,.popover.popover-bottom{margin-top:10px}.popover.bs-tether-element-attached-top .popover-arrow,.popover.popover-bottom .popover-arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-top .popover-arrow::after,.popover.popover-bottom .popover-arrow::after{top:1px;margin-left:-10px;content:"";border-top-width:0;border-bottom-color:#fff}.popover.bs-tether-element-attached-right,.popover.popover-left{margin-left:-10px}.popover.bs-tether-element-attached-right .popover-arrow,.popover.popover-left .popover-arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-right .popover-arrow::after,.popover.popover-left .popover-arrow::after{right:1px;bottom:-10px;content:"";border-right-width:0;border-left-color:#fff}.popover-title{padding:8px 14px;margin:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:-.7rem -.7rem 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}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.carousel-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>.carousel-item>a>img,.carousel-inner>.carousel-item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.carousel-item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:transform .6s ease-in-out,-o-transform .6s ease-in-out;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out,-o-transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.carousel-item.active.right,.carousel-inner>.carousel-item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.carousel-item.active.left,.carousel-inner>.carousel-item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.carousel-item.active,.carousel-inner>.carousel-item.next.left,.carousel-inner>.carousel-item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.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);opacity:.5}.carousel-control.left{background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));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: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-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));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: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:focus,.carousel-control:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .icon-next{right:50%;margin-right:-10px}.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:transparent;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 (min-width:544px){.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .icon-prev{margin-left:-15px}.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix::after{display:table;clear:both;content:""}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-xs-left{float:left!important}.pull-xs-right{float:right!important}.pull-xs-none{float:none!important}@media (min-width:544px){.pull-sm-left{float:left!important}.pull-sm-right{float:right!important}.pull-sm-none{float:none!important}}@media (min-width:768px){.pull-md-left{float:left!important}.pull-md-right{float:right!important}.pull-md-none{float:none!important}}@media (min-width:992px){.pull-lg-left{float:left!important}.pull-lg-right{float:right!important}.pull-lg-none{float:none!important}}@media (min-width:1200px){.pull-xl-left{float:left!important}.pull-xl-right{float:right!important}.pull-xl-none{float:none!important}}.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}.invisible{visibility:hidden!important}.text-hide{font:"0/0" a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-xs-left{text-align:left!important}.text-xs-right{text-align:right!important}.text-xs-center{text-align:center!important}@media (min-width:544px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-normal{font-weight:400}.font-weight-bold{font-weight:700}.font-italic{font-style:italic}.text-muted{color:#818a91}.text-primary{color:#0275d8!important}a.text-primary:focus,a.text-primary:hover{color:#025aa5}.text-success{color:#5cb85c!important}a.text-success:focus,a.text-success:hover{color:#449d44}.text-info{color:#5bc0de!important}a.text-info:focus,a.text-info:hover{color:#31b0d5}.text-warning{color:#f0ad4e!important}a.text-warning:focus,a.text-warning:hover{color:#ec971f}.text-danger{color:#d9534f!important}a.text-danger:focus,a.text-danger:hover{color:#c9302c}.bg-inverse{color:#eceeef;background-color:#373a3c}.bg-faded{background-color:#f7f7f9}.bg-primary{color:#fff!important;background-color:#0275d8!important}a.bg-primary:focus,a.bg-primary:hover{background-color:#025aa5}.bg-success{color:#fff!important;background-color:#5cb85c!important}a.bg-success:focus,a.bg-success:hover{background-color:#449d44}.bg-info{color:#fff!important;background-color:#5bc0de!important}a.bg-info:focus,a.bg-info:hover{background-color:#31b0d5}.bg-warning{color:#fff!important;background-color:#f0ad4e!important}a.bg-warning:focus,a.bg-warning:hover{background-color:#ec971f}.bg-danger{color:#fff!important;background-color:#d9534f!important}a.bg-danger:focus,a.bg-danger:hover{background-color:#c9302c}.m-x-auto{margin-right:auto!important;margin-left:auto!important}.m-a-0{margin:0 0!important}.m-t-0{margin-top:0!important}.m-r-0{margin-right:0!important}.m-b-0{margin-bottom:0!important}.m-l-0{margin-left:0!important}.m-x-0{margin-right:0!important;margin-left:0!important}.m-y-0{margin-top:0!important;margin-bottom:0!important}.m-a-1{margin:1rem 1rem!important}.m-t-1{margin-top:1rem!important}.m-r-1{margin-right:1rem!important}.m-b-1{margin-bottom:1rem!important}.m-l-1{margin-left:1rem!important}.m-x-1{margin-right:1rem!important;margin-left:1rem!important}.m-y-1{margin-top:1rem!important;margin-bottom:1rem!important}.m-a-2{margin:1.5rem 1.5rem!important}.m-t-2{margin-top:1.5rem!important}.m-r-2{margin-right:1.5rem!important}.m-b-2{margin-bottom:1.5rem!important}.m-l-2{margin-left:1.5rem!important}.m-x-2{margin-right:1.5rem!important;margin-left:1.5rem!important}.m-y-2{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-a-3{margin:3rem 3rem!important}.m-t-3{margin-top:3rem!important}.m-r-3{margin-right:3rem!important}.m-b-3{margin-bottom:3rem!important}.m-l-3{margin-left:3rem!important}.m-x-3{margin-right:3rem!important;margin-left:3rem!important}.m-y-3{margin-top:3rem!important;margin-bottom:3rem!important}.p-a-0{padding:0 0!important}.p-t-0{padding-top:0!important}.p-r-0{padding-right:0!important}.p-b-0{padding-bottom:0!important}.p-l-0{padding-left:0!important}.p-x-0{padding-right:0!important;padding-left:0!important}.p-y-0{padding-top:0!important;padding-bottom:0!important}.p-a-1{padding:1rem 1rem!important}.p-t-1{padding-top:1rem!important}.p-r-1{padding-right:1rem!important}.p-b-1{padding-bottom:1rem!important}.p-l-1{padding-left:1rem!important}.p-x-1{padding-right:1rem!important;padding-left:1rem!important}.p-y-1{padding-top:1rem!important;padding-bottom:1rem!important}.p-a-2{padding:1.5rem 1.5rem!important}.p-t-2{padding-top:1.5rem!important}.p-r-2{padding-right:1.5rem!important}.p-b-2{padding-bottom:1.5rem!important}.p-l-2{padding-left:1.5rem!important}.p-x-2{padding-right:1.5rem!important;padding-left:1.5rem!important}.p-y-2{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-a-3{padding:3rem 3rem!important}.p-t-3{padding-top:3rem!important}.p-r-3{padding-right:3rem!important}.p-b-3{padding-bottom:3rem!important}.p-l-3{padding-left:3rem!important}.p-x-3{padding-right:3rem!important;padding-left:3rem!important}.p-y-3{padding-top:3rem!important;padding-bottom:3rem!important}.pos-f-t{position:fixed;top:0;right:0;left:0;z-index:1030}.hidden-xs-up{display:none!important}@media (max-width:543px){.hidden-xs-down{display:none!important}}@media (min-width:544px){.hidden-sm-up{display:none!important}}@media (max-width:767px){.hidden-sm-down{display:none!important}}@media (min-width:768px){.hidden-md-up{display:none!important}}@media (max-width:991px){.hidden-md-down{display:none!important}}@media (min-width:992px){.hidden-lg-up{display:none!important}}@media (max-width:1199px){.hidden-lg-down{display:none!important}}@media (min-width:1200px){.hidden-xl-up{display:none!important}}.hidden-xl-down{display:none!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}} 6 | /*# sourceMappingURL=bootstrap.min.css.map */ -------------------------------------------------------------------------------- /src/client/assets/styles/styles.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background: #f1f1f1; 3 | padding-top: 30px; 4 | } 5 | -------------------------------------------------------------------------------- /src/client/scripts/development.js: -------------------------------------------------------------------------------- 1 | // Load CSS via Webpack to be able to require Bootstrap, Font Awesome, etc. from npm 2 | require('styles/styles.scss'); 3 | 4 | // JavaScript main file 5 | require('javascripts/app'); 6 | -------------------------------------------------------------------------------- /src/client/scripts/production.js: -------------------------------------------------------------------------------- 1 | // Expose Raven 2 | window.Raven = require('raven-js'); 3 | 4 | // Load CSS via Webpack to be able to require Bootstrap, Font Awesome, etc. from npm 5 | require('styles/styles.scss'); 6 | 7 | // JavaScript main file 8 | require('javascripts/app'); 9 | -------------------------------------------------------------------------------- /test/e2e/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicksp/redux-webpack-es6-boilerplate/3383b0dc44f125fbaf513079b3e8b96ae13c6ac0/test/e2e/.gitkeep -------------------------------------------------------------------------------- /test/unit/actions/FriendsActionsSpec.js: -------------------------------------------------------------------------------- 1 | import { expect } from '../testHelper'; 2 | import * as types from '../../../src/js/constants/ActionTypes'; 3 | import { addFriend, deleteFriend, starFriend } from '../../../src/js/actions/FriendsActions'; 4 | 5 | describe('Actions', () => { 6 | 7 | describe('addFriend', () => { 8 | 9 | it('has the correct type', () => { 10 | const action = addFriend(); 11 | expect(action.type).to.equal(types.ADD_FRIEND); 12 | }); 13 | 14 | it('has the correct payload', () => { 15 | const action = addFriend('Eminem'); 16 | expect(action.name).to.equal('Eminem'); 17 | }); 18 | }); 19 | 20 | describe('deleteFriend', () => { 21 | 22 | it('has the correct type', () => { 23 | const action = deleteFriend(); 24 | expect(action.type).to.equal(types.DELETE_FRIEND); 25 | }); 26 | 27 | it('has the correct payload', () => { 28 | const action = deleteFriend(0); 29 | expect(action.id).to.equal(0); 30 | }); 31 | }); 32 | 33 | describe('starFriend', () => { 34 | 35 | it('has the correct type', () => { 36 | const action = starFriend(); 37 | expect(action.type).to.equal(types.STAR_FRIEND); 38 | }); 39 | 40 | it('has the correct payload', () => { 41 | const action = starFriend(1); 42 | expect(action.id).to.equal(1); 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/unit/containers/FriendListAppSpec.js: -------------------------------------------------------------------------------- 1 | import { renderComponent, expect } from '../testHelper'; 2 | import FriendListApp from '../../../src/js/containers/FriendListApp/FriendListApp'; 3 | 4 | describe('FriendListApp', () => { 5 | 6 | let component; 7 | 8 | beforeEach(() => { 9 | component = renderComponent(FriendListApp); 10 | }); 11 | 12 | it('shows an input to add a new friend', () => { 13 | expect(component.find('.addFriendInput')).to.exist; 14 | }); 15 | 16 | it('shows a friend list', () => { 17 | expect(component.find('.friendList')).to.exist; 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /test/unit/cssNullCompiler.js: -------------------------------------------------------------------------------- 1 | function noop() { 2 | return null; 3 | } 4 | 5 | require.extensions['.styl'] = noop; 6 | require.extensions['.scss'] = noop; 7 | require.extensions['.less'] = noop; 8 | require.extensions['.jpg'] = noop; 9 | require.extensions['.png'] = noop; 10 | require.extensions['.woff'] = noop; 11 | -------------------------------------------------------------------------------- /test/unit/testHelper.js: -------------------------------------------------------------------------------- 1 | import jq from 'jquery'; 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import ReactTestUtils from 'react-addons-test-utils'; 5 | import jsdom from 'jsdom'; 6 | import chai, { expect } from 'chai'; 7 | import chaiJquery from 'chai-jquery'; 8 | import createHistory from 'react-router/lib/browserHistory'; 9 | import { Provider } from 'react-redux'; 10 | import { createStore } from 'redux'; 11 | import reducers from '../../src/js/reducers'; 12 | 13 | // Global prerequisites to make it work in the command line 14 | global.document = jsdom.jsdom(''); 15 | global.window = global.document.defaultView; 16 | const $ = jq(window); 17 | 18 | // Set up chai-jquery 19 | chaiJquery(chai, chai.util, $); 20 | 21 | function renderComponent(ComponentClass, props = {}, state = {}) { 22 | const componentInstance = ReactTestUtils.renderIntoDocument( 23 | 24 | 25 | 26 | ); 27 | 28 | // Produces HTML 29 | return $(ReactDOM.findDOMNode(componentInstance)); 30 | } 31 | 32 | function mockHistory(component) { 33 | component.childContextTypes = { history: React.PropTypes.object }; 34 | component.prototype.getChildContext = () => ({ history: createHistory() }); 35 | } 36 | 37 | // Helper for simulating events 38 | $.fn.simulate = function(eventName, value) { 39 | if (value) { 40 | this.val(value); 41 | } 42 | ReactTestUtils.Simulate[eventName](this[0]); 43 | }; 44 | 45 | export { renderComponent, mockHistory, expect }; 46 | --------------------------------------------------------------------------------