├── .gitignore ├── changelog.txt ├── dashboard.package ├── license.txt ├── make.bat ├── make.sh ├── readme.md └── source ├── css ├── default.css ├── spa.min@18.css ├── ui.css └── ui.extras.css ├── fonts ├── fa-brands-400.eot ├── fa-brands-400.svg ├── fa-brands-400.ttf ├── fa-brands-400.woff ├── fa-brands-400.woff2 ├── fa-regular-400.eot ├── fa-regular-400.svg ├── fa-regular-400.ttf ├── fa-regular-400.woff ├── fa-regular-400.woff2 ├── fa-solid-900.eot ├── fa-solid-900.svg ├── fa-solid-900.ttf ├── fa-solid-900.woff └── fa-solid-900.woff2 ├── index.html ├── index.js ├── js ├── default.js ├── spa.min@18.js ├── ui.extras.js └── ui.js └── templates ├── form-components.html ├── form-database.html ├── form-tab.html └── form-widgets.html /.gitignore: -------------------------------------------------------------------------------- 1 | sftp-config.json 2 | /logs/ 3 | /tmp/ 4 | dependencies 5 | /public/iot/ 6 | /public/private/ 7 | /public/superadmin/ 8 | /public/server/ 9 | -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | ======= 7.0.0 2 | 3 | - updated jComponent to v18 4 | - updated UI components 5 | - updated FontAwesome to v5 6 | - added delegates for saving designer.json 7 | 8 | ======= 4.0.0 9 | 10 | - updated jComponent version 11 | - updated UI components -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | Copyright 2012-2018 (c) Peter Širka 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to permit 9 | persons to whom the Software is furnished to do so, subject to the 10 | following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 18 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 | USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | ECHO OFF 2 | SETLOCAL ENABLEEXTENSIONS 3 | SET parent=%~dp0 4 | SET name=dashboard.package 5 | 6 | cd source 7 | total4 --package %parent%%name% 8 | MOVE %name% ../ -------------------------------------------------------------------------------- /make.sh: -------------------------------------------------------------------------------- 1 | NAME=`basename "$PWD"`.package 2 | 3 | cd source 4 | total4 --package "$NAME" 5 | mv "$NAME" ../ 6 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Total.js Dashboard 2 | 3 | [![Support](https://www.totaljs.com/img/button-support.png?v=2)](https://www.totaljs.com/support/) 4 | 5 | __Total.js Dashboard__ `v7.0.0` is dashboard for __IoT__ and [Total.js Flow](https://www.totaljs.com/flow/). 6 | 7 | ## Installation 8 | 9 | - Total.js `+v3.3.0` 10 | - Flow `+v5.0.0` 11 | - download and copy `dashboard.package` into the `/packages/` directory __or create a definition file with:__ 12 | 13 | ```javascript 14 | var options = {}; 15 | 16 | // ==================================== 17 | // COMMON (OPTIONAL) 18 | // ==================================== 19 | 20 | // options.url = '/$dashboard/'; 21 | 22 | // A maximum length of request: 23 | // options.limit = 50; 24 | 25 | // Predefined set of components (default value): 26 | // options.templates = 'https://raw.githubusercontent.com/totaljs/dashboardcomponents/master/templates.json'; 27 | 28 | // ==================================== 29 | // Security (OPTIONAL) 30 | // ==================================== 31 | 32 | // +v6.0.0 33 | // Default light theme 34 | // options.dark = false; 35 | 36 | // +v6.0.0 37 | // Enables backing up of Dashboard designer 38 | // options.backup = true; 39 | // default: false 40 | 41 | // +v6.0.0 42 | // Enables link to Flow (if exists) in context menu 43 | // options.flow = true; 44 | // default: true 45 | 46 | // +v6.0.0 47 | // Enables link to Flowboard (if exists) in context menu 48 | // options.flowboard = true; 49 | // default: true 50 | 51 | // HTTP Basic auth: 52 | // options.auth = ['admin:admin', 'name:password']; 53 | 54 | // Standard "authorize" flag 55 | // options.auth = true; 56 | 57 | // IP restrictions: 58 | // options.restrictions = ['127.0.0.1', '138.201', '172.31.33']; 59 | 60 | // options.token = ['OUR_COMPANY_TOKEN']; 61 | // you can open dashboard using : /$dashboard/?token=OUR_COMPANY_TOKEN 62 | 63 | INSTALL('package', 'https://cdn.totaljs.com/dashboard.package', options); 64 | ``` 65 | 66 | - __IMPORTANT__: it doesn't support `UPTODATE` mechanism 67 | - URL address `http://127.0.0.1:8000/$dashboard/` (default, can be changed in config) 68 | - __first start__ you have to install components via Component manager in `Dashboard` 69 | 70 | ## How to create own component? 71 | 72 | ### Dashboard (client-side) 73 | 74 | ```html 75 | 76 | 81 | 82 | 83 | 86 | 87 | 88 | 91 | 92 | 93 | 243 | ``` 244 | 245 | __Common variables (client-side)__: 246 | 247 | ```javascript 248 | common.instances; 249 | // {Object Array} All Flow instances 250 | 251 | DEBUG; 252 | // {Boolean} Determines component's maker 253 | 254 | RELEASE; 255 | // {Boolean} Determines dashboard 256 | 257 | Icons; 258 | // {Object} Contains Font-Awesome UTF-8 chars for SVG images 259 | // +v6.0.0 260 | ``` 261 | 262 | __Common methods (client-side)__: 263 | 264 | ```javascript 265 | common.operations.emit(event_name, [arg1], [arg2], [argN]); 266 | // Emits an event in all components 267 | ``` 268 | 269 | __Good to know__: 270 | 271 | - each Dashboard element is wrapped to `data-jc-scope=""` (generated randomly) 272 | 273 | ### Flow (server-side) 274 | 275 | Each Flow component connected to Dashboard component can define this code: 276 | 277 | ```javascript 278 | // (Optional) This method sends data to Dashboard component (server-side to client-side) 279 | instance.dashboard(type, data); 280 | 281 | // (Optional) This event captures data from Dashboard component 282 | instance.on('dashboard', function(type, data) { 283 | 284 | }); 285 | ``` 286 | 287 | ## Client-Side 288 | 289 | ### Events 290 | 291 | ```javascript 292 | ON('open.componentname', function(component, options) { 293 | // Settings will be open 294 | }); 295 | 296 | ON('save.componentname', function(component, options) { 297 | // Settings will be save 298 | }); 299 | 300 | ON('apply', function() { 301 | // Designer will be sent to server 302 | }); 303 | ``` 304 | 305 | ### Components: jComponent +v14.5.0 306 | 307 | Bellow jComponents can be used in `Settings form`: 308 | 309 | - autocomplete (declared `body`) 310 | - binder (declared in `body`) 311 | - calendar (declared in `body`) 312 | - checkbox 313 | - checkboxlist 314 | - codemirror 315 | - colorpicker (declared in `body`) 316 | - confirm (declared in `body`) 317 | - contextmenu (declared in `body`) 318 | - dropdown 319 | - dropdowncheckbox 320 | - error 321 | - exec (declared in `body`) 322 | - form 323 | - importer 324 | - keyvalue 325 | - loading 326 | - message (declared in `body`) 327 | - nosqlcounter 328 | - repeater 329 | - repeater-group 330 | - search 331 | - selectbox 332 | - textbox 333 | - textboxlist 334 | - validation 335 | - visible 336 | - multioptions 337 | - dragdropfiles 338 | - filereader 339 | 340 | __References:__ 341 | 342 | - [Componentator.com](https://componentator.com/) 343 | - [jComponents on Github](https://github.com/totaljs/jComponent) 344 | 345 | ## Components 346 | 347 | - https://github.com/totaljs/dashboardcomponents 348 | -------------------------------------------------------------------------------- /source/css/default.css: -------------------------------------------------------------------------------- 1 | /*auto*/ 2 | 3 | html,body { height: 100%; margin: 0; padding: 0; } 4 | body { background-color: #F0F0F0; font-smoothing: antialiased; color: #505050; } 5 | /*.ui-dark { color: #A0A0A0; background-color: #202020; }*/ 6 | 7 | .noscroll { overflow: hidden; } 8 | 9 | #success { height: 40px; top: 50px; left: 240px; width: 40px; background-color: #8CC152; font-size: 25px; line-height: 0; position: fixed; z-index: 20; color: white; text-align: center; padding: 8px 0 0 1px; display: none; transition: all 0.4s; z-index: 1000; border-radius: 4px; box-shadow: 0 2px 10px rgba(0,0,0,0.3); } 10 | .success-animation { transform: scale(2) translate(0, 50px); } 11 | .success { background-color: #8CC152; text-align: center; padding: 8px 10px; font-size: 12px; color: white; } 12 | .success .fa { margin-right: 5px; } 13 | 14 | figure > header { height: 34px; border-bottom: 1px solid #E0E0E0; font-size: 12px; color: black; } 15 | figure > header label { float: left; margin: 8px 0 0 10px; font-weight: bold; max-width: 50%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } 16 | figure > header button { float: right; background-color: transparent; border-radius: 0; border: 0; border-left: 1px solid #E0E0E0; height: 20px; min-width: 28px; margin: 7px 0 0 0; color: #A0A0A0; outline: 0; padding: 0; } 17 | figure > header button:hover { color: black; } 18 | figure > header button.selected { color: black; } 19 | 20 | .ui-dark figure > header { border-bottom-color: #404040; color: white; } 21 | .ui-dark figure > header button { color: #555555; border-left-color: #404040; } 22 | .ui-dark figure > header button.selected { color: white; } 23 | .ui-dark figure > header button:hover { color: white; } 24 | 25 | .draft .mainmenu { color: #E33733; } 26 | 27 | .padding { padding: 25px; } 28 | .m { margin-bottom: 20px; } 29 | .cl { clear: both; } 30 | .center { text-align: center; } 31 | 32 | .npb { padding-bottom: 0; } 33 | .npt { padding-top: 0; } 34 | .nmt { margin-top: 0; } 35 | .nmb { margin-bottom: 0; } 36 | .mr5 { margin-right: 5px; } 37 | .b { font-weight: bold; } 38 | .black { color: black; } 39 | .ui-dark .black { color: #c4bebe; } 40 | 41 | .left { text-align: left !important; } 42 | .right { text-align: right !important; } 43 | .center { text-align: center !important; } 44 | 45 | .toolbar { left: 0; top: 0; width: 100%; height: 50px; background-color: #E7E9ED; box-shadow: 0 2px 10px rgba(0,0,0,0.05); z-index: 5; position: fixed; border-bottom: 1px solid #D9D9D9; } 46 | .ui-dark .toolbar { background-color: #101010; box-shadow: inset 0 2px 10px rgba(255,255,255,0.04), 0 2px 10px rgba(0,0,0,0.2); } 47 | .toolbar .tabs { margin: 0; } 48 | .toolbar .tabs a { position: relative; display: inline-block; padding: 14px 10px 0; height: 49px; color: gray; border-right: 1px solid #D9D9D9; font-size: 14px; outline: 0; min-width: 90px; text-align: center; max-width: 120px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } 49 | .toolbar .tabs div { position: relative; display: inline-block; } 50 | .toolbar .tabs .last { display: none; } 51 | .draft .toolbar .tabs .last { display: inline-block; min-width: 40px; border-right: 0; } 52 | .toolbar .tabs a:hover { text-decoration: none; color: black; } 53 | .toolbar .tabs a.selected { background-color: white; color: black; } 54 | 55 | .ui-dark .toolbar { border-bottom-color: #252525; } 56 | .ui-dark .toolbar .tabs a { border-color: #202020; } 57 | .ui-dark .toolbar .tabs a:hover { color: white; } 58 | .ui-dark .toolbar .tabs a.selected { background-color: #323232; color: white; } 59 | 60 | .toolbar .tabs a.mainmenu { min-width: 49px; padding-top: 12px; font-size: 19px; color: black; opacity: 0.8; transition: all 0.3s; } 61 | .toolbar .tabs a.mainmenu:hover { color: black; opacity: 1; } 62 | .toolbar .tabs a.mainmenu .fa-spin { color: black; opacity: 1; } 63 | 64 | .ui-dark .toolbar .tabs a.mainmenu { color: #E0E0E0; } 65 | .ui-dark .toolbar .tabs a.mainmenu:hover { color: white; } 66 | .ui-dark .toolbar .tabs a.mainmenu .fa-spin { color: white; } 67 | 68 | .mainmenu.highlight { color: white !important; background-color: silver; font-weight: bold; text-shadow: 1px 1px 1px rgba(0,0,0,0.1); } 69 | .mainmenu.blink { animation: blinker 0.5s infinite alternate; background-color: #8CC152 !important; } 70 | @keyframes blinker { 71 | 0% { background-color: #9BD15F; } 72 | 100% { background-color: #78AD3E; } 73 | } 74 | 75 | .link .fa { margin-right: 5px; } 76 | .red { color: #E33733; } 77 | 78 | .mt5 { margin-top: 5px; } 79 | .mt10 { margin-top: 10px; } 80 | .help { margin-top: 5px; font-size: 11px; color: #A0A0A0; } 81 | .help code { font: normal normal 11px Arial; background-color: #F0F0F0; padding: 1px 5px; border-radius: 4px; } 82 | .help .fa { margin-right: 5px; } 83 | .fs12 { font-size: 12px; line-height: 15px; } 84 | 85 | .designer-container { position: absolute; width: 100%; height: 100%; left: 0; top: 0px; right: 0; bottom: 0; overflow: hidden; padding-top: 50px; } 86 | .designer-scroll { width: 100%; height: 100%; overflow-y: scroll; overflow-scrolling: touch; } 87 | .designer { background-color: #F0F0F0; position: relative; margin: 30px 0; } 88 | .ui-dark .cell.selected > div { background-color: black; } 89 | .ui-dark .designer { background-color: #202020; } 90 | 91 | .grid { line-height: 0; padding-bottom: 50px; margin-bottom: 50px; display: table; width: 100%; } 92 | .cell { float: left; display: none; width: 47.5px; height: 47.5px; background-color: #E0E0E0; border: 1px solid #D0D0D0; user-select: none; line-height: 0; } 93 | .container-fluid .cell { width: 4.1667%; } 94 | .grid.moving .cell:hover {background-color: lightgrey !important;} 95 | .grid.moving .widget {pointer-events: none;} 96 | .grid.moving .drag {pointer-events: none;} 97 | .ui-dark .cell { background-color: #171717; border: 1px solid #202020; } 98 | .draft .cell { display: block; } 99 | 100 | .grid .cell.selected { background-color: white; } 101 | .ui-dark .grid .cell.selected { background-color: #303030; } 102 | .ui-dark .ui-form-container { color: #505050; } 103 | 104 | .widgets { position: relative; } 105 | .widget { position: absolute; z-index: 2; padding: 10px; } 106 | .widget_offset { position: absolute; z-index: 1; height: 1px; width: 1px; } 107 | .widget-toolbar { position: absolute; left: 0; top: 0; height: 100%; width: 100%; text-align: center; margin: 0; display: none; z-index: 10; padding-top: 15px; } 108 | .widget-toolbar button { background-color: white; box-shadow: 0 0 5px rgba(0,0,0,0.1); border: 1px solid black; font-size: 16px; width: 30px; height: 30px; border-radius: 3px; cursor: pointer; outline: 0; text-align: center; line-height: 16px; padding: 0; position: absolute; left: 20px; top: 20px; } 109 | .widget-toolbar button .fa { margin: 0; } 110 | .ui-dark .widget-toolbar button { background-color: #505050; color: white; } 111 | .draft .widget-toolbar { display: block; } 112 | .widget-body { height: 100%; background-color: white; box-shadow: 0px 3px 10px 1px rgba(0,0,0,0.02); overflow: hidden; } 113 | .ui-dark .widget-body { background-color: #303030; box-shadow: 0px 3px 10px 1px rgba(0, 0, 0, 0.05); } 114 | .widget-body > figure { height: 100%; } 115 | .widget-body.transparent { background-color: transparent !important; box-shadow: none !important; } 116 | .draft .widget-body { background-color: white; box-shadow: 0px 3px 10px 1px rgba(0,0,0,0.05); } 117 | .draft.ui-dark .widget-body { background-color: #303030; box-shadow: 0px 3px 5px 1px rgba(0,0,0,0.1); } 118 | 119 | .help { margin-top: 5px; font-size: 11px; color: #A0A0A0; } 120 | .help code { font: normal normal 11px Arial; background-color: #F0F0F0; padding: 1px 5px; border-radius: 4px; } 121 | .help .fa { margin-right: 5px; } 122 | 123 | .db-container { margin: 0 -10px; } 124 | .db-norefresh .db-refresh { display: none; } 125 | .db-item { position: relative; display: inline-block; background-color: white; border: 2px solid #E0E0E0; padding: 4px 10px; width: 205px; margin: 10px 10px 5px; border-radius: 3px; } 126 | .db-item > span { float: right; width: 20px; text-align: right; margin: 0; cursor: pointer; color: #E33733; } 127 | .db-item > span .fa-refresh { color: #909090; } 128 | .db-item > span:hover { opacity: 0.8; } 129 | .db-item > div { margin-right: 20px; width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } 130 | .db-item .canupdate { display: none; color: red; } 131 | .db-item-update { border-color: #70B348; border-style: dashed; } 132 | .db-item-update .canupdate { display: inline-block; } 133 | .db-item .name { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #505050; } 134 | .db-item .author { font-size: 11px; color: gray; } 135 | .db-item .version { font-size: 11px; } 136 | .db-item .version b { font-size: 10px; text-transform: uppercase; margin-left: 5px; } 137 | .db-category { font-size: 16px; color: black; margin: 15px 10px 5px; font-weight: bold; border-bottom: 1px solid black; padding: 5px 0; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } 138 | .db-category .fa { margin-right: 8px; } 139 | .db-item .datetime { font-size: 11px; color: #A0A0A0; } 140 | .db-item .datetime .fa { margin-right: 5px; } 141 | .ui-dark .db-item { background-color: #333333; border: 1px solid #000000; } 142 | .ui-dark .db-item .name { color: #c7c7c7; } 143 | .ui-dark .db-category { border-bottom: 1px solid #444444; color: #c7c7c7; } 144 | 145 | .db-widget { position: relative; display: inline-block; background-color: white; border: 1px solid #E0E0E0; padding: 8px 10px 8px 0; width: 204px; margin: 10px 10px 5px; border-radius: 3px; cursor: pointer; } 146 | .db-widget > span { float: left; width: 40px; text-align: center; margin: 0; cursor: pointer; color: #A0A0A0; border-right: 1px solid #E0E0E0; font-size: 20px; } 147 | .db-widget > div { float: left; margin-left: 10px; width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 14px; } 148 | .db-widget .name { font-size: 14px; font-weight: bold; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #505050; } 149 | .db-widget .author { font-size: 11px; color: gray; } 150 | .db-widget:hover { background-color: #F0F0F0; } 151 | .ui-dark .db-widget { background-color: #333333; border: 1px solid #000000; } 152 | .ui-dark .db-widget:hover { background-color: #191919; } 153 | .ui-dark .db-widget .name { color: #c7c7c7; } 154 | 155 | .bg-fade { background: linear-gradient(#F8F8F8, white); border-bottom: 1px solid #F0F0F0; margin-bottom: 5px; padding-bottom: 7px !important; } 156 | .bg-smoke { background-color: #F8F8F8; } 157 | .bg-yellow { background-color: #FFFFD5; } 158 | 159 | .tag { position: relative; display: inline-block; padding: 5px 10px; margin: 0 8px 8px 0; background-color: #3BAFDA; color: white; text-decoration: none; border-radius: 3px; font-size: 12px; cursor: pointer; line-height: 14px; } 160 | .tag:hover { opacity: 0.8; text-decoration: none; } 161 | .tag2 { background-color: #165b7b; } 162 | .block { display: block; } 163 | 164 | .resize { position:absolute; color:white; right:13px; bottom:13px; cursor:se-resize; width:20px; height: 20px; border-style: solid; border-width: 0 3px 3px 0px; border-color: #a9a9a9; } 165 | .move { position: absolute; top: 0; left: 0; right: 0; bottom: 0; cursor: move; } 166 | 167 | .devicetype { display: none; } 168 | .draft .devicetype { display: block; width: 200px; margin: 20px auto 10px; text-align: center; background-color: #fff; border-radius: 2px; box-shadow: 0px 5px 20px 1px rgba(0,0,0,0.1); } 169 | .ui-dark.draft .devicetype { background-color: #0F0F0F; } 170 | 171 | @media(max-width: 1199px) { 172 | .cell { width: 78.3px; height: 78.3px; } 173 | } 174 | 175 | @media(max-width: 991px) { 176 | .cell { width: 59.9px; height: 59.9px; } 177 | } 178 | 179 | @media(max-width: 768px) { 180 | .widget { padding: 8px !important; } 181 | .cell { width: 8.3%; height: auto; } 182 | .toolbar .tabs a { padding-left: 5px; padding-right: 5px; max-width: 100px; min-width: 60px; font-size: 11px; } 183 | .designer > .container { padding-left: 4px; padding-right: 4px; } 184 | .designer { margin: 12px 0; } 185 | } 186 | -------------------------------------------------------------------------------- /source/css/spa.min@18.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Build 17.000 3 | * Bootstrap v3.3.1 4 | * Copyright 2011-2014 Twitter, Inc. 5 | * Licensed under MIT 6 | * ---- 7 | * normalize.css v3.0.2 | MIT License 8 | * ---- 9 | * Font Awesome Free 5.1.0 by @fontawesome - https://fontawesome.com 10 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 11 | */ 12 | html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0;font-smoothing:antialiased;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:antialiased}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,a:hover{outline:0;text-decoration:underline}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{border-radius:0;outline:0;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{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a,.link{color:#337ab7;cursor:pointer;text-decoration:none}.link:hover{text-decoration:underline}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;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}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media(min-width:768px){.container{width:750px}}@media(min-width:992px){.container{width:970px}}@media(min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:rgba(255,255,255,.075)!important}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}.clearfix:before,.clearfix:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after{content:" ";display:table}.clearfix:after,.container:after,.container-fluid:after,.row:after{clear:both}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(max-width:767px){.visible-xs-block{display:block!important}}@media(max-width:767px){.visible-xs-inline{display:inline!important}}@media(max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media(min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media(min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media(min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media(min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media(min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media(min-width:1200px){.visible-lg-block{display:block!important}}@media(min-width:1200px){.visible-lg-inline{display:inline!important}}@media(min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media(max-width:767px){.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}input::-ms-clear{display:none}input:invalid{box-shadow:none} 13 | .fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-wheelchair-alt:before,.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book-o:before,.fa-address-book:before{content:"\f2b9"}.fa-address-card-o:before,.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-circle-o-down:before,.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-circle-o-left:before,.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-circle-o-right:before,.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-circle-o-up:before,.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows:before,.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-h:before,.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-v:before,.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-balance-scale:before{content:"\f24e"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-navicon:before,.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bathtub:before,.fa-bath:before{content:"\f2cd"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell-o:before,.fa-bell:before{content:"\f0f3"}.fa-bell-slash-o:before,.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket-square:before,.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark-o:before,.fa-bookmark:before{content:"\f02e"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-bug:before{content:"\f188"}.fa-building-o:before,.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar-o:before,.fa-calendar:before{content:"\f133"}.fa-calendar:before,.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check-o:before,.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus-o:before,.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus-o:before,.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times-o:before,.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-o-down:before,.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-o-left:before,.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-o-right:before,.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-o-up:before,.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-area-chart:before,.fa-chart-area:before{content:"\f1fe"}.fa-bar-chart-o:before,.fa-chart-bar:before{content:"\f080"}.fa-line-chart:before,.fa-chart-line:before{content:"\f201"}.fa-pie-chart:before,.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle-o:before,.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square-o:before,.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-church:before{content:"\f51d"}.fa-circle-o:before,.fa-circle:before{content:"\f111"}.fa-circle-o-notch:before,.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-paste:before,.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock-o:before,.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-cc:before,.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download:before,.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload:before,.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-fork:before,.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment-o:before,.fa-comment:before{content:"\f075"}.fa-commenting-o:before,.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments-o:before,.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-files-o:before,.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card-alt:before,.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-scissors:before,.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deafness:before,.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar:before,.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle-o:before,.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-pencil-square-o:before,.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-envelope-o:before,.fa-envelope:before{content:"\f0e0"}.fa-envelope-open-o:before,.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-eur:before,.fa-euro-sign:before{content:"\f153"}.fa-exchange:before,.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-arrows-alt:before,.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link:before,.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square:before,.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eyedropper:before,.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook-official:before,.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before,.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file-o:before,.fa-file:before{content:"\f15b"}.fa-file-text-o:before,.fa-file-alt:before{content:"\f15c"}.fa-file-archive-o:before,.fa-file-archive:before{content:"\f1c6"}.fa-file-audio-o:before,.fa-file-audio:before{content:"\f1c7"}.fa-file-code-o:before,.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel-o:before,.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image-o:before,.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf-o:before,.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint-o:before,.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-movie-o:before,.fa-file-video:before{content:"\f1c8"}.fa-file-word-o:before,.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag-o:before,.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder-o:before,.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open-o:before,.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown-o:before,.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol-o:before,.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-diamond:before,.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass:before,.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus-circle:before,.fa-google-plus:before{content:"\f2b3"}.fa-google-plus:before,.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-y-combinator-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard-o:before,.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper-o:before,.fa-hand-paper:before{content:"\f256"}.fa-hand-peace-o:before,.fa-hand-peace:before{content:"\f25b"}.fa-hand-o-down:before,.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-o-left:before,.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-o-right:before,.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-o-up:before,.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer-o:before,.fa-hand-pointer:before{content:"\f25a"}.fa-hand-grab-o:before,.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors-o:before,.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock-o:before,.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake-o:before,.fa-handshake:before{content:"\f2b5"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-wizard:before{content:"\f6e8"}.fa-haykal:before{content:"\f666"}.fa-hdd-o:before,.fa-hdd:before{content:"\f0a0"}.fa-header:before,.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart-o:before,.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital-o:before,.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass-o:before,.fa-hourglass:before{content:"\f254"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license-o:before,.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-igloo:before{content:"\f7ae"}.fa-image:before,.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard-o:before,.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon-o:before,.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down:before,.fa-level-down-alt:before{content:"\f3be"}.fa-level-up:before,.fa-level-up-alt:before{content:"\f3bf"}.fa-life-bouy:before,.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb-o:before,.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-linkedin-square:before,.fa-linkedin:before{content:"\f08c"}.fa-linkedin:before,.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-try:before,.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-down:before,.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-left:before,.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-right:before,.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-up:before,.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map-o:before,.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker:before,.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh-o:before,.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square-o:before,.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-phone:before,.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money:before,.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon-o:before,.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper-o:before,.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-nintendo-switch:before{content:"\f418"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane-o:before,.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle-o:before,.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pencil-square:before,.fa-pen-square:before{content:"\f14b"}.fa-pencil:before,.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-volume-control-phone:before,.fa-phone-volume:before{content:"\f2a0"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle-o:before,.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square-o:before,.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-gbp:before,.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle-o:before,.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-repeat:before,.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-renren:before{content:"\f18b"}.fa-mail-reply:before,.fa-reply:before{content:"\f3e5"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-rouble:before,.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-inr:before,.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-floppy-o:before,.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-eercast:before,.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square-o:before,.fa-share-square:before{content:"\f14d"}.fa-ils:before,.fa-shekel-sign:before{content:"\f20b"}.fa-shield:before,.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in:before,.fa-sign-in-alt:before{content:"\f2f6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-sign-out:before,.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders:before,.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile-o:before,.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake-o:before,.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-asc:before,.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-desc:before,.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-amount-asc:before,.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-desc:before,.fa-sort-amount-up:before{content:"\f161"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-asc:before,.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-desc:before,.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square-o:before,.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stamp:before{content:"\f5bf"}.fa-star-o:before,.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half-empty:before,.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note-o:before,.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle-o:before,.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun-o:before,.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-synagogue:before{content:"\f69b"}.fa-refresh:before,.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet:before,.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-dashboard:before,.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-4:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-o-down:before,.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-o-up:before,.fa-thumbs-up:before{content:"\f164"}.fa-thumb-tack:before,.fa-thumbtack:before{content:"\f08d"}.fa-ticket:before,.fa-ticket-alt:before{content:"\f3ff"}.fa-close:before,.fa-times:before{content:"\f00d"}.fa-times-circle-o:before,.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-o:before,.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-television:before,.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-chain-broken:before,.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user-o:before,.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle-o:before,.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-spoon:before,.fa-utensil-spoon:before{content:"\f2e5"}.fa-cutlery:before,.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video-camera:before,.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo:before,.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-times-rectangle-o:before,.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-krw:before,.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-cny:before,.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube-play:before,.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;font-display:auto;src:url(../fonts/fa-brands-400.eot);src:url(../fonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../fonts/fa-brands-400.woff2) format("woff2"),url(../fonts/fa-brands-400.woff) format("woff"),url(../fonts/fa-brands-400.ttf) format("truetype"),url(../fonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(../fonts/fa-regular-400.eot);src:url(../fonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../fonts/fa-regular-400.woff2) format("woff2"),url(../fonts/fa-regular-400.woff) format("woff"),url(../fonts/fa-regular-400.ttf) format("truetype"),url(../fonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(../fonts/fa-solid-900.eot);src:url(../fonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../fonts/fa-solid-900.woff2) format("woff2"),url(../fonts/fa-solid-900.woff) format("woff"),url(../fonts/fa-solid-900.ttf) format("truetype"),url(../fonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} 14 | .ui-dark{color:#E0E0E0;background-color:#202020}.b{font-weight:bold}.mr5{margin-right:5px}.mt5{margin-top:5px}.mt10{margin-top:10px}.m{margin-bottom:15px}.nmt{margin-top:0!important}.nmb{margin-bottom:0!important}.npt{padding-top:0!important}.npb{padding-bottom:0!important}.table-small{font-size:12px}.ui-dark hr{border-color:#404040}.table-small>tbody>tr>td,.table-small>tfoot>tr>td{padding:3px 5px}.table-small>thead>tr>th{padding:5px}.ui-dark .table-striped>tbody>tr:nth-child(odd){background-color:#292929}.ui-dark .table>thead>tr>th,.ui-dark .table>tbody>tr>th,.ui-dark .table>tfoot>tr>th,.ui-dark .table>thead>tr>td,.ui-dark .table>tbody>tr>td,.ui-dark .table>tfoot>tr>td{border-top-color:#373737}.ui-dark .table>thead>tr>th{border-bottom-color:#373737}.ui-dark .table-bordered{border-color:#373737}.ui-dark .table-bordered>thead>tr>th,.ui-dark .table-bordered>tbody>tr>th,.ui-dark .table-bordered>tfoot>tr>th,.ui-dark .table-bordered>thead>tr>td,.ui-dark .table-bordered>tbody>tr>td,.ui-dark .table-bordered>tfoot>tr>td{border-color:#373737}.padding{padding:20px}.help{font-size:11px;color:#909090;margin-top:8px;line-height:13px}.help i{margin-right:5px}.help code{font:normal normal 11px Arial;background-color:#F0F0F0;padding:1px 3px;border-radius:2px;border:1px solid #E0E0E0;}.ui-dark .help{color:#656565}.ui-dark .help code{background-color:#353535;border-color:#303030;color:#777}.ui-dark .help .link{color:#79d0ff}.hellip{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.np{padding:0!important}.silver{color:#A0A0A0!important}.red{color:#D63B32!important}.blue{color:#377BB5!important}.green{color:#68B25B!important}.center{text-align:center!important}.right{text-align:right!important} 15 | .ui-scrollbar{overflow:hidden}.ui-scrollbar-area{overflow:scroll;overflow-scrolling:touch;-webkit-overflow-scrolling:touch}.ui-scrollbar-body{margin: 0}.ui-scrollbar-path{position:relative}.ui-scrollbar-y{width:6px;height:100%;background-color:#E0E0E0;position:absolute;right:0;top:0;z-index:5}.ui-scrollbar-x{height:6px;width:100%;background-color:#E0E0E0;position:absolute;left:0;bottom:0;z-index:5}.ui-scrollbar-y span{height:30px;width:100%;background-color:#A0A0A0;display:block;position:relative}.ui-scrollbar-path b{width:100%;height:100%;display:block}.ui-scrollbar-x span{width:30px;height:100%;background-color:#A0A0A0;display:block;position:relative}.ui-scrollbar-y span:hover,.ui-scrollbar-x span:hover{background-color:#A9A9A9}.ui-scrollbar-isx .ui-scrollbar-padding{padding-right:30px}.ui-scrollbar-hidden span{display:none!important}.ui-scrollbar-notready{display:none!important}.ui-dark .ui-scrollbar-y span,.ui-dark .ui-scrollbar-x span{background-color:#505050}.ui-dark .ui-scrollbar-y,.ui-dark .ui-scrollbar-x{background-color:#303030}.ui-dark .ui-scrollbar-y span:hover,.ui-dark .ui-scrollbar-x span:hover{background-color:#606060}.ui-scrollbar-touch .ui-scrollbar-y{display:none!important}.ui-scrollbar-touch .ui-scrollbar-x{display:none!important}.ui-scrollbar-touch .ui-scrollbar-body{margin:0!important}.ui-scrollbar-touch .ui-scrollbar-padding{padding-right:0}.noscrollbar{overflow-x:hidden;overflow-y:hidden;overflow-scrolling:touch;-webkit-overflow-scrolling:touch;height:100%} -------------------------------------------------------------------------------- /source/css/ui.extras.css: -------------------------------------------------------------------------------- 1 | .ui-designer * { user-select: none; } 2 | .ui-designer { cursor: move; } 3 | .ui-designer .selected { animation: hop 0.3s; } 4 | .ui-designer .component { cursor: move; } 5 | .draft .ui-designer .component { cursor: crosshair; } 6 | 7 | @keyframes hop { 8 | 0% { transform: scale(1); } 9 | 50% { transform: scale(1.18); } 10 | 100% { transform: scale(1); } 11 | } 12 | 13 | .ui-devicetype { height: 28px; } 14 | .ui-devicetype span { float: left; width: 50%; text-align: center; height: 28px; cursor: pointer; padding: 6px 0 0 0; font-size: 12px; text-transform: uppercase; } 15 | .ui-devicetype span:first-child { border-radius: 2px 0 0 2px; } 16 | .ui-devicetype span:last-child { border-radius: 0 2px 2px 0; } 17 | .ui-devicetype-selected { background-color: #303030; color: white; font-weight: bold; } 18 | 19 | .ui-dark .ui-devicetype-selected { background-color: white; color: black; } 20 | 21 | .ui-controls { position: absolute; opacity: 0; transition: 0.25s transform cubic-bezier(0.23, 1, 0.32, 1); left: -100; top: -100; z-index: 20; max-width: 300px; box-shadow: 0 5px 15px rgba(0,0,0,0.1); transform: translate(0px,20px); background-color: white; border: 1px solid #E0E0E0; } 22 | .ui-controls-visible { opacity: 1; transform: translate(0px,0px); } 23 | .ui-controls-items .item { font-size: 11px; height: 60px; background-color: #F0F0F0; cursor: pointer; width: 100px; text-overflow: ellipsis; overflow: hidden; text-align: center; display: block; float: left; } 24 | .ui-controls-items .item:nth-child(even) { background-color: #F8F8F8; } 25 | .ui-controls-items .item:hover { background-color: #E0E0E0; } 26 | .ui-controls-items .item i { text-align: center; padding: 11px 0 3px; font-size: 22px; color: #A0A0A0; display: block; } 27 | .ui-controls-items span { color: black; width: 180px; margin: 10px 0 0 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; height: 20px; } 28 | .ui-controls-items .divider { font-size: 11px; color: #A0A0A0; text-transform: uppercase; padding: 10px 10px; border-width: 0; border-bottom: 1px solid #E0E0E0; margin-top: 15px; } 29 | .ui-controls-items .divider .fa { margin-right: 5px; } 30 | .ui-controls .selected { font-weight: bold; background-color: #F6BB42 !important; box-shadow: inset 0 0 10px rgba(0,0,0,0.2); } 31 | .ui-controls .selected * { color: white !important; } 32 | .ui-controls .disabled { background-color: white !important; cursor: not-allowed; } 33 | .ui-controls .disabled * { color: silver !important; } 34 | 35 | .ui-dark .ui-controls { background-color: #181818; box-shadow: 0 1px 15px rgba(0,0,0,0.8); } 36 | .ui-dark .ui-controls-items .item { background-color: #202020; } 37 | .ui-dark .ui-controls-items .item:nth-child(even) { background-color: #282828; } 38 | .ui-dark .ui-controls-items .item:hover { background-color: #303030; } 39 | .ui-dark .ui-controls-items .item i { color: gray; } 40 | .ui-dark .ui-controls-items .item span { color: #E0E0E0; } 41 | .ui-dark .ui-controls-items .divider { color: gray; border-bottom-color: #303030; font-weight: bold; } 42 | .ui-dark .ui-controls .selected { background-color: #F6BB42 !important; } 43 | .ui-dark .ui-controls .selected * { color: white !important; } 44 | .ui-dark .ui-controls .disabled { background-color: #161616 !important; cursor: not-allowed; } 45 | .ui-dark .ui-controls .disabled * { color: #353535 !important; } 46 | 47 | .ui-form-buttons { padding: 20px; border-top: 1px solid #F0F0F0; background: linear-gradient(#F8F8F8,white); border-radius: 0 0 4px 4px; } 48 | .ui-form-buttons button { border: 1px solid #D0D0D0; background-color: white; border-radius: 4px; height: 45px; padding: 0 15px; color: black; margin: 0; cursor: pointer; font-family: Arial; vertical-align: middle; outline: 0; font-size: 14px; text-decoration: none; transition: all 0.3s; } 49 | .ui-form-buttons button .fa { width: 16px; } 50 | .ui-form-buttons button:hover { border-color: silver; } 51 | .ui-form-buttons button:active { background-color: #D0D0D0; } 52 | .ui-form-buttons button:disabled { background-color: #F5F5F5 !important; border-color: #E0E0E0 !important; color: silver !important; cursor: not-allowed; box-shadow: none; } 53 | .ui-form-buttons button[name="submit"] { width: 220px; margin-right: 15px; font-weight: bold; } 54 | .ui-form-buttons button[name="cancel"] { color: gray; } 55 | .ui-form-buttons div { position: relative; display: inline-block; vertical-align: middle; } 56 | .ui-form-buttons label { float: right; margin: 12px 0 0 0; font-size: 11px; } 57 | 58 | .ui-form-dragdrop { background-color: #F8F8F8; } 59 | 60 | .ui-filereader { border: 1px solid #d0d0d0; padding: 5px 8px; border-radius: 3px; position: relative; display: block; width: 100%; background-color: white; } 61 | .ui-filereader input[type="text"] { border: 0; width: 100%; outline: 0; font: normal 14px Arial; color: black; } 62 | .ui-filereader .fa { position: absolute; right: 8px; top: 8px; color: gray; font-size: 16px; } 63 | .ui-filereader-input { position: absolute; width: 100%; height: 30px; border: 1px solid #D0D0D0; margin: -5px 0 0 -7px; opacity: 0; cursor: pointer; font-weight: bold; } 64 | .ui-filereader-label { margin-bottom: 3px; font-size: 12px; } 65 | .ui-filereader-label .fa { width: 13px; } 66 | /*.ui-filereader-label-required { font-weight: bold; }*/ 67 | .ui-filereader-label-required:before { color: red; content: '***'; margin-right: 5px; } 68 | .ui-dark .ui-filereader { border: 1px solid #404040; background-color: #202020; } 69 | .ui-dark .ui-filereader input[type="text"] { background-color: #202020; } -------------------------------------------------------------------------------- /source/fonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-brands-400.eot -------------------------------------------------------------------------------- /source/fonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /source/fonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-brands-400.woff -------------------------------------------------------------------------------- /source/fonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /source/fonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-regular-400.eot -------------------------------------------------------------------------------- /source/fonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /source/fonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-regular-400.woff -------------------------------------------------------------------------------- /source/fonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /source/fonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-solid-900.eot -------------------------------------------------------------------------------- /source/fonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /source/fonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-solid-900.woff -------------------------------------------------------------------------------- /source/fonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/totaljs/dashboard/58a84c1ab50610916a29e52292cfdf04caa9dfc4/source/fonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /source/index.html: -------------------------------------------------------------------------------- 1 | @{layout('')} 2 | 3 | 4 | 5 | 6 | @(Dashboard v7.0:) @{config.name} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | @{import('head')} 19 | 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 |
36 |
37 | 38 |
39 | 42 |
43 | 44 |
45 |
46 | 47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | 57 |
58 |
59 |
60 |
61 |
62 | 63 | 76 | 77 | @{import(model.url + 'js/default.js')} 78 | @{place('scripts')} 79 | 80 | 501 | 502 | @{components('dashboard')} 503 | 504 | 505 | 506 | -------------------------------------------------------------------------------- /source/index.js: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // Copyright Peter Širka 3 | 4 | const Fs = require('fs'); 5 | const WS_COMPONENT = { TYPE: 'component' }; 6 | const WS_LOADED = { TYPE: 'loaded' }; 7 | const WS_INIT = { TYPE: 'init' }; 8 | const WS_INSTANCES = { TYPE: 'instances' }; 9 | const WS_DATA = { TYPE: 'data' }; 10 | const PATH = '/dashboard/'; 11 | const FILEDESIGNER = '/dashboard/designer.json'; 12 | const FLAGS = ['get', 'dnscache']; 13 | const WS_ERROR = { TYPE: 'error' }; 14 | const WS_TEMPLATES = { TYPE: 'templates' }; 15 | const REG_INSTANCES = /^dashboard\w+/i; 16 | 17 | var OPT; 18 | var DDOS = {}; 19 | var WS = null; 20 | 21 | global.DASHBOARD = {}; 22 | global.DASHBOARD.send = function(instance, type, data) { 23 | WS_DATA.id = instance.id; 24 | WS_DATA.name = instance.name; 25 | WS_DATA.component = instance.component; 26 | WS_DATA.body = data; 27 | WS_DATA.type = type; 28 | WS_DATA.reference = instance.reference; 29 | WS && WS.send(WS_DATA); 30 | }; 31 | 32 | global.DASHBOARD.online = function() { 33 | return WS ? true : false; 34 | }; 35 | 36 | exports.install = function(options) { 37 | 38 | OPT = options; 39 | !OPT && (OPT = {}); 40 | 41 | if (OPT.auth instanceof Array) { 42 | OPT.baa = {}; 43 | OPT.auth.forEach(function(user) { 44 | var hash = user.hash().toString(); 45 | OPT.baa[hash] = user; 46 | }); 47 | } 48 | 49 | if (OPT.dark == null) 50 | OPT.dark = true; 51 | 52 | if (OPT.flow == null) 53 | OPT.flow = true; 54 | 55 | if (OPT.flowboard == null) 56 | OPT.flowboard = true; 57 | 58 | global.DASHBOARD.url = OPT.url = U.path(OPT.url || '/$dashboard/'); 59 | !OPT.limit && (OPT.limit = 50); 60 | !OPT.templates && (OPT.templates = 'https://cdn.totaljs.com/dashboard/templates.json'); 61 | 62 | try { 63 | Fs.mkdirSync(F.path.root(PATH)); 64 | } catch(e) {} 65 | 66 | if (OPT.auth === true) { 67 | ROUTE(OPT.url, view_index, ['authorize']); 68 | WEBSOCKET(OPT.url, websocket, ['authorize', 'json'], OPT.limit); 69 | } else { 70 | ROUTE(OPT.url, view_index); 71 | WEBSOCKET(OPT.url, websocket, ['json'], OPT.limit); 72 | } 73 | 74 | // Files 75 | LOCALIZE(OPT.url + 'templates/*.html', ['compress']); 76 | 77 | // Merging & Mapping 78 | MERGE(OPT.url + 'css/default.css', '@dashboard/css/spa.min@18.css', '@dashboard/css/default.css', '@dashboard/css/ui.css', '@dashboard/css/ui.extras.css'); 79 | MERGE(OPT.url + 'js/default.js', '@dashboard/js/spa.min@18.js', '@dashboard/js/default.js', '@dashboard/js/ui.js', '@dashboard/js/ui.extras.js'); 80 | MAP(OPT.url + 'templates/', '@dashboard/templates/'); 81 | MAP(OPT.url + 'fonts/', '@dashboard/fonts/'); 82 | MAP(OPT.url + 'img/', '@dashboard/img/'); 83 | 84 | DEF.helpers.DASHBOARD = global.DASHBOARD; 85 | 86 | // Service 87 | ON('service', service); 88 | 89 | WAIT(function() { 90 | return global.FLOW; 91 | }, function() { 92 | FLOW.prototypes(function(proto) { 93 | proto.Component.dashboard = function(type, data) { 94 | DASHBOARD.send(this, type, data); 95 | return this; 96 | }; 97 | }); 98 | }); 99 | }; 100 | 101 | function service(counter) { 102 | counter % 5 === 0 && (DDOS = {}); 103 | } 104 | 105 | function view_index() { 106 | if (auth(this)) { 107 | this.theme(''); 108 | this.view('@dashboard/index', OPT); 109 | } 110 | } 111 | 112 | function websocket() { 113 | var self = WS = this; 114 | 115 | self.autodestroy(() => WS = null); 116 | 117 | self.on('open', function(client) { 118 | 119 | // Security 120 | if ((OPT.token && OPT.token.indexOf(client.query.token) === -1) || (OPT.baa && !OPT.baa[client.query.baa]) || (OPT.restrictions && OPT.restrictions[self.ip] === -1)) { 121 | setImmediate(() => client.close('Unauthorized')); 122 | return; 123 | } 124 | 125 | client.send(WS_INIT); 126 | send_instances(client, () => send_components(client, () => DASHBOARD.load(client, function() { 127 | self.send(WS_LOADED); 128 | }))); 129 | }); 130 | 131 | self.on('message', function(client, message) { 132 | 133 | // message.id 134 | // message.TYPE 135 | // message.body 136 | 137 | switch (message.TYPE) { 138 | case 'templates': 139 | OPT.templates && REQUEST({ 140 | method: 'get', 141 | url: OPT.templates, 142 | dnscache: true, 143 | callback: function(err, response) { 144 | if (!err) { 145 | WS_TEMPLATES.body = response.body.parseJSON(); 146 | WS_TEMPLATES.body && client.send(WS_TEMPLATES); 147 | } 148 | } 149 | }); 150 | break; 151 | case 'send': 152 | var instance = FLOW.findById(message.id); 153 | instance && instance.emit('dashboard', message.type, message.body); 154 | break; 155 | case 'install': 156 | component_install(self, message); 157 | break; 158 | case 'uninstall': 159 | component_uninstall(self, message.body); 160 | break; 161 | case 'save': 162 | DASHBOARD.save(message.body, OPT.backup); 163 | break; 164 | default: 165 | EMIT('dashboard.message', message); 166 | } 167 | }); 168 | } 169 | 170 | ON('flow.save', function() { 171 | WS && send_instances(WS); 172 | }); 173 | 174 | function component_install(controller, response, callback) { 175 | 176 | var u = response.body.substring(0, 6); 177 | if (u === 'http:/' || u === 'https:') { 178 | var target = F.path.root(PATH + U.getName(response.body)); 179 | DOWNLOAD(response.body, target, function(err, res) { 180 | if (err) { 181 | WS_ERROR.body = err.toString(); 182 | DASHBOARD.send(WS_ERROR); 183 | return callback(err); 184 | } else { 185 | Fs.readFile(target, function(err, response) { 186 | if (response) 187 | response = U.minify_html(response.toString('utf8')); 188 | callback && callback(); 189 | controller && send_component(target, controller); 190 | }); 191 | } 192 | }); 193 | return; 194 | } 195 | 196 | var filename = F.path.root(PATH + response.filename); 197 | Fs.writeFile(filename, U.minify_html(response.body), function() { 198 | callback && callback(); 199 | controller && send_component(filename, controller); 200 | }); 201 | } 202 | 203 | function component_uninstall(controller, name, callback) { 204 | 205 | var index = name.indexOf('/'); 206 | if (index === -1) 207 | name = name.substring(index + 1); 208 | 209 | Fs.unlink(F.path.root(PATH + name), function() { 210 | callback && callback(); 211 | controller && send_components(controller); 212 | }); 213 | } 214 | 215 | DASHBOARD.save = function(body, backup, callback) { 216 | save(body, callback); 217 | }; 218 | 219 | function save(body, callback) { 220 | var path = F.path.root(FILEDESIGNER); 221 | var json = JSON.stringify(body); 222 | Fs.writeFile(path, json, callback || NOOP); 223 | OPT.backup && Fs.writeFile(F.path.root(FILEDESIGNER.replace(/\.json/g, '-' + F.datetime.format('yyyyMMdd_HHmmss') + '.backup')), json, NOOP); 224 | } 225 | 226 | DASHBOARD.load = function(client, callback) { 227 | load(client, callback) 228 | }; 229 | 230 | function load(client, callback) { 231 | var path = F.path.root(FILEDESIGNER); 232 | Fs.readFile(path, function(err, data) { 233 | data && client.send(data.toString('utf8'), true); 234 | callback && callback(); 235 | }); 236 | } 237 | 238 | function send_instances(client, callback) { 239 | 240 | WS_INSTANCES.body = []; 241 | 242 | if (!global.FLOW) { 243 | callback && callback(); 244 | return; 245 | } 246 | 247 | var keys = Object.keys(FLOW.instances); 248 | 249 | for (var i = 0, length = keys.length; i < length; i++) { 250 | var instance = FLOW.instances[keys[i]]; 251 | var declaration = FLOW.components[instance.component]; 252 | if (declaration.dashboard || REG_INSTANCES.test(instance.component)) 253 | WS_INSTANCES.body.push({ id: instance.id, name: instance.name || instance.title, component: instance.component, reference: instance.reference }); 254 | } 255 | 256 | client.send(WS_INSTANCES); 257 | callback && callback(); 258 | } 259 | 260 | function send_component(filename, client, callback) { 261 | Fs.stat(filename, function(err, stats) { 262 | 263 | if (err) { 264 | callback && callback(err); 265 | return; 266 | } 267 | 268 | Fs.readFile(filename, function(err, data) { 269 | if (data) { 270 | WS_COMPONENT.body = U.minify_html(TRANSLATOR('default', data.toString('utf8'))); 271 | WS_COMPONENT.name = U.getName(filename); 272 | WS_COMPONENT.dateupdated = stats.mtime; 273 | client.send(WS_COMPONENT); 274 | } 275 | callback && callback(); 276 | }); 277 | }); 278 | } 279 | 280 | function send_components(client, callback) { 281 | var path = F.path.root(PATH); 282 | U.ls(path, function(files) { 283 | files.wait(function(item, next) { 284 | Fs.stat(item, function(err, stats) { 285 | if (err) 286 | return next(); 287 | Fs.readFile(item, function(err, data) { 288 | if (data) { 289 | WS_COMPONENT.body = U.minify_html(TRANSLATOR('default', data.toString('utf8'))); 290 | WS_COMPONENT.name = U.getName(item); 291 | WS_COMPONENT.dateupdated = stats.mtime; 292 | client.send(WS_COMPONENT); 293 | } 294 | next(); 295 | }); 296 | }); 297 | }, callback); 298 | }, (filename) => filename.endsWith('.html')); 299 | } 300 | 301 | function auth(controller) { 302 | 303 | if (OPT.auth instanceof Array) { 304 | var user = controller.baa(); 305 | if (OPT.auth.indexOf(user.user + ':' + user.password) === -1) { 306 | if (DDOS[controller.ip]) 307 | DDOS[controller.ip]++; 308 | else 309 | DDOS[controller.ip] = 1; 310 | if (DDOS[controller.ip] > 4) 311 | controller.throw401(); 312 | else 313 | controller.baa('Secured area, please add sign-in'); 314 | return false; 315 | } 316 | controller.repository.baa = (user.user + ':' + user.password).hash(); 317 | } 318 | 319 | if (OPT.restrictions && OPT.restrictions[controller.ip] === -1) { 320 | controller.throw401(); 321 | return false; 322 | } 323 | 324 | if (OPT.token && OPT.token.indexOf(controller.query.token) === -1) { 325 | if (DDOS[controller.ip]) 326 | DDOS[controller.ip]++; 327 | else 328 | DDOS[controller.ip] = 1; 329 | 330 | if (DDOS[controller.ip] > 4) { 331 | controller.throw401(); 332 | return false; 333 | } 334 | } 335 | 336 | return true; 337 | } -------------------------------------------------------------------------------- /source/js/default.js: -------------------------------------------------------------------------------- 1 | var settings = {}; 2 | var DEBUG = false; 3 | var RELEASE = true; 4 | var common = {}; 5 | var Icons = getIcons(); 6 | 7 | common.database = []; 8 | common.events = {}; 9 | common.settings = {}; 10 | common.operations = {}; 11 | common.statics = {}; 12 | common.instances = []; 13 | common.data = []; 14 | common.designer = []; 15 | common.sizing = {}; 16 | 17 | $(window).on('resize', resizewindow); 18 | 19 | function resizewindow() { 20 | var d = WIDTH(); 21 | var sizing = common.sizing; 22 | var b = $('.designer-container'); 23 | 24 | if (sizing.display && sizing.display !== d) 25 | b.rclass(sizing.display); 26 | 27 | b.aclass(d); 28 | sizing.display = d; 29 | 30 | var font = 24; 31 | 32 | switch (d) { 33 | case 'xs': 34 | var w = $(window).width(); 35 | font = w > 500 ? 12 : w > 400 ? 10 : 9; 36 | break; 37 | case 'sm': 38 | font = 16; 39 | break; 40 | case 'md': 41 | font = 18; 42 | break; 43 | case 'lg': 44 | font = 24; 45 | break; 46 | } 47 | 48 | sizing.fontsize = font; 49 | b.css('font-size', font); 50 | } 51 | 52 | resizewindow(); 53 | 54 | SETTER(true, 'loading', 'hide', 1000); 55 | 56 | common.operations.emit = function(name, a, b, c, d) { 57 | $('figure').each(function() { 58 | if (name === 'data') 59 | a = CLONE(a); 60 | this.$widget && this.$widget.$events[name] && this.$widget.emit(name, a, b, c, d); 61 | }); 62 | return common.operations; 63 | }; 64 | 65 | common.operations.remove = function(name, uninstall) { 66 | $('figure[data-name="{0}"]'.format(name)).each(function() { 67 | var instance = this.$widget; 68 | instance.emit('destroy'); 69 | delete instance.$events; 70 | $(this).remove(); 71 | }); 72 | 73 | var item = common.database.findItem('name', name); 74 | common.database = common.database.remove('name', name); 75 | item && uninstall && SETTER('websocket', 'send', { TYPE: 'uninstall', body: item.filename }); 76 | UPDATE('common.database', 1000); 77 | }; 78 | 79 | function getScripts(html) { 80 | var obj = {}; 81 | 82 | if (!html) 83 | return obj; 84 | 85 | var t = []; 86 | var otag = ' p[1] - r[1]); 112 | 113 | var pairs = []; 114 | var depth = 1; 115 | var len = t.length; 116 | if (t[0][0] !== 0) 117 | return; 118 | var beg = t[0][1]; 119 | for (var i = 1; i < len; i++) { 120 | if (t[i][0] === 0) 121 | depth++; 122 | else 123 | depth--; 124 | if (depth === 0) { 125 | pairs.push([beg, t[i][1]]); 126 | if (!t[i+1]) 127 | break; 128 | beg = t[i+1][1]; 129 | } 130 | } 131 | 132 | pairs.forEach(function(pair, index){ 133 | var script = html.substring(pair[0], pair[1]); 134 | var br = script.indexOf('>') + 1; 135 | var type = script.substring(0, br); 136 | if (type.indexOf('markdown') !== -1) 137 | obj.readme = script.substring(br).trim(); 138 | else if (type.indexOf('body') !== -1) 139 | obj.html = script.substring(br).trim(); 140 | else if (type.indexOf('settings') !== -1) 141 | obj.settings = script.substring(br).trim(); 142 | else if (type.indexOf('svg') !== -1) 143 | obj.svg = script.substring(br).trim(); 144 | else 145 | obj.script = script.substring(br).trim(); 146 | }); 147 | 148 | beg = html.indexOf('', beg) + 1, html.indexOf('')).trim(); 151 | 152 | return obj; 153 | }; 154 | 155 | common.operations.append = function(html, updated, filename) { 156 | 157 | var scripts = getScripts(html); 158 | 159 | var component = {}; 160 | new Function('exports', scripts.script)(component); 161 | 162 | if (!component.name) 163 | return false; 164 | 165 | component.settings = scripts.settings; 166 | component.svg = scripts.svg; 167 | component.readme = scripts.readme; 168 | component.html = scripts.html; 169 | component.dateupdated = updated; 170 | component.filename = filename; 171 | 172 | if (scripts.style) { 173 | $('#inlinecss_' + component.name).remove(); 174 | $('').appendTo('head'); 175 | } 176 | 177 | var index = common.database.findIndex('name', component.name); 178 | if (index === -1) 179 | common.database.push(component); 180 | else { 181 | var tmp = common.database[index]; 182 | tmp.uninstall && tmp.uninstall(true); 183 | common.database[index] = component; 184 | var designer = FIND('designer'); 185 | designer && designer.operations.upgrade(component); 186 | } 187 | 188 | common.database.quicksort('name'); 189 | 190 | // hack for refreshing database 191 | common.form === 'database' && UPDATE('common.database'); 192 | return true; 193 | }; 194 | 195 | function Instance(id, element, declaration, options, size) { 196 | var self = this; 197 | self.$events = {}; 198 | self.id = id; 199 | self.scope = 'scope' + id; 200 | self.name = declaration.name; 201 | self.options = $.extend(true, CLONE(declaration.options), options || {}); 202 | 203 | self.$container = $(element.closest('.widget')[0]); 204 | self.element = element; 205 | 206 | self.dom = element[0]; 207 | self.size = CLONE(size); 208 | 209 | if (self.size.padding > 0) { 210 | self.size.width -= self.size.padding * 2; 211 | self.size.height -= self.size.padding * 2; 212 | } 213 | 214 | declaration.install.call(self, self); 215 | 216 | var tmp = declaration.html; 217 | 218 | if (self.prerender) 219 | tmp = self.prerender(tmp); 220 | 221 | if (tmp) { 222 | element.html(tmp); 223 | tmp.indexOf('data-jc="') !== -1 && COMPILE(); 224 | } 225 | 226 | setTimeout(function() { 227 | self.make && self.make(); 228 | }, 1); 229 | } 230 | 231 | Instance.prototype.emit = function(name) { 232 | var e = this.$events[name]; 233 | if (e && e.length) { 234 | for (var i = 0, length = e.length; i < length; i++) 235 | e[i].call(this, arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); 236 | } 237 | return this; 238 | }; 239 | 240 | Instance.prototype.on = function(name, fn) { 241 | var e = this.$events[name]; 242 | !e && (this.$events[name] = e = []); 243 | e.push(fn); 244 | return this; 245 | }; 246 | 247 | Instance.prototype.menu = function(items, el, callback, offsetX) { 248 | SETTER('controls', 'show', el || this.element, items, callback, offsetX); 249 | return this; 250 | }; 251 | 252 | Instance.prototype.send = function(id, type, data) { 253 | if (data) { 254 | var msg = {}; 255 | msg.TYPE = 'send'; 256 | msg.id = id; 257 | msg.type = type; 258 | msg.body = data; 259 | SETTER('websocket', 'send', msg); 260 | } else { 261 | var msg = {}; 262 | msg.TYPE = 'send'; 263 | msg.id = id; 264 | msg.type = type; 265 | msg.body = data; 266 | setTimeout2('isend' + id + 'x' + (type || ''), function(msg) { 267 | SETTER('websocket', 'send', msg); 268 | }, 200, 10, msg); 269 | } 270 | return this; 271 | }; 272 | 273 | Instance.prototype.destroy = function() { 274 | var self = this; 275 | if (self.element) { 276 | self.emit('destroy'); 277 | delete self.$events; 278 | delete self.element[0].$widget; 279 | self.element.remove(); 280 | self.element = null; 281 | } 282 | return self; 283 | }; 284 | 285 | Instance.prototype.find = function(selector) { 286 | return this.element.find(selector); 287 | }; 288 | 289 | Instance.prototype.append = function(value) { 290 | return this.element.append(value); 291 | }; 292 | 293 | Instance.prototype.html = function(value) { 294 | return this.element.html(value); 295 | }; 296 | 297 | Instance.prototype.event = function() { 298 | this.element.on.apply(this.element, arguments); 299 | return this; 300 | }; 301 | 302 | Instance.prototype.css = function() { 303 | this.element.css.apply(this.element, arguments); 304 | return this; 305 | }; 306 | 307 | Instance.prototype.empty = function() { 308 | this.element.empty(); 309 | return this; 310 | }; 311 | 312 | Instance.prototype.aclass = function(v) { 313 | this.element.aclass(v); 314 | return this; 315 | }; 316 | 317 | Instance.prototype.rclass = function(v) { 318 | this.element.rclass(v); 319 | return this; 320 | }; 321 | 322 | Instance.prototype.tclass = function(v, t) { 323 | this.element.tclass(v, t); 324 | return this; 325 | }; 326 | 327 | Instance.prototype.hidden = function() { 328 | return this.$container.hclass('hidden'); 329 | }; 330 | 331 | Instance.prototype.hclass = function(v) { 332 | return this.element.hclass(v); 333 | }; 334 | 335 | Instance.prototype.settings = function() { 336 | var self = this; 337 | staticContent(self, function() { 338 | common.selected = self.element.parent(); 339 | var options = CLONE(self.options); 340 | EMIT('open.' + self.name, self, options); 341 | SET('settings.' + self.name, options, true); 342 | SET('common.form', 'settings-' + self.name); 343 | RESET('settings.' + self.name + '.*', 500); 344 | }); 345 | return self; 346 | }; 347 | 348 | Instance.prototype.transparent = function(t) { 349 | this.element.parent().tclass('transparent', t); 350 | return this; 351 | }; 352 | 353 | String.prototype.parseTransform = function() { 354 | var prop = ['translate', 'matrix', 'rotate', 'skewX', 'skewY', 'scale']; 355 | var val = this.match(/(translate|matrix|rotate|skewX|skewY|scale)\(.*?\)/g); 356 | var obj = {}; 357 | if (val) { 358 | for (var i = 0, length = val.length; i < length; i++) { 359 | var item = val[i]; 360 | var index = item.indexOf('('); 361 | var v = item.substring(index + 1, item.length - 1).split(/,|\s/); 362 | var n = item.substring(0, index); 363 | obj[n] = {}; 364 | switch (n) { 365 | case 'translate': 366 | case 'scale': 367 | obj[n].x = +v[0] || 0; 368 | obj[n].y = +v[1] || 0; 369 | break; 370 | case 'rotate': 371 | obj[n].a = +v[0] || 0; 372 | obj[n].x = +v[1] || 0; 373 | obj[n].y = +v[2] || 0; 374 | break; 375 | case 'skewX': 376 | case 'skewY': 377 | obj[n].a = +v[0]; 378 | break; 379 | case 'matrix': 380 | obj[n].a = +v[0] || 0; 381 | obj[n].b = +v[1] || 0; 382 | obj[n].c = +v[2] || 0; 383 | obj[n].d = +v[3] || 0; 384 | obj[n].e = +v[4] || 0; 385 | obj[n].f = +v[5] || 0; 386 | break; 387 | } 388 | } 389 | } 390 | 391 | obj.toString = function() { 392 | var builder = []; 393 | for (var i = 0, length = prop.length; i < length; i++) { 394 | var n = prop[i]; 395 | var o = this[n]; 396 | if (!o) 397 | continue; 398 | switch (n) { 399 | case 'translate': 400 | case 'scale': 401 | builder.push(n + '(' + o.x + ',' + o.y + ')'); 402 | break; 403 | case 'rotate': 404 | builder.push(n + '(' + o.a + ' ' + o.x + ' ' + o.y + ')'); 405 | break; 406 | case 'skewX': 407 | case 'skewY': 408 | builder.push(n + '(' + o.a + ')'); 409 | break; 410 | case 'matrix': 411 | builder.push(n + '(' + o.a + ',' + o.b + ',' + o.c + ',' + o.d + ',' + o.e + ',' + o.f + ')'); 412 | break; 413 | } 414 | } 415 | return builder.join(' '); 416 | }; 417 | 418 | return obj; 419 | }; 420 | 421 | $.fn.getPosition = function(fixed) { 422 | var obj = {}; 423 | obj.x = this.css('left').parseInt(); 424 | obj.y = this.css('top').parseInt(); 425 | obj.width = fixed ? this.width() : this.innerWidth(); 426 | obj.height = fixed ? this.height() : this.innerHeight(); 427 | var matrix = this.css('transform'); 428 | if (matrix) { 429 | var values = matrix.substring(1, matrix.length - 1).trim(); 430 | values = values.split(',').trim(); 431 | obj.rotation = Math.round(Math.asin(values[1]) * (180 / Math.PI)); 432 | } else 433 | obj.rotation = null; 434 | return obj; 435 | }; 436 | 437 | $.fn.setPosition = function(obj) { 438 | var css = {}; 439 | obj.x != null && (css.left = obj.x + 'px'); 440 | obj.y != null && (css.top = obj.y + 'px'); 441 | obj.width != null && (css.width = obj.width + 'px'); 442 | obj.height != null && (css.height = obj.height + 'px'); 443 | obj.rotation != null && (css.transform = 'rotate({0}deg)'.format(obj.rotation)); 444 | this.css(css); 445 | return this; 446 | }; 447 | 448 | function getIcons() { 449 | var classes = document.styleSheets[0].rules || document.styleSheets[0].cssRules; 450 | var icons = {}; 451 | for (var x = 0; x < classes.length; x++) { 452 | var cls = classes[x]; 453 | var sel = cls.selectorText; 454 | if (sel && sel.substring(0, 4) == '.fa-') { 455 | sel = sel.substring(4, sel.indexOf(':')).trim(); 456 | var val = cls.cssText ? cls.cssText : cls.cssText.style.cssText; 457 | var a = val.match(/[^x00-x7F]+/); 458 | if (a) 459 | icons[sel] = a.toString(); 460 | } 461 | } 462 | return icons; 463 | } -------------------------------------------------------------------------------- /source/js/ui.extras.js: -------------------------------------------------------------------------------- 1 | COMPONENT('designer', function(self) { 2 | 3 | var container, scroller; 4 | var move = {}; 5 | var widget = {}; 6 | var cells, widgets; 7 | var size; 8 | 9 | self.make = function() { 10 | 11 | self.aclass('designer'); 12 | self.append('
'); 13 | 14 | scroller = self.element.closest('.designer-scroll'); 15 | container = self.find('.grid'); 16 | 17 | var builder = []; 18 | for (var i = 0; i < 720; i++) { 19 | if (i % 24 === 0) { 20 | if (i) 21 | builder.push(''); 22 | builder.push(''); 23 | } 24 | builder.push('
 
'.format(i % 24, Math.ceil((i + 1) / 24) - 1, i)); 25 | } 26 | 27 | builder.push(''); 28 | 29 | container.append(builder.join('')); 30 | cells = self.find('.cell'); 31 | widgets = $(self.find('.widgets').eq(0)); 32 | size = self.getSize(); 33 | if (size.width < 300) { 34 | WAIT(function() { 35 | return $(window).width(); 36 | }, function(){ 37 | size = self.getSize(); 38 | self.operations.resize(); 39 | }); 40 | } 41 | 42 | self.event('click', '.widget-settings', function(button) { 43 | var button = $(this); 44 | var el = button.closest('.widget'); 45 | var w = el.find('[data-name]')[0]; 46 | self.emit('designer.contextmenu', button, el, w ? w.$widget : null); 47 | }); 48 | 49 | self.event('mousedown mousemove mouseup', function(e) { 50 | switch (e.type) { 51 | case 'mousemove': 52 | if (!move.drag && !widget.moving && !widget.resizing) 53 | return; 54 | 55 | var target = $(e.target); 56 | 57 | if (widget.moving || widget.resizing) { 58 | self.move_resize_mmove(e); 59 | } else if (target.hclass('cell') || target.hclass('space')) { 60 | self.mmove(e.pageX, e.pageY, e); 61 | } else { 62 | container.find('.selected').rclass('selected'); 63 | move.drag = false; 64 | } 65 | 66 | e.preventDefault(); 67 | break; 68 | case 'mousedown': 69 | if (e.which === 3 || e.button === 2) // ignore right click 70 | return; 71 | var el = $(e.target); 72 | if (el.hclass('move') || el.hclass('resize') || el.parent().hclass('resize')) { 73 | self.move_resize_mdown(el, e); 74 | } else 75 | self.mdown(e.pageX, e.pageY, e); 76 | // Clicks won't work if the code below is not commented 77 | // e.preventDefault(); 78 | break; 79 | case 'mouseup': 80 | if (widget.moving || widget.resizing) { 81 | widget.moving = false; 82 | widget.resizing = false; 83 | self.scroller_cursor(false); // reset 84 | var grid = widget.element.attr('data-grid').split(','); 85 | if (common.device === 'desktop') { 86 | grid[0] = widget.index; 87 | grid[1] = widget.size.cols; 88 | grid[2] = widget.size.rows; 89 | } else { 90 | grid[3] = widget.index; 91 | grid[4] = widget.size.cols; 92 | grid[5] = widget.size.rows; 93 | } 94 | widget.element.attr('data-grid', grid.join(',')); 95 | } else { 96 | if (!move.drag) 97 | return; 98 | self.mup(e.pageX, e.pageY, e); 99 | } 100 | 101 | // Clicks won't work if the code below is not commented 102 | //e.preventDefault(); 103 | break; 104 | } 105 | }); 106 | 107 | self.event('touchstart touchmove touchend', function(evt) { 108 | var e = evt.touches[0]; 109 | switch (evt.type) { 110 | case 'touchmove': 111 | 112 | if (!move.drag) 113 | return; 114 | 115 | var target = $(evt.target); 116 | if (target.hclass('cell') || target.hclass('space')) { 117 | self.mmove(e.pageX, e.pageY, e); 118 | } else { 119 | container.find('.selected').rclass('selected'); 120 | move.drag = false; 121 | } 122 | 123 | for (var i = 0, length = move.intervals.length; i < length; i++) { 124 | var int = move.intervals[i]; 125 | if (e.pageX >= int.x && e.pageX <= int.w && e.pageY >= int.y && e.pageY <= int.h) { 126 | container.find('.selected').rclass('selected'); 127 | move.drag = false; 128 | evt.preventDefault(); 129 | return; 130 | } 131 | } 132 | 133 | move.cacheX = e.pageX; 134 | move.cacheY = e.pageY; 135 | evt.preventDefault(); 136 | break; 137 | 138 | case 'touchstart': 139 | 140 | var target = $(evt.target); 141 | if (!target.hclass('cell')) 142 | return; 143 | 144 | move.intervals = []; 145 | var r = /px/; 146 | 147 | var off = container.offset(); 148 | 149 | widgets.find('.widget.tab_' + common.tab.id).each(function() { 150 | var el = $(this); 151 | var obj = { x: (+el.css('left').replace(r, '')) - 8, y: (+el.css('top').replace(r, '')) - 8, w: (+el.css('width').replace(r, '')) + 8, h: (+el.css('height').replace(r, '')) + 8 }; 152 | obj.x += off.left; 153 | obj.y += off.top; 154 | obj.w += obj.x; 155 | obj.h += obj.y; 156 | move.intervals.push(obj); 157 | }); 158 | 159 | self.mdown(e.pageX, e.pageY, e); 160 | evt.preventDefault(); 161 | break; 162 | 163 | case 'touchend': 164 | if (!move.drag) 165 | return; 166 | self.mup(move.cacheX, move.cacheY, e); 167 | evt.preventDefault(); 168 | break; 169 | } 170 | }); 171 | 172 | $(window).resize(self.operations.resize); 173 | WIDTH() === 'xs' && self.operations.resize(); 174 | }; 175 | 176 | self.getSize = function() { 177 | var obj = {}; 178 | obj.width = container.width(); 179 | obj.cell = 100 / 24; 180 | obj.pixels = (obj.width / 100) * obj.cell; 181 | obj.pixelsh = obj.pixels + 0.5; 182 | common.size = obj; 183 | return obj; 184 | }; 185 | 186 | self.scroller_cursor = function(el) { 187 | if (el === false) { 188 | scroller.css('cursor', 'default'); 189 | $('.widget-toolbar .move').css('cursor', 'move'); 190 | return; 191 | } 192 | 193 | if (el.hclass('move')) { 194 | scroller.css('cursor', 'move'); 195 | } else { 196 | scroller.css('cursor', 'se-resize'); 197 | $('.widget-toolbar .move').css('cursor', 'se-resize'); 198 | } 199 | }; 200 | 201 | self.move_resize_mdown = function(el, e) { 202 | 203 | widgets.find('.widget').each(function() { 204 | $(this).css('z-index', 2); 205 | }); 206 | 207 | self.scroller_cursor(el); 208 | widget.element = el.closest('.widget'); 209 | var offset = widget.element.offset(); 210 | widget.mouse_offset = { col: Math.floor((e.pageX - offset.left) / size.pixels), row: Math.floor((e.pageY - offset.top) / size.pixelsh)}; 211 | widget.zindex = widget.element.css('z-index'); 212 | widget.element.css('z-index', 15); 213 | var grid = self.grid(widget.element.attr('data-grid').split(',')); 214 | widget.index = grid.index; 215 | widget.size = { cols: grid.cols, rows: grid.rows }; 216 | widget.pos = self.getPosition(widget.index); 217 | widget.origin = { pos: CLONE(widget.pos), size: CLONE(widget.size) }; 218 | 219 | if (el.hclass('move')) { 220 | widget.moving = true; 221 | widget.move_cols = 0; 222 | widget.move_rows = 0; 223 | } else { 224 | widget.resizing = true; 225 | widget.resize_cols = 0; 226 | widget.resize_rows = 0; 227 | } 228 | }; 229 | 230 | self.move_resize_mmove = function(e) { 231 | 232 | var item = common.designer.findItem('id', widget.element.attr('data-id')); 233 | var offset = container.offset(); 234 | 235 | if (widget.moving) { 236 | var mouse_col = Math.floor((e.pageX - offset.left) / size.pixels); 237 | var mouse_row = Math.floor((e.pageY - offset.top) / size.pixelsh); 238 | var move_cols = mouse_col - widget.mouse_offset.col - widget.origin.pos.col; 239 | var move_rows = mouse_row - widget.mouse_offset.row - widget.origin.pos.row; 240 | if (widget.move_cols === move_cols && widget.move_rows === move_rows) 241 | return; 242 | var item_col = widget.index % 24; 243 | var item_row = Math.floor(widget.index / 24); 244 | if (item_col < 0 || item_row < 0) 245 | return; 246 | widget.move_cols = (widget.origin.pos.col + move_cols + widget.origin.size.cols) > 24 ? 24 - (widget.origin.pos.col + widget.origin.size.cols) : move_cols; 247 | widget.move_rows = move_rows; 248 | var col = widget.origin.pos.col + widget.move_cols; 249 | var row = widget.origin.pos.row + widget.move_rows; 250 | col = col < 0 ? 0 : col; 251 | row = row < 0 ? 0 : row; 252 | widget.element.animate({ left: col * size.pixels, top: row * size.pixelsh }, 15); 253 | widget.index = (row * 24) + col; 254 | if (item) 255 | item[common.device === 'desktop' ? 'index' : 'mindex'] = widget.index; 256 | } 257 | 258 | if (widget.resizing) { 259 | var resize_cols = Math.floor((e.pageX - offset.left) / size.pixelsh) - widget.mouse_offset.col - widget.origin.pos.col; 260 | var resize_rows = Math.floor((e.pageY - offset.top) / size.pixels) - widget.mouse_offset.row - widget.origin.pos.row; 261 | if ((widget.resize_cols === resize_cols && widget.resize_rows === resize_rows) || (widget.origin.pos.col + widget.origin.size.cols + resize_cols) > 24) 262 | return; 263 | widget.resize_cols = resize_cols; 264 | widget.resize_rows = resize_rows; 265 | widget.size.cols = +widget.origin.size.cols + resize_cols; 266 | widget.size.rows = +widget.origin.size.rows + resize_rows; 267 | if (widget.size.cols < 1) 268 | widget.size.cols = 1; 269 | if (widget.size.rows < 1) 270 | widget.size.rows = 1; 271 | widget.element.animate({ width: widget.size.cols * size.pixels, height: widget.size.rows * size.pixelsh }, 15); 272 | if (item) { 273 | item[common.device === 'desktop' ? 'cols' : 'mcols'] = widget.size.cols; 274 | item[common.device === 'desktop' ? 'rows' : 'mrows'] = widget.size.rows; 275 | var instance = widget.element.find('figure')[0].$widget; 276 | var padding = instance.size.padding; 277 | instance.size = { cols: widget.size.cols, rows: widget.size.rows, height: (size.pixelsh * widget.size.rows) - (padding * 2), width: (size.pixels * widget.size.cols) - (padding * 2), padding: padding, pixels: size.pixels }; 278 | instance.emit('resize', instance.size); 279 | } 280 | } 281 | }; 282 | 283 | self.mup = function() { 284 | move.drag = false; 285 | var selected = container.find('.selected'); 286 | if (!selected.length) 287 | return; 288 | var first = selected.first(); 289 | var last = selected.last(); 290 | var gridA = first.attrd('grid').split(','); 291 | var gridB = last.attrd('grid').split(','); 292 | var off = self.getStartPosition(+gridA[0], +gridA[1]); 293 | move.x = off.x; 294 | move.y = off.y; 295 | var cols = +gridB[0] - (+gridA[0]) + 1; 296 | var rows = +gridB[1] - (+gridA[1]) + 1; 297 | selected.aclass('locked').rclass('selected'); 298 | var index = +first.attrd('index'); 299 | var selection = { id: Date.now(), tab: common.tab.id, rows: rows, cols: cols, index: index, mrows: rows, mcols: cols, mindex: index }; 300 | self.create(selection, true); 301 | }; 302 | 303 | self.mdown = function(x, y, e) { 304 | move.drag = true; 305 | move.scrollX = scroller.prop('scrollLeft'); 306 | move.scrollY = scroller.prop('scrollTop'); 307 | var item = cells.eq(0); 308 | move.x = e.pageX - item.width(); 309 | move.y = e.pageY - item.height(); 310 | }; 311 | 312 | self.mmove = function(x, y) { 313 | 314 | var fx = x > move.x ? move.x : x - size.pixels; 315 | var fy = y > move.y ? move.y : y - size.pixelsh; 316 | var tx = x > move.x ? x : move.x + size.pixels; 317 | var ty = y > move.y ? y : move.y + size.pixelsh; 318 | cells.each(function() { 319 | var el = $(this); 320 | var offset = el.offset(); 321 | var is = offset.left >= fx && offset.left <= tx && offset.top >= fy && offset.top <= ty; 322 | el.tclass('selected', is); 323 | }); 324 | }; 325 | 326 | self.create = function(w) { 327 | var key = common.device === 'mobile' ? 'm' : ''; 328 | var pos = self.getPosition(w[key + 'index']); 329 | var grid = w.index + ',' + w.cols + ',' + w.rows + ',' + (w.mindex === 0 ? 0 : (w.mindex || w.index)) + ',' + (w.mcols === 0 ? 0 : (w.mcols || w.cols)) + ',' + (w.mrows === 0 ? 0 : (w.mrows || w.rows)); 330 | var html = ''; 331 | html = html.format(pos.col * size.pixels, pos.row * size.pixelsh, w[key + 'cols'] * size.pixels, w[key + 'rows'] * size.pixelsh, grid, w.tab, w.id, w.app ? '
'.format(w.app) : ''); 332 | widgets.append(html); 333 | self.operations.tab(); 334 | }; 335 | 336 | self.compile = function() { 337 | 338 | var size = self.getSize(); 339 | var device = WIDTH(); 340 | var csswh = {}; 341 | 342 | widgets.find('figure[data-name]').each(function() { 343 | var el = $(this); 344 | if (this.$widget) 345 | return; 346 | 347 | var w = el.closest('.widget'); 348 | var grid = w.attr('data-grid').split(','); 349 | var id = w.attr('data-id'); 350 | 351 | var instance = common.designer.findItem('id', id); 352 | var declaration = common.database.findItem('name', el.attr('data-name')); 353 | 354 | if (!declaration) 355 | return; 356 | 357 | var opt = {}; 358 | opt.index = +grid[0]; 359 | opt.cols = +grid[1]; 360 | opt.rows = +grid[2]; 361 | opt.mindex = +grid[3]; 362 | opt.mcols = +grid[4]; 363 | opt.mrows = +grid[5]; 364 | opt.device = device; 365 | opt.width = opt[common.device === 'desktop' ? 'cols' : 'mcols'] * size.pixels; 366 | opt.height = opt[common.device === 'desktop' ? 'rows' : 'mrows'] * size.pixelsh; 367 | 368 | if (!instance) { 369 | instance = { id: id, app: declaration.name, index: opt.index, cols: opt.cols, rows: opt.rows, mindex: opt.mindex, mcols: opt.mcols, mrows: opt.mrows, tab: self.attr('data-tab'), options: null }; 370 | common.designer.push(instance); 371 | } 372 | 373 | opt.padding = (w.css('padding') || '').parseInt(); 374 | 375 | this.$widget = new Instance(id, el, declaration, instance.options, opt); 376 | this.$widget.$events[device] && this.$widget.emit(device, opt); 377 | csswh.width = opt.width; 378 | csswh.height = opt.height; 379 | // this.$widget.css(csswh); 380 | var k; 381 | if (common.device === 'desktop') 382 | k = opt.cols + 'x' + opt.rows; 383 | else 384 | k = opt.mcols + 'x' + opt.mrows; 385 | this.$widget.$events[k] && this.$widget.emit(k, opt); 386 | }); 387 | 388 | setTimeout2('designer.tabs', function() { 389 | self.operations.tab(); 390 | }, 100); 391 | }; 392 | 393 | self.getPosition = function(index) { 394 | var ri = (index / 24) >> 0; 395 | var ci = index % 24; 396 | return { row: ri, col: ci }; 397 | }; 398 | 399 | self.getStartPosition = function(col, row) { 400 | var obj = {}; 401 | obj.x = col * size.pixels; 402 | obj.y = row * size.pixelsh; 403 | return obj; 404 | }; 405 | 406 | self.operations = {}; 407 | self.operations.save = function() { 408 | var items = []; 409 | 410 | widgets.find('.widget').each(function() { 411 | var el = $(this); 412 | var pos = el.attr('data-grid').split(','); 413 | var app = el.find('[data-name]'); 414 | items.push({ id: el.attrd('id'), index: +pos[0], cols: +pos[1], rows: +pos[2], mindex: +pos[3], mcols: +pos[4], mrows: +pos[5], tab: el.attrd('tab'), app: app.length ? app.attrd('name') : null, options: app.length && app[0].$widget ? app[0].$widget.options : null }); 415 | }); 416 | 417 | var data = {}; 418 | data.items = items; 419 | return data; 420 | }; 421 | 422 | self.operations.load = function(data, callback) { 423 | 424 | var arr = []; 425 | 426 | widgets.find('figure[data-name]').each(function() { 427 | arr.push(this.$widget); 428 | }); 429 | 430 | arr.wait(function(item, next) { 431 | item.destroy(); 432 | setTimeout(next, 30); 433 | }, function() { 434 | setTimeout2('designer.clear', function() { 435 | 436 | widgets.empty(); 437 | data.items.forEach(function(item) { 438 | self.create(item); 439 | }); 440 | 441 | self.compile(); 442 | 443 | common.tabs = data.tabs; 444 | 445 | if (!common.tabs || !common.tabs.length) { 446 | common.tabs = []; 447 | common.tabs.push({ id: Date.now().toString(), name: 'Main', icon: 'fa-object-ungroup', linker: 'main' }); 448 | } 449 | 450 | UPDATE('common.tabs'); 451 | SETTER('binder', 'scan'); 452 | 453 | var hash = location.hash.substring(1); 454 | var tab = common.tabs.findItem('linker', hash); 455 | 456 | if (!tab) 457 | tab = common.tabs[0]; 458 | 459 | SET('common.tab', tab); 460 | callback && setTimeout(callback, 100); 461 | 462 | }, widgets.length ? 500 : 0); 463 | }); 464 | }; 465 | 466 | self.operations.upgrade = function(component) { 467 | 468 | var arr = []; 469 | 470 | widgets.find('figure[data-name="{0}"]'.format(component.name)).each(function() { 471 | var el = $(this).parent(); 472 | var widget = this.$widget; 473 | widget.destroy(); 474 | arr.push({ el: el, html: '
'.format(component.name) }); 475 | }); 476 | 477 | setTimeout(function() { 478 | arr.wait(function(item, next) { 479 | item.el.html(item.html); 480 | next(); 481 | }, self.compile); 482 | }, 100); 483 | }; 484 | 485 | self.operations.tabclear = function(id) { 486 | widgets.find('.tab_' + id).each(function() { 487 | var el = $(this); 488 | var widget = el.find('figure[data-name]')[0]; 489 | 490 | if (!widget) { 491 | el.remove(); 492 | return; 493 | } 494 | 495 | widget = widget.$widget; 496 | widget && widget.destroy(); 497 | setTimeout(function() { 498 | el.remove(); 499 | }, 100); 500 | }); 501 | }; 502 | 503 | self.operations.tab = function() { 504 | setTimeout2('designer.tabs', function() { 505 | widgets.find('.widget').each(function() { 506 | var el = $(this); 507 | var hidden = el.hclass('hidden'); 508 | if (el.hclass('tab_' + common.tab.id)) { 509 | hidden && el.rclass('hidden'); 510 | } else { 511 | !hidden && el.aclass('hidden'); 512 | } 513 | }); 514 | }, 100); 515 | }; 516 | 517 | self.grid = function(grid) { 518 | var g = {}; 519 | if (common.device === 'desktop') { 520 | g.index = +grid[0]; 521 | g.cols = +grid[1]; 522 | g.rows = +grid[2]; 523 | } else { 524 | g.index = +grid[3]; 525 | g.cols = +grid[4]; 526 | g.rows = +grid[5]; 527 | } 528 | return g; 529 | }; 530 | 531 | self.operations.resize = function() { 532 | 533 | if (!common.draft) 534 | common.device = WIDTH() === 'xs' ? 'mobile' : 'desktop'; 535 | 536 | setTimeout2(self.id + '.resize', function() { 537 | 538 | size = self.getSize(); 539 | 540 | var device = WIDTH(); 541 | var css = {}; 542 | var csswh = {}; 543 | 544 | cells.css('height', size.pixelsh + 'px'); 545 | 546 | widgets.find('.widget').each(function() { 547 | var el = $(this); 548 | var grid = self.grid(el.attrd('grid').split(',')); 549 | var cols = grid.cols; 550 | var rows = grid.rows; 551 | var index = grid.index; 552 | var pos = self.getPosition(index); 553 | 554 | css.left = pos.col * size.pixels + 'px'; 555 | css.top = pos.row * size.pixelsh + 'px'; 556 | css.width = cols * size.pixels + 'px'; 557 | css.height = rows * size.pixelsh + 'px'; 558 | el.css(css); 559 | 560 | var app = el.find('[data-name]')[0]; 561 | if (app) { 562 | var opt = {}; 563 | opt.cols = cols; 564 | opt.rows = rows; 565 | opt.device = device; 566 | opt.width = cols * size.pixels; 567 | opt.height = rows * size.pixelsh; 568 | opt.padding = (el.css('padding') || '').parseInt(); 569 | csswh.width = opt.width; 570 | csswh.height = opt.height; 571 | if (app.$widget) { 572 | var sz = app.$widget.size = CLONE(opt); 573 | if (sz.padding > 0) { 574 | sz.width -= sz.padding * 2; 575 | sz.height -= sz.padding * 2; 576 | } 577 | app.$widget.$events.resize && app.$widget.emit('resize', sz); 578 | app.$widget.$events[device] && app.$widget.emit(device, sz); 579 | } 580 | } 581 | }); 582 | }, 100, 10); 583 | }; 584 | 585 | }); 586 | 587 | COMPONENT('controls', function(self) { 588 | 589 | var is = false; 590 | var timeout; 591 | var container; 592 | 593 | self.template = Tangular.compile('
{{ name | raw }}
'); 594 | self.singleton(); 595 | self.readonly(); 596 | self.callback = null; 597 | 598 | self.make = function() { 599 | 600 | self.aclass('ui-controls'); 601 | self.append('
'); 602 | container = self.find('.ui-controls-items'); 603 | 604 | self.event('touchstart mousedown', 'div[data-value]', function(e) { 605 | var el = $(this); 606 | !el.hclass('disabled') && self.callback && self.callback(self.items[+el.attr('data-value')], $(self.target)); 607 | self.hide(); 608 | e.preventDefault(); 609 | e.stopPropagation(); 610 | }); 611 | 612 | $(document).on('touchstart mousedown', function() { 613 | SETTER('controls', 'hide'); 614 | }); 615 | }; 616 | 617 | self.show = function(target, items, callback, offsetX) { 618 | 619 | if (is) { 620 | clearTimeout(timeout); 621 | var obj = target instanceof jQuery ? target[0] : target; 622 | if (self.target === obj) { 623 | self.hide(0); 624 | return; 625 | } 626 | } 627 | 628 | target = $(target); 629 | var type = typeof(items); 630 | var item; 631 | 632 | if (type === 'string') 633 | items = self.get(items); 634 | else if (type === 'function') { 635 | callback = items; 636 | items = (target.attr('data-options') || '').split(';'); 637 | for (var i = 0, length = items.length; i < length; i++) { 638 | item = items[i]; 639 | if (!item) 640 | continue; 641 | var val = item.split('|'); 642 | items[i] = { name: val[0], icon: val[1], value: val[2] === undefined ? val[0] : val[2] }; 643 | } 644 | } 645 | 646 | if (!items) { 647 | self.hide(0); 648 | return; 649 | } 650 | 651 | self.callback = callback; 652 | self.items = items; 653 | 654 | var builder = []; 655 | 656 | for (var i = 0, length = items.length; i < length; i++) { 657 | item = items[i]; 658 | 659 | if (typeof(item) === 'string') { 660 | builder.push('
{0}
'.format(item, i === 0 ? ' style="margin-top:0"' : '')); 661 | continue; 662 | } 663 | 664 | item.index = i; 665 | if (item.value === undefined) 666 | item.value = item.name; 667 | if (!item.icon) 668 | item.icon = 'fa-caret-right'; 669 | 670 | var tmp = self.template(item); 671 | if (item.url) 672 | tmp = tmp.replace('$/g, 'a>'); 673 | 674 | builder.push(tmp); 675 | } 676 | 677 | builder.push('
'); 678 | 679 | var off = target.closest('.widget').offset(); 680 | 681 | self.target = target[0]; 682 | var offset = target.offset(); 683 | var scroller = $('.designer-scroll'); 684 | 685 | offset.left += scroller.scrollLeft(); 686 | offset.top += scroller.scrollTop() - (off ? off.top : 0); 687 | 688 | container.html(builder); 689 | 690 | var options = { left: (offset.left - 8 + (offsetX || 0)), top: offset.top + target.innerHeight() + 10 }; 691 | self.css(options); 692 | 693 | if (is) 694 | return; 695 | 696 | self.element.show(); 697 | setTimeout(function() { 698 | self.classes('ui-controls-visible'); 699 | self.emit('controls', true, self, self.target); 700 | }, 100); 701 | 702 | is = true; 703 | }; 704 | 705 | self.hide = function(sleep) { 706 | if (!is) 707 | return; 708 | clearTimeout(timeout); 709 | timeout = setTimeout(function() { 710 | self.element.hide().rclass('ui-controls-visible'); 711 | self.emit('controls', false, self, self.target); 712 | self.callback = null; 713 | self.target = null; 714 | is = false; 715 | }, sleep ? sleep : 100); 716 | }; 717 | }); 718 | 719 | COMPONENT('devicetype', function(self, config) { 720 | 721 | self.configure = function(key, value, init) { 722 | if (init) 723 | return; 724 | switch (key) { 725 | case 'items': 726 | self.find('span').remove(); 727 | var builder = []; 728 | value.split(',').forEach(function(item) { 729 | item = item.split('|'); 730 | builder.push('{1}'.format(item[1] || item[0], item[0] || item[1])); 731 | }); 732 | self.append(builder.join('')); 733 | self.refresh(); 734 | break; 735 | } 736 | }; 737 | 738 | self.make = function() { 739 | var builder = []; 740 | self.aclass('ui-devicetype'); 741 | self.event('click', 'span', function() { 742 | if (config.disabled) 743 | return; 744 | var value = $(this).attrd('value'); 745 | self.set(value); 746 | self.change(true); 747 | }); 748 | self.html(builder.join('')); 749 | config.items && self.reconfigure('items:' + config.items); 750 | config.type && (self.type = config.type); 751 | }; 752 | 753 | self.validate = function(value) { 754 | return config.disabled || !config.required ? true : !!value; 755 | }; 756 | 757 | self.setter = function(value) { 758 | self.find('span').each(function() { 759 | var el = $(this); 760 | var is = el.attrd('value') === (value == null ? null : value.toString()); 761 | el.tclass('ui-devicetype-selected', is); 762 | }); 763 | }; 764 | }); -------------------------------------------------------------------------------- /source/templates/form-components.html: -------------------------------------------------------------------------------- 1 | 21 | 22 | -------------------------------------------------------------------------------- /source/templates/form-database.html: -------------------------------------------------------------------------------- 1 | 66 | 67 | -------------------------------------------------------------------------------- /source/templates/form-tab.html: -------------------------------------------------------------------------------- 1 | 32 | 33 | -------------------------------------------------------------------------------- /source/templates/form-widgets.html: -------------------------------------------------------------------------------- 1 | 30 | 31 | 69 | 70 | --------------------------------------------------------------------------------