├── styles.css ├── src ├── assets │ ├── .gitkeep │ ├── img │ │ └── du.gif │ └── css │ │ ├── prettify.css │ │ ├── sons-of-obsidian.css │ │ ├── desert.css │ │ ├── sunburst.css │ │ ├── doxy.css │ │ ├── busy.css │ │ └── bootstrap.min.css ├── app │ ├── app.component.css │ ├── app.component.html │ ├── modules │ │ └── ng-busy-demo │ │ │ ├── component │ │ │ ├── demo │ │ │ │ ├── demo.component.css │ │ │ │ ├── demo.component.ts │ │ │ │ ├── demo.component.html │ │ │ │ └── demo.component.spec.ts │ │ │ ├── code-viewer │ │ │ │ ├── code-viewer.component.css │ │ │ │ ├── code-viewer.component.html │ │ │ │ ├── code-viewer.component.spec.ts │ │ │ │ └── code-viewer.component.ts │ │ │ ├── custom-busy-component │ │ │ │ ├── custom-busy-component.component.css │ │ │ │ ├── custom-busy-component.component.html │ │ │ │ ├── custom-busy-component.component.spec.ts │ │ │ │ └── custom-busy-component.component.ts │ │ │ ├── table │ │ │ │ ├── table.component.css │ │ │ │ ├── table.component.html │ │ │ │ ├── table.component.spec.ts │ │ │ │ └── table.component.ts │ │ │ ├── options │ │ │ │ ├── options.component.css │ │ │ │ ├── options.component.spec.ts │ │ │ │ ├── options.component.html │ │ │ │ └── options.component.ts │ │ │ ├── header │ │ │ │ ├── header.component.html │ │ │ │ ├── header.component.css │ │ │ │ ├── header.component.ts │ │ │ │ └── header.component.spec.ts │ │ │ └── github-corner │ │ │ │ ├── github-corner.component.ts │ │ │ │ ├── github-corner.component.spec.ts │ │ │ │ ├── github-corner.component.css │ │ │ │ └── github-corner.component.html │ │ │ ├── ng-busy-demo.module.spec.ts │ │ │ ├── service │ │ │ ├── template.service.spec.ts │ │ │ └── template.service.ts │ │ │ └── ng-busy-demo.module.ts │ ├── app.component.ts │ ├── app.module.ts │ └── app.component.spec.ts ├── favicon.ico ├── styles.css ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── tsconfig.app.json ├── tsconfig.spec.json ├── index.html ├── tslint.json ├── main.ts ├── test.ts ├── karma.conf.js └── polyfills.ts ├── projects └── ng-busy │ ├── src │ ├── lib │ │ ├── component │ │ │ └── ng-busy │ │ │ │ ├── ng-busy.component.css │ │ │ │ ├── ng-busy.component.html │ │ │ │ ├── ng-busy.component.ts │ │ │ │ └── ng-busy.component.spec.ts │ │ ├── util │ │ │ └── isPromise.ts │ │ ├── service │ │ │ ├── instance-config-holder.service.ts │ │ │ ├── busy-config-holder.service.ts │ │ │ ├── instance-config-holder.service.spec.ts │ │ │ ├── busy-config-holder.service.spec.ts │ │ │ ├── busy-tracker.service.ts │ │ │ └── busy-tracker.service.spec.ts │ │ ├── ng-busy.module.ts │ │ ├── style │ │ │ └── busy.less │ │ ├── model │ │ │ └── busy-config.ts │ │ ├── ng-busy.directive.ts │ │ └── ng-busy.directive.spec.ts │ ├── public_api.ts │ └── test.ts │ ├── tsconfig.lib.prod.json │ ├── ng-package.prod.json │ ├── ng-package.json │ ├── tsconfig.spec.json │ ├── tslint.json │ ├── tsconfig.lib.json │ ├── package.json │ ├── karma.conf.js │ └── README.md ├── .browserslistrc ├── .vscode ├── launch.json └── tasks.json ├── tsconfig.json ├── .travis.yml ├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── tslint.json └── angular.json /styles.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/demo/demo.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/component/ng-busy/ng-busy.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/code-viewer/code-viewer.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victos/angular-opensource/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/custom-busy-component/custom-busy-component.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /src/assets/img/du.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victos/angular-opensource/HEAD/src/assets/img/du.gif -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/custom-busy-component/custom-busy-component.component.html: -------------------------------------------------------------------------------- 1 |

2 | custom-busy-component works! 3 |

4 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/table/table.component.css: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Table style 3 | * @author yumao 4 | */ 5 | .table { 6 | position: relative; 7 | } 8 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/code-viewer/code-viewer.component.html: -------------------------------------------------------------------------------- 1 | The current options of ngBusy is :
2 | {{optionsForShow}} 3 |

4 | The code of the template is:
-------------------------------------------------------------------------------- /projects/ng-busy/src/lib/util/isPromise.ts: -------------------------------------------------------------------------------- 1 | export function isPromise(value: any): value is PromiseLike { 2 | return value && typeof (value).subscribe !== 'function' && typeof (value as any).then === 'function'; 3 | } 4 | -------------------------------------------------------------------------------- /projects/ng-busy/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false 5 | }, 6 | "angularCompilerOptions": { 7 | "compilationMode": "partial" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/options/options.component.css: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Options style 3 | * @author yumao 4 | */ 5 | .c-checkbox { 6 | line-height: 36px; 7 | } 8 | 9 | #template-ng-style { 10 | height: 100px; 11 | } -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'app'; 10 | } 11 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/header/header.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Ng Busy

4 |

Show busy/loading indicators on any promise, or on any Observable's subscription.

5 |
6 |
7 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "main.ts", 9 | "polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /projects/ng-busy/ng-package.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/ng-busy", 4 | "lib": { 5 | "entryFile": "src/public_api.ts" 6 | }, 7 | "allowedNonPeerDependencies": ["rxjs", "@angular/common", "@angular/core", "@angular/animations"] 8 | } 9 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/service/instance-config-holder.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {IBusyConfig} from '../model/busy-config'; 3 | 4 | @Injectable({ 5 | providedIn: 'any' 6 | }) 7 | export class InstanceConfigHolderService { 8 | public config: IBusyConfig; 9 | constructor() { } 10 | } 11 | -------------------------------------------------------------------------------- /projects/ng-busy/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/ng-busy", 4 | "deleteDestPath": false, 5 | "lib": { 6 | "entryFile": "src/public_api.ts" 7 | }, 8 | "allowedNonPeerDependencies": ["rxjs", "@angular/common", "@angular/core", "@angular/animations"] 9 | } 10 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/component/ng-busy/ng-busy.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 |
6 |
7 |
8 | -------------------------------------------------------------------------------- /projects/ng-busy/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts" 12 | ], 13 | "include": [ 14 | "**/*.spec.ts", 15 | "**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/header/header.component.css: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Header style 3 | * @author yumao 4 | */ 5 | header { 6 | padding: 3rem .9375rem; 7 | margin-bottom: 3rem; 8 | background: #b03a58; 9 | color: #e8bac5; 10 | } 11 | 12 | header h1 { 13 | color: #fff; 14 | font-size: 3rem; 15 | } 16 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AngularOpensource 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-header', 5 | templateUrl: './header.component.html', 6 | styleUrls: ['./header.component.css'] 7 | }) 8 | export class HeaderComponent implements OnInit { 9 | 10 | constructor() { 11 | } 12 | 13 | ngOnInit() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # For IE 9-11 support, please uncomment the last line of the file and adjust as needed 5 | > 0.5% 6 | last 2 versions 7 | Firefox ESR 8 | not dead 9 | # IE 9-11 -------------------------------------------------------------------------------- /projects/ng-busy/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "lib", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "lib", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/ng-busy-demo.module.spec.ts: -------------------------------------------------------------------------------- 1 | import {NgBusyDemoModule} from './ng-busy-demo.module'; 2 | 3 | describe('NgBusyDemoModule', () => { 4 | let ngBusyDemoModule: NgBusyDemoModule; 5 | 6 | beforeEach(() => { 7 | ngBusyDemoModule = new NgBusyDemoModule(); 8 | }); 9 | 10 | it('should create an instance', () => { 11 | expect(ngBusyDemoModule).toBeTruthy(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.log(err)); 13 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/github-corner/github-corner.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-github-corner', 5 | templateUrl: './github-corner.component.html', 6 | styleUrls: ['./github-corner.component.css'] 7 | }) 8 | export class GithubCornerComponent implements OnInit { 9 | 10 | constructor() { 11 | } 12 | 13 | ngOnInit() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/demo/demo.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, ViewEncapsulation} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-busy-demo', 5 | templateUrl: './demo.component.html', 6 | encapsulation: ViewEncapsulation.None, 7 | styleUrls: ['./demo.component.css'] 8 | }) 9 | export class DemoComponent implements OnInit { 10 | 11 | constructor() { 12 | } 13 | 14 | ngOnInit() { 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/service/busy-config-holder.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable, Optional} from '@angular/core'; 2 | import {BUSY_CONFIG_DEFAULTS, BusyConfig} from '../model/busy-config'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class BusyConfigHolderService { 8 | config: BusyConfig; 9 | 10 | constructor(@Optional() config: BusyConfig) { 11 | this.config = Object.assign({}, BUSY_CONFIG_DEFAULTS, config || new BusyConfig()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/service/template.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {TestBed, inject} from '@angular/core/testing'; 2 | 3 | import {TemplateService} from './template.service'; 4 | 5 | describe('TemplateService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [TemplateService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([TemplateService], (service: TemplateService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:4200", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {BrowserModule} from '@angular/platform-browser'; 2 | import {NgModule} from '@angular/core'; 3 | 4 | import {AppComponent} from './app.component'; 5 | import {NgBusyDemoModule} from './modules/ng-busy-demo/ng-busy-demo.module'; 6 | 7 | @NgModule({ 8 | declarations: [ 9 | AppComponent 10 | ], 11 | imports: [ 12 | BrowserModule, 13 | NgBusyDemoModule 14 | ], 15 | providers: [], 16 | bootstrap: [AppComponent] 17 | }) 18 | export class AppModule { 19 | } 20 | -------------------------------------------------------------------------------- /projects/ng-busy/src/public_api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of ng-busy 3 | */ 4 | 5 | export * from "./lib/ng-busy.module"; 6 | export * from "./lib/util/isPromise"; 7 | export * from "./lib/model/busy-config"; 8 | export { NgBusyDirective } from "./lib/ng-busy.directive"; 9 | export { NgBusyComponent } from "./lib/component/ng-busy/ng-busy.component"; 10 | export { InstanceConfigHolderService } from "./lib/service/instance-config-holder.service"; 11 | export { BusyTrackerService } from "./lib/service/busy-tracker.service"; 12 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "start", 9 | "problemMatcher": [] 10 | }, 11 | { 12 | "type": "npm", 13 | "script": "build", 14 | "path": "projects/ng-busy/", 15 | "problemMatcher": [] 16 | }, 17 | { 18 | "type": "npm", 19 | "script": "build", 20 | "problemMatcher": [] 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | // First, initialize the Angular testing environment. 11 | getTestBed().initTestEnvironment( 12 | BrowserDynamicTestingModule, 13 | platformBrowserDynamicTesting(), { 14 | teardown: { destroyAfterEach: false } 15 | } 16 | ); 17 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/service/instance-config-holder.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { InstanceConfigHolderService } from './instance-config-holder.service'; 4 | 5 | describe('InstanceConfigHolderService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [InstanceConfigHolderService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([InstanceConfigHolderService], (service: InstanceConfigHolderService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /projects/ng-busy/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js'; 4 | import 'zone.js/testing'; 5 | import { getTestBed } from '@angular/core/testing'; 6 | import { 7 | BrowserDynamicTestingModule, 8 | platformBrowserDynamicTesting 9 | } from '@angular/platform-browser-dynamic/testing'; 10 | 11 | // First, initialize the Angular testing environment. 12 | getTestBed().initTestEnvironment( 13 | BrowserDynamicTestingModule, 14 | platformBrowserDynamicTesting(), { 15 | teardown: { destroyAfterEach: false } 16 | } 17 | ); 18 | -------------------------------------------------------------------------------- /src/assets/css/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.clo,.opn,.pun{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.kwd,.tag,.typ{font-weight:700}.str{color:#060}.kwd{color:#006}.com{color:#600;font-style:italic}.typ{color:#404}.lit{color:#044}.clo,.opn,.pun{color:#440}.tag{color:#006}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "importHelpers": true, 6 | "esModuleInterop": true, 7 | "module": "esnext", 8 | "outDir": "./dist/out-tsc", 9 | "sourceMap": true, 10 | "declaration": false, 11 | "moduleResolution": "node", 12 | "experimentalDecorators": true, 13 | "target": "ES2022", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2020", 19 | "dom" 20 | ], 21 | "paths": { 22 | "ng-busy": [ 23 | "dist/ng-busy" 24 | ] 25 | }, 26 | "useDefineForClassFields": false 27 | } 28 | } -------------------------------------------------------------------------------- /src/assets/css/sons-of-obsidian.css: -------------------------------------------------------------------------------- 1 | .str{color:#ec7600}.kwd{color:#93c763}.com{color:#66747b}.typ{color:#678cb1}.lit{color:#facd22}.pun{color:#f1f2f3}.pln{color:#f1f2f3}.tag{color:#8ac763}.atn{color:#e0e2e4}.atv{color:#ec7600}.dec{color:purple}pre.prettyprint{border:0 solid #888}ol.linenums{margin-top:0;margin-bottom:0}.prettyprint{background:#000}li.L0,li.L1,li.L2,li.L3,li.L4,li.L5,li.L6,li.L7,li.L8,li.L9{color:#555;list-style-type:decimal}li.L1,li.L3,li.L5,li.L7,li.L9{background:#111}@media print{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun{color:#440}.pln{color:#000}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}} -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * In development mode, to ignore zone related error stack frames such as 11 | * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can 12 | * import the following file, but please comment it out in production mode 13 | * because it will have performance impact when throw error 14 | */ 15 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 16 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/header/header.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {HeaderComponent} from './header.component'; 4 | 5 | describe('HeaderComponent', () => { 6 | let component: HeaderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [HeaderComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HeaderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - linux 3 | dist: trusty 4 | services: 5 | - docker 6 | language: node_js 7 | node_js: 8 | - '12' 9 | addons: 10 | chrome: stable 11 | cache: 12 | yarn: true 13 | directories: 14 | - $HOME/.yarn-cache 15 | - node_modules 16 | branches: 17 | only: 18 | - master 19 | before_install: 20 | - export CHROME_BIN=/usr/bin/google-chrome 21 | - export DISPLAY=:99.0 22 | - sh -e /etc/init.d/xvfb start 23 | - curl -o- -L https://yarnpkg.com/install.sh | bash 24 | - export PATH=$HOME/.yarn/bin:$PATH 25 | - yarn global add @angular/cli 26 | install: 27 | - yarn install 28 | script: 29 | - ng test ng-busy --watch=false 30 | - ng build ng-busy --prod 31 | # - ng test angular-opensource --watch=false 32 | notifications: 33 | webhooks: 34 | on_success: change 35 | on_failure: always 36 | on_start: false 37 | -------------------------------------------------------------------------------- /projects/ng-busy/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/lib", 5 | "declarationMap": true, 6 | "module": "es2020", 7 | "moduleResolution": "node", 8 | "declaration": true, 9 | "sourceMap": true, 10 | "inlineSources": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "types": [], 14 | "lib": [ 15 | "dom", 16 | "es2020" 17 | ] 18 | }, 19 | "angularCompilerOptions": { 20 | "skipTemplateCodegen": true, 21 | "strictMetadataEmit": true, 22 | "fullTemplateTypeCheck": true, 23 | "strictInjectionParameters": true, 24 | "flatModuleId": "AUTOGENERATED", 25 | "flatModuleOutFile": "AUTOGENERATED" 26 | }, 27 | "exclude": [ 28 | "src/test.ts", 29 | "**/*.spec.ts" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/github-corner/github-corner.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {GithubCornerComponent} from './github-corner.component'; 4 | 5 | describe('GithubCornerComponent', () => { 6 | let component: GithubCornerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [GithubCornerComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(GithubCornerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/table/table.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
#NameSpeciesOccupation
1Arthur DentHumanRadio Employee
2Ford PrefectBetelgeusianResearcher
3MarvinRobotServant
31 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/demo/demo.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 |
7 | 8 |
9 |
10 | 11 |
12 |
13 |
14 |
15 |
16 | 17 |
18 |
19 | 20 | 21 |
Hi, This is from ng-template.
22 |
23 |
-------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.angular/cache 29 | /.sass-cache 30 | /connect.lock 31 | /coverage 32 | /libpeerconnection.log 33 | npm-debug.log 34 | testem.log 35 | /typings 36 | 37 | # e2e 38 | /e2e/*.js 39 | /e2e/*.map 40 | 41 | # System Files 42 | .DS_Store 43 | Thumbs.db 44 | *.iml 45 | package-lock.json 46 | .circleci/ 47 | e2e/src/ 48 | e2e/tsconfig.e2e.json 49 | yarn.lock 50 | yarn-error.log 51 | .vim/* 52 | pnpm-lock.yaml -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/service/busy-config-holder.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { BusyConfigHolderService } from './busy-config-holder.service'; 4 | import {BusyConfig} from '../model/busy-config'; 5 | 6 | describe('BusyConfigHolderService', () => { 7 | beforeEach(() => { 8 | TestBed.configureTestingModule({ 9 | providers: [BusyConfigHolderService, {provide: BusyConfig, useValue: {message: 'the message should be this'}}] 10 | }); 11 | }); 12 | 13 | it('should be created', inject([BusyConfigHolderService], (service: BusyConfigHolderService) => { 14 | expect(service).toBeTruthy(); 15 | })); 16 | 17 | it('should load BusyConfig', inject([BusyConfigHolderService], (service: BusyConfigHolderService) => { 18 | expect(service.config.message).toBe('the message should be this'); 19 | })); 20 | }); 21 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/github-corner/github-corner.component.css: -------------------------------------------------------------------------------- 1 | .github-corner svg { 2 | position: absolute; 3 | top: 0; 4 | border: 0; 5 | right: 0; 6 | fill: #fff; 7 | color: #b03a58; 8 | } 9 | 10 | .github-corner .octo-arm { 11 | transform-origin: 130px 106px; 12 | } 13 | 14 | .github-corner:hover .octo-arm { 15 | animation: octocat-wave 560ms ease-in-out; 16 | } 17 | 18 | @media (max-width: 500px) { 19 | .github-corner .octo-arm { 20 | animation: octocat-wave 560ms ease-in-out; 21 | } 22 | 23 | .github-corner:hover .octo-arm { 24 | animation: none; 25 | } 26 | } 27 | 28 | @keyframes octocat-wave { 29 | 0%, 30 | 100% { 31 | transform: rotate(0); 32 | } 33 | 20%, 34 | 60% { 35 | transform: rotate(-25deg); 36 | } 37 | 40%, 38 | 80% { 39 | transform: rotate(10deg); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/assets/css/desert.css: -------------------------------------------------------------------------------- 1 | pre.prettyprint{display:block;background-color:#333}pre .nocode{background-color:none;color:#000}pre .str{color:#ffa0a0}pre .kwd{color:#f0e68c;font-weight:bold}pre .com{color:#87ceeb}pre .typ{color:#98fb98}pre .lit{color:#cd5c5c}pre .pun{color:#fff}pre .pln{color:#fff}pre .tag{color:#f0e68c;font-weight:bold}pre .atn{color:#bdb76b;font-weight:bold}pre .atv{color:#ffa0a0}pre .dec{color:#98fb98}ol.linenums{margin-top:0;margin-bottom:0;color:#aeaeae}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}@media print{pre.prettyprint{background-color:none}pre .str,code .str{color:#060}pre .kwd,code .kwd{color:#006;font-weight:bold}pre .com,code .com{color:#600;font-style:italic}pre .typ,code .typ{color:#404;font-weight:bold}pre .lit,code .lit{color:#044}pre .pun,code .pun{color:#440}pre .pln,code .pln{color:#000}pre .tag,code .tag{color:#006;font-weight:bold}pre .atn,code .atn{color:#404}pre .atv,code .atv{color:#060}} -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/table/table.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {TableComponent} from './table.component'; 4 | import {NgBusyModule} from 'ng-busy'; 5 | import {TemplateService} from '../../service/template.service'; 6 | 7 | describe('TableComponent', () => { 8 | let component: TableComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(waitForAsync(() => { 12 | TestBed.configureTestingModule({ 13 | imports: [NgBusyModule], 14 | declarations: [TableComponent], 15 | providers: [TemplateService] 16 | }) 17 | .compileComponents(); 18 | })); 19 | 20 | beforeEach(() => { 21 | fixture = TestBed.createComponent(TableComponent); 22 | component = fixture.componentInstance; 23 | fixture.detectChanges(); 24 | }); 25 | 26 | it('should create', () => { 27 | expect(component).toBeTruthy(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/assets/css/sunburst.css: -------------------------------------------------------------------------------- 1 | pre .str,code .str{color:#65b042}pre .kwd,code .kwd{color:#e28964}pre .com,code .com{color:#aeaeae;font-style:italic}pre .typ,code .typ{color:#89bdff}pre .lit,code .lit{color:#3387cc}pre .pun,code .pun{color:#fff}pre .pln,code .pln{color:#fff}pre .tag,code .tag{color:#89bdff}pre .atn,code .atn{color:#bdb76b}pre .atv,code .atv{color:#65b042}pre .dec,code .dec{color:#3387cc}pre.prettyprint,code.prettyprint{background-color:#000;border-radius:8px}pre.prettyprint{width:95%;margin:1em auto;padding:1em;white-space:pre-wrap}ol.linenums{margin-top:0;margin-bottom:0;color:#aeaeae}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}@media print{pre .str,code .str{color:#060}pre .kwd,code .kwd{color:#006;font-weight:bold}pre .com,code .com{color:#600;font-style:italic}pre .typ,code .typ{color:#404;font-weight:bold}pre .lit,code .lit{color:#044}pre .pun,code .pun{color:#440}pre .pln,code .pln{color:#000}pre .tag,code .tag{color:#006;font-weight:bold}pre .atn,code .atn{color:#404}pre .atv,code .atv{color:#060}} -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/custom-busy-component/custom-busy-component.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {CustomBusyComponentComponent} from './custom-busy-component.component'; 4 | 5 | describe('CustomBusyComponentComponent', () => { 6 | let component: CustomBusyComponentComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [CustomBusyComponentComponent], 12 | providers: [{provide: 'instanceConfigHolder', useValue: {config: {message : 'hello'}}}] 13 | }) 14 | .compileComponents(); 15 | })); 16 | 17 | beforeEach(() => { 18 | fixture = TestBed.createComponent(CustomBusyComponentComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/options/options.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {OptionsComponent} from './options.component'; 4 | import {FormsModule} from '@angular/forms'; 5 | import {TemplateService} from 'src/app/modules/ng-busy-demo/service/template.service'; 6 | 7 | describe('OptionsComponent', () => { 8 | let component: OptionsComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(waitForAsync(() => { 12 | TestBed.configureTestingModule({ 13 | declarations: [OptionsComponent], 14 | imports: [FormsModule], 15 | providers: [TemplateService] 16 | }) 17 | .compileComponents(); 18 | })); 19 | 20 | beforeEach(() => { 21 | fixture = TestBed.createComponent(OptionsComponent); 22 | component = fixture.componentInstance; 23 | fixture.detectChanges(); 24 | }); 25 | 26 | it('should create', () => { 27 | expect(component).toBeTruthy(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/ng-busy.module.ts: -------------------------------------------------------------------------------- 1 | import {ModuleWithProviders, NgModule} from '@angular/core'; 2 | import {BusyConfig, DefaultBusyComponent, IBusyConfig} from './model/busy-config'; 3 | import {CommonModule} from '@angular/common'; 4 | import {BusyTrackerService} from './service/busy-tracker.service'; 5 | import {BusyConfigHolderService} from './service/busy-config-holder.service'; 6 | import {NgBusyDirective} from './ng-busy.directive'; 7 | import {NgBusyComponent} from './component/ng-busy/ng-busy.component'; 8 | 9 | @NgModule({ 10 | imports: [CommonModule], 11 | declarations: [DefaultBusyComponent, NgBusyDirective, NgBusyComponent], 12 | providers: [BusyConfigHolderService, BusyTrackerService], 13 | exports: [NgBusyDirective] 14 | }) 15 | export class NgBusyModule { 16 | static forRoot(config: IBusyConfig): ModuleWithProviders { 17 | return { 18 | ngModule: NgBusyModule, 19 | providers: [ 20 | {provide: BusyConfig, useValue: config} 21 | ] 22 | }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, waitForAsync } from '@angular/core/testing'; 2 | import {AppComponent} from './app.component'; 3 | import {FormsModule} from '@angular/forms'; 4 | import {NgBusyDemoModule} from './modules/ng-busy-demo/ng-busy-demo.module'; 5 | 6 | describe('AppComponent', () => { 7 | beforeEach(waitForAsync(() => { 8 | TestBed.configureTestingModule({ 9 | declarations: [ 10 | AppComponent 11 | ], 12 | imports: [ 13 | FormsModule, 14 | NgBusyDemoModule 15 | ] 16 | }).compileComponents(); 17 | })); 18 | it('should create the app', waitForAsync(() => { 19 | const fixture = TestBed.createComponent(AppComponent); 20 | const app = fixture.debugElement.componentInstance; 21 | expect(app).toBeTruthy(); 22 | })); 23 | it(`should have as title 'app'`, waitForAsync(() => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.debugElement.componentInstance; 26 | expect(app.title).toEqual('app'); 27 | })); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/table/table.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, Input, OnInit, SimpleChanges} from '@angular/core'; 2 | import {IBusyConfig} from 'ng-busy'; 3 | import {TemplateService} from '../../service/template.service'; 4 | 5 | @Component({ 6 | selector: 'app-table', 7 | templateUrl: './table.component.html', 8 | styleUrls: ['./table.component.css'], 9 | changeDetection: ChangeDetectionStrategy.OnPush 10 | }) 11 | export class TableComponent implements OnInit { 12 | 13 | @Input() loading: IBusyConfig; 14 | @Input() customTemplate: any; 15 | 16 | constructor(private templateService: TemplateService) { 17 | } 18 | 19 | ngOnInit() { 20 | } 21 | 22 | ngOnChanges(changes: SimpleChanges): void { 23 | this.templateService.setCustomTemplate(this.customTemplate); 24 | } 25 | 26 | onBusyStart(): void { 27 | console.log('what happened ?'); 28 | console.log('busy started'); 29 | } 30 | 31 | onBusyStop(): void { 32 | console.log('busy stopped'); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/code-viewer/code-viewer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {CodeViewerComponent} from './code-viewer.component'; 4 | import {TemplateService} from '../../service/template.service'; 5 | import {ElementRef, Renderer2} from '@angular/core'; 6 | 7 | describe('CodeViewerComponent', () => { 8 | let component: CodeViewerComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(waitForAsync(() => { 12 | TestBed.configureTestingModule({ 13 | declarations: [CodeViewerComponent], 14 | providers: [TemplateService, Renderer2, {provide: ElementRef, useValue: {}}] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(CodeViewerComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /projects/ng-busy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-busy", 3 | "version": "18.0.0", 4 | "description": "Show busy/loading indicators on any promise or subscription", 5 | "author": "victos", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/victos/angular-opensource.git" 10 | }, 11 | "homepage": "https://github.com/victos/angular-opensource/tree/master/projects/ng-busy", 12 | "bugs": { 13 | "url": "https://github.com/victos/angular-opensource" 14 | }, 15 | "keywords": [ 16 | "angular", 17 | "angular2", 18 | "busy", 19 | "loading", 20 | "angular2-busy", 21 | "ng2-busy", 22 | "ng-busy", 23 | "waiting", 24 | "angular5", 25 | "angular6" 26 | ], 27 | "engines": { 28 | "node": ">= 18.0.0", 29 | "npm": ">= 5.6.0" 30 | }, 31 | "peerDependencies": { 32 | "@angular/common": "^18.0.0", 33 | "@angular/core": "^18.0.0", 34 | "@angular/animations": "^18.0.0", 35 | "rxjs": "^7.8.1" 36 | }, 37 | "dependencies": { 38 | "tslib": "^2.3.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 victos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AngularOpensource 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.0. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/github-corner/github-corner.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/ng-busy-demo.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {DemoComponent} from './component/demo/demo.component'; 4 | import {CodeViewerComponent} from './component/code-viewer/code-viewer.component'; 5 | import {HeaderComponent} from './component/header/header.component'; 6 | import {OptionsComponent} from './component/options/options.component'; 7 | import {TableComponent} from './component/table/table.component'; 8 | import {CustomBusyComponentComponent} from './component/custom-busy-component/custom-busy-component.component'; 9 | import {GithubCornerComponent} from './component/github-corner/github-corner.component'; 10 | import {FormsModule} from '@angular/forms'; 11 | import {NgBusyModule} from 'ng-busy'; 12 | import {TemplateService} from './service/template.service'; 13 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; 14 | 15 | @NgModule({ 16 | imports: [ 17 | CommonModule, 18 | FormsModule, 19 | NgBusyModule, 20 | BrowserAnimationsModule 21 | ], 22 | declarations: [DemoComponent, CodeViewerComponent, HeaderComponent, OptionsComponent, 23 | TableComponent, CustomBusyComponentComponent, GithubCornerComponent], 24 | exports: [DemoComponent], 25 | providers: [TemplateService] 26 | }) 27 | export class NgBusyDemoModule { 28 | } 29 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/custom-busy-component/custom-busy-component.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; 2 | import { BUSY_CONFIG_DEFAULTS } from 'ng-busy'; 3 | import { InstanceConfigHolderService } from '../../../../../../projects/ng-busy/src/lib/service/instance-config-holder.service'; 4 | 5 | @Component({ 6 | selector: 'default-busy', 7 | template: ` 8 |
9 |
10 | {{message}} 11 |
12 |
13 | `, 14 | }) 15 | export class CustomBusyComponentComponent implements OnInit, OnDestroy { 16 | 17 | constructor(@Inject('instanceConfigHolder')public instanceConfigHolder: InstanceConfigHolderService) { 18 | } 19 | 20 | get message() { 21 | return this.instanceConfigHolder.config.message; 22 | } 23 | 24 | ngOnDestroy(): void { 25 | console.log('custom component destroy'); 26 | } 27 | 28 | ngOnInit(): void { 29 | console.log('custom component init'); 30 | } 31 | } 32 | 33 | export const OPTIONS_TEMPLATE: Object = { 34 | default: BUSY_CONFIG_DEFAULTS.template, 35 | custom: CustomBusyComponentComponent 36 | }; 37 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/demo/demo.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {DemoComponent} from './demo.component'; 4 | import {GithubCornerComponent} from '../github-corner/github-corner.component'; 5 | import {HeaderComponent} from '../header/header.component'; 6 | import {OptionsComponent} from '../options/options.component'; 7 | import {CodeViewerComponent} from '../code-viewer/code-viewer.component'; 8 | import {TableComponent} from '../table/table.component'; 9 | import {FormsModule} from '@angular/forms'; 10 | import {NgBusyModule} from 'ng-busy'; 11 | import {TemplateService} from 'src/app/modules/ng-busy-demo/service/template.service'; 12 | 13 | describe('DemoComponent', () => { 14 | let component: DemoComponent; 15 | let fixture: ComponentFixture; 16 | 17 | beforeEach(waitForAsync(() => { 18 | TestBed.configureTestingModule({ 19 | declarations: [DemoComponent, GithubCornerComponent, HeaderComponent, OptionsComponent, CodeViewerComponent, TableComponent], 20 | imports: [FormsModule, NgBusyModule], 21 | providers: [TemplateService] 22 | }) 23 | .compileComponents(); 24 | })); 25 | 26 | beforeEach(() => { 27 | fixture = TestBed.createComponent(DemoComponent); 28 | component = fixture.componentInstance; 29 | fixture.detectChanges(); 30 | }); 31 | 32 | it('should create', () => { 33 | expect(component).toBeTruthy(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/assets/css/doxy.css: -------------------------------------------------------------------------------- 1 | pre .str,code .str{color:#fec243}pre .kwd,code .kwd{color:#8470ff}pre .com,code .com{color:#32cd32;font-style:italic}pre .typ,code .typ{color:#6ecbcc}pre .lit,code .lit{color:#d06}pre .pun,code .pun{color:#8b8970}pre .pln,code .pln{color:#f0f0f0}pre .tag,code .tag{color:#9c9cff}pre .htm,code .htm{color:#dda0dd}pre .xsl,code .xsl{color:#d0a0d0}pre .atn,code .atn{color:#46eeee;font-weight:normal}pre .atv,code .atv{color:#eeb4b4}pre .dec,code .dec{color:#3387cc}a{text-decoration:none}pre.prettyprint,code.prettyprint{font-family:'Droid Sans Mono','CPMono_v07 Bold','Droid Sans';font-weight:bold;font-size:9pt;background-color:#0f0f0f;-moz-border-radius:8px;-webkit-border-radius:8px;-o-border-radius:8px;-ms-border-radius:8px;-khtml-border-radius:8px;border-radius:8px}pre.prettyprint{width:95%;margin:1em auto;padding:1em;white-space:pre-wrap}pre.prettyprint a,code.prettyprint a{text-decoration:none}ol.linenums{margin-top:0;margin-bottom:0;color:#8b8970}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}@media print{pre.prettyprint,code.prettyprint{background-color:#fff}pre .str,code .str{color:#088}pre .kwd,code .kwd{color:#006;font-weight:bold}pre .com,code .com{color:#oc3;font-style:italic}pre .typ,code .typ{color:#404;font-weight:bold}pre .lit,code .lit{color:#044}pre .pun,code .pun{color:#440}pre .pln,code .pln{color:#000}pre .tag,code .tag{color:#b66ff7;font-weight:bold}pre .htm,code .htm{color:#606;font-weight:bold}pre .xsl,code .xsl{color:#606;font-weight:bold}pre .atn,code .atn{color:#c71585;font-weight:normal}pre .atv,code .atv{color:#088;font-weight:normal}} -------------------------------------------------------------------------------- /src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | customLaunchers: { 16 | ChromeHeadlessCI: { 17 | base: 'ChromeHeadless', 18 | flags: ['--no-sandbox', 19 | '--headless', 20 | '--disable-gpu', 21 | '--disable-translate', 22 | '--disable-extensions'] 23 | } 24 | }, 25 | client: { 26 | clearContext: false // leave Jasmine Spec Runner output visible in browser 27 | }, 28 | coverageIstanbulReporter: { 29 | dir: require('path').join(__dirname, '../coverage'), 30 | reports: ['html', 'lcovonly'], 31 | fixWebpackSourcePaths: true 32 | }, 33 | reporters: ['progress', 'kjhtml'], 34 | port: 9876, 35 | colors: true, 36 | logLevel: config.LOG_INFO, 37 | autoWatch: true, 38 | browsers: ['Chrome', 'ChromeHeadlessCI'], 39 | singleRun: false 40 | }); 41 | }; -------------------------------------------------------------------------------- /projects/ng-busy/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | customLaunchers: { 16 | ChromeHeadlessCI: { 17 | base: 'ChromeHeadless', 18 | flags: ['--no-sandbox', 19 | '--headless', 20 | '--disable-gpu', 21 | '--disable-translate', 22 | '--disable-extensions'] 23 | } 24 | }, 25 | client: { 26 | clearContext: false // leave Jasmine Spec Runner output visible in browser 27 | }, 28 | coverageIstanbulReporter: { 29 | dir: require('path').join(__dirname, '../../coverage'), 30 | reports: ['html', 'lcovonly'], 31 | fixWebpackSourcePaths: true 32 | }, 33 | reporters: ['progress', 'kjhtml'], 34 | port: 9876, 35 | colors: true, 36 | logLevel: config.LOG_INFO, 37 | autoWatch: true, 38 | browsers: ['Chrome', 'ChromeHeadlessCI'], 39 | singleRun: false 40 | }); 41 | }; 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-opensource", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng build ng-busy && ng serve", 7 | "prebuild": "rimraf ./dist/ng-busy", 8 | "build": "ng build ng-busy --configuration production", 9 | "postbuild": "lessc ./projects/ng-busy/src/lib/style/busy.less ./dist/ng-busy/src/style/busy.css", 10 | "publish": "npm run build && npm publish ./dist/ng-busy" 11 | }, 12 | "dependencies": { 13 | "@angular/animations": "^18.2.7", 14 | "@angular/cdk": "^18.2.7", 15 | "@angular/common": "^18.2.7", 16 | "@angular/compiler": "^18.2.7", 17 | "@angular/core": "^18.2.7", 18 | "@angular/forms": "^18.2.7", 19 | "@angular/material": "^18.2.7", 20 | "@angular/platform-browser": "^18.2.7", 21 | "@angular/platform-browser-dynamic": "^18.2.7", 22 | "@angular/router": "^18.2.7", 23 | "code-prettify": "^0.1.0", 24 | "rxjs": "^7.8.1", 25 | "tslib": "^2.3.0", 26 | "zone.js": "^0.14.10" 27 | }, 28 | "devDependencies": { 29 | "@angular-devkit/build-angular": "^18.2.7", 30 | "@angular-devkit/core": "18.2.7", 31 | "@angular/cli": "18.2.7", 32 | "@angular/compiler-cli": "^18.2.7", 33 | "@angular/language-service": "^18.2.7", 34 | "@types/jasmine": "~5.1.4", 35 | "@types/jasminewd2": "~2.0.6", 36 | "@types/node": "^22.7.4", 37 | "codelyzer": "^6.0.2", 38 | "jasmine-core": "~5.3.0", 39 | "jasmine-spec-reporter": "~7.0.0", 40 | "karma": "~6.4.4", 41 | "karma-chrome-launcher": "~3.2.0", 42 | "karma-coverage-istanbul-reporter": "~3.0.2", 43 | "karma-jasmine": "~5.1.0", 44 | "karma-jasmine-html-reporter": "^2.1.0", 45 | "less": "^4.1.3", 46 | "lessc": "^1.0.2", 47 | "ng-packagr": "^18.2.1", 48 | "protractor": "~7.0.0", 49 | "rimraf": "^5.0.1", 50 | "ts-node": "^10.9.2", 51 | "tslint": "~6.1.3", 52 | "typescript": "^5.4.5" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/style/busy.less: -------------------------------------------------------------------------------- 1 | .ng-busy { 2 | z-index: 1002; 3 | 4 | &, 5 | > *, 6 | > ng-component > * { 7 | position: absolute; 8 | top: 0px; 9 | left: 0px; 10 | right: 0px; 11 | bottom: 0px; 12 | } 13 | } 14 | 15 | .ng-busy-backdrop { 16 | position: absolute; 17 | top: 0; 18 | left: 0; 19 | right: 0; 20 | bottom: 0; 21 | z-index: 1001; 22 | background: #fff; 23 | opacity: .7; 24 | } 25 | 26 | .ng-busy-default-wrapper { 27 | text-align: center; 28 | } 29 | 30 | .ng-busy-default-sign { 31 | position: relative; 32 | display: inline-block; 33 | z-index: 1003; 34 | padding: 12px 14px; 35 | border: 1px solid #d8d8d8; 36 | border-top: 0; 37 | border-radius: 4px; 38 | border-top-left-radius: 0; 39 | border-top-right-radius: 0; 40 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 41 | background: #f8f8f8; 42 | color: #333; 43 | } 44 | 45 | .ng-busy-default-text { 46 | display: inline-block; 47 | margin-left: 6px; 48 | max-width: 400px; 49 | font-size: 14px; 50 | text-align: left; 51 | } 52 | 53 | .ng-busy-default-spinner { 54 | position: relative; 55 | display: inline-block; 56 | width: 25px; 57 | height: 25px; 58 | vertical-align: middle; 59 | 60 | div { 61 | position: absolute; 62 | left: 44.5%; 63 | top: 37%; 64 | width: 10%; 65 | height: 26%; 66 | background: #666; 67 | border-radius: 50px; 68 | box-shadow: 0 0 3px rgba(0, 0, 0, .2); 69 | opacity: 0; 70 | animation: busy-spinner-anim 1s linear infinite; 71 | } 72 | 73 | .generate-bars(@n, @i: 1) when (@i =< @n) { 74 | .bar@{i} { 75 | transform: rotate(unit((360 / 12 * (@i - 1)), deg)) translate(0, -142%); 76 | animation-delay: unit((-1 + 1 / 12 * (@i - 1)), s); 77 | } 78 | .generate-bars(@n, (@i + 1)); 79 | } 80 | 81 | .generate-bars(12); 82 | } 83 | 84 | @keyframes busy-spinner-anim { 85 | from { 86 | opacity: 1; 87 | } 88 | to { 89 | opacity: 0.25; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/component/ng-busy/ng-busy.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectorRef, Component, EventEmitter, Inject, OnDestroy, ViewContainerRef } from '@angular/core'; 2 | import { animate, style, transition, trigger } from '@angular/animations'; 3 | import { InstanceConfigHolderService } from '../../service/instance-config-holder.service'; 4 | import { Subject, takeUntil } from 'rxjs'; 5 | 6 | const inactiveStyle = style({ 7 | opacity: 0, 8 | transform: 'translateY(-40px)' 9 | }); 10 | const timing = '.3s ease'; 11 | 12 | @Component({ 13 | selector: 'lib-ng-busy', 14 | templateUrl: './ng-busy.component.html', 15 | styleUrls: ['./ng-busy.component.css'], 16 | animations: [ 17 | trigger('flyInOut', [ 18 | transition('void => *', [ 19 | inactiveStyle, 20 | animate(timing) 21 | ]), 22 | transition('* => void', [ 23 | animate(timing, inactiveStyle) 24 | ]) 25 | ]) 26 | ] 27 | }) 28 | export class NgBusyComponent implements OnDestroy { 29 | 30 | public wrapperClass: string; 31 | public disableAnimation = false; 32 | public showBackdrop = true; 33 | private destroyIndicator = new Subject(); 34 | public show = new Subject(); 35 | 36 | constructor( 37 | @Inject('instanceConfigHolder') private instanceConfigHolder: InstanceConfigHolderService, 38 | @Inject('busyEmitter') public busyEmitter: EventEmitter, 39 | public vcr: ViewContainerRef, 40 | private cdr: ChangeDetectorRef, 41 | ) { 42 | this.show.pipe(takeUntil(this.destroyIndicator)).subscribe(() => { 43 | this.cdr.detectChanges(); 44 | }); 45 | this.busyEmitter.pipe(takeUntil(this.destroyIndicator)) 46 | .subscribe((isActive: boolean) => { 47 | if (isActive === true) { 48 | const config = this.instanceConfigHolder.config; 49 | this.wrapperClass = config.wrapperClass; 50 | this.showBackdrop = config.backdrop; 51 | this.disableAnimation = config.disableAnimation; 52 | } 53 | this.show.next(isActive); 54 | }); 55 | } 56 | 57 | ngOnDestroy(): void { 58 | this.destroyIndicator.next(null); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/model/busy-config.ts: -------------------------------------------------------------------------------- 1 | import {Subscription} from 'rxjs'; 2 | import {Component, TemplateRef, Type, Inject, ChangeDetectorRef} from '@angular/core'; 3 | import {InstanceConfigHolderService} from '../service/instance-config-holder.service'; 4 | 5 | export class BusyConfig implements IBusyConfig { 6 | template: TemplateRef | Type; 7 | templateNgStyle: {}; 8 | delay: number; 9 | minDuration: number; 10 | backdrop: boolean; 11 | message: string; 12 | wrapperClass: string; 13 | disableAnimation: boolean; 14 | 15 | constructor(config: IBusyConfig = {}) { 16 | for (const option of Object.keys(BUSY_CONFIG_DEFAULTS)) { 17 | this[option] = config[option] !== undefined ? config[option] : BUSY_CONFIG_DEFAULTS[option]; 18 | } 19 | } 20 | } 21 | 22 | @Component({ 23 | selector: 'default-busy', 24 | template: ` 25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
{{message}}
42 |
43 |
44 | `, 45 | }) 46 | export class DefaultBusyComponent { 47 | 48 | constructor(@Inject('instanceConfigHolder') private instanceConfigHolder: InstanceConfigHolderService) { 49 | } 50 | 51 | get message() { 52 | return this.instanceConfigHolder.config.message; 53 | } 54 | } 55 | 56 | export interface IBusyConfig { 57 | template?: TemplateRef | Type; 58 | templateNgStyle?: {}; 59 | delay?: number; 60 | minDuration?: number; 61 | backdrop?: boolean; 62 | message?: string; 63 | wrapperClass?: string; 64 | busy?: Array | Subscription>; 65 | disableAnimation?: boolean; 66 | } 67 | 68 | export const BUSY_CONFIG_DEFAULTS = { 69 | template: DefaultBusyComponent, 70 | templateNgStyle: {}, 71 | delay: 0, 72 | minDuration: 0, 73 | backdrop: true, 74 | message: 'Please wait...', 75 | wrapperClass: 'ng-busy', 76 | disableAnimation: false 77 | }; 78 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/code-viewer/code-viewer.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, ElementRef, Inject, Input, OnChanges, Renderer2, SimpleChanges} from '@angular/core'; 2 | import {IBusyConfig} from 'ng-busy'; 3 | import {TemplateService} from '../../service/template.service'; 4 | 5 | @Component({ 6 | selector: 'app-code-viewer', 7 | templateUrl: './code-viewer.component.html', 8 | styleUrls: ['./code-viewer.component.css'], 9 | providers: [{provide: 'Window', useValue: window}] 10 | }) 11 | export class CodeViewerComponent implements OnChanges { 12 | 13 | @Input() key: string; 14 | public code: string; 15 | private currentContent: any; 16 | @Input() private options: IBusyConfig; 17 | public optionsForShow: string; 18 | 19 | constructor(@Inject('Window') private window: any, 20 | private templateService: TemplateService, 21 | private render: Renderer2, 22 | private elementRef: ElementRef) { 23 | } 24 | 25 | ngOnChanges(changes: SimpleChanges): void { 26 | if (changes['key']) { 27 | if (this.currentContent) { 28 | this.render.removeChild(this.elementRef.nativeElement, this.currentContent); 29 | this.currentContent = undefined; 30 | } 31 | this.code = this.templateService.getCode(changes['key']['currentValue']); 32 | if (this.code) { 33 | this.currentContent = this.render.createElement('pre'); 34 | this.render.setAttribute(this.currentContent, 'class', 'prettyprint'); 35 | const currentText = this.render.createText(this.code); 36 | this.render.appendChild(this.currentContent, currentText); 37 | this.render.appendChild(this.elementRef.nativeElement, this.currentContent); 38 | } 39 | if (this.window.PR) { 40 | this.window.PR.prettyPrint(); 41 | } 42 | } 43 | this.optionsForShow = this.stringifyOptions(this.options); 44 | } 45 | 46 | private stringifyOptions(config: IBusyConfig) { 47 | const options = {}; 48 | let template; 49 | if (this.key === 'custom') { 50 | template = 'CustomBusyComponent'; 51 | } else if (this.key === 'template') { 52 | template = 'customTemplate'; 53 | } else { 54 | template = 'DefaultBusyComponent'; 55 | } 56 | options['delay'] = config.delay; 57 | options['minDuration'] = config.minDuration; 58 | options['backdrop'] = config.backdrop; 59 | options['message'] = config.message; 60 | options['wrapperClass'] = config.wrapperClass; 61 | options['templateNgStyle'] = config.templateNgStyle; 62 | let result = JSON.stringify(options); 63 | result = result.replace('{', `{template:${template},`); 64 | return result; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/options/options.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 |
7 |
8 | 9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 | 17 |
18 |
19 |
20 | 21 |
22 | 25 |
26 |
27 |
28 | 29 |
30 | 31 |
32 |
33 |
34 | 35 |
36 | 42 |
43 |
44 |
45 | 46 |
47 | 52 |
53 |
54 |
55 | 56 |
-------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for the Reflect API. */ 38 | // import 'core-js/es6/reflect'; 39 | 40 | 41 | /** Evergreen browsers require these. **/ 42 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 43 | 44 | /** 45 | * By default, zone.js will patch all possible macroTask and DomEvents 46 | * user can disable parts of macroTask/DomEvents patch by setting following flags 47 | */ 48 | 49 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 50 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 51 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 52 | 53 | /* 54 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 55 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 56 | */ 57 | // (window as any).__Zone_enable_cross_context_check = true; 58 | 59 | /*************************************************************************************************** 60 | * Zone JS is required by default for Angular itself. 61 | */ 62 | import 'zone.js'; // Included with Angular CLI. 63 | 64 | 65 | 66 | /*************************************************************************************************** 67 | * APPLICATION IMPORTS 68 | */ 69 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/component/options/options.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Component: Options 3 | * @author yumao 4 | */ 5 | 6 | import { Component } from '@angular/core'; 7 | 8 | import { BUSY_CONFIG_DEFAULTS, IBusyConfig } from 'ng-busy'; 9 | import { Observer, Observable } from 'rxjs'; 10 | import { TemplateService } from '../../service/template.service'; 11 | 12 | 13 | @Component({ 14 | selector: 'demo-options', 15 | templateUrl: './options.component.html', 16 | styleUrls: ['./options.component.css'] 17 | }) 18 | export class OptionsComponent { 19 | templateNgStyle = '{"background-color":"black", "color": "red"}'; 20 | templateType = 'default'; 21 | templates: any = [ 22 | { val: 'default', show: 'Default' }, 23 | { val: 'custom', show: 'Custom' }, 24 | { val: 'template', show: 'Template' } 25 | ]; 26 | data: IBusyConfig = Object.assign({}, BUSY_CONFIG_DEFAULTS); 27 | 28 | constructor(private templateService: TemplateService) { 29 | } 30 | 31 | changeTemplate(tmp: string) { 32 | this.templateType = tmp; 33 | this.data.template = this.templateService.getTemplate(this.templateType); 34 | } 35 | 36 | changeBackdrop(element: HTMLInputElement) { 37 | this.data.backdrop = element.checked; 38 | } 39 | 40 | disableAnimation(element: HTMLInputElement) { 41 | this.data.disableAnimation = element.checked; 42 | } 43 | 44 | playDemo() { 45 | this.data.templateNgStyle = JSON.parse(this.templateNgStyle); 46 | const busies = []; 47 | const promise = new Promise(resolve => { 48 | setTimeout(() => { 49 | resolve(); 50 | console.log('Promise finished!'); 51 | }, 3000); 52 | }); 53 | 54 | const observable1: Observable = Observable.create((observer: Observer) => { 55 | setTimeout(() => { 56 | observer.next(1); 57 | observer.complete(); 58 | }, 1000); 59 | }); 60 | 61 | const observable2: Observable = Observable.create((observer: Observer) => { 62 | setTimeout(() => { 63 | observer.next(2); 64 | observer.complete(); 65 | }, 2000); 66 | }); 67 | 68 | const observable3: Observable = Observable.create((observer: Observer) => { 69 | setTimeout(() => { 70 | observer.next(3); 71 | observer.complete(); 72 | }, 5000); 73 | }); 74 | 75 | const observable4: Observable = Observable.create((observer: Observer) => { 76 | setTimeout(() => { 77 | observer.next(4); 78 | observer.complete(); 79 | }, 4000); 80 | }); 81 | 82 | busies.push(promise); 83 | busies.push(observable1.subscribe((val: number) => { 84 | console.log(`Observer${val} done!`); 85 | })); 86 | busies.push(observable2.subscribe((val: number) => { 87 | console.log(`Observer${val} done!`); 88 | })); 89 | busies.push(observable3.subscribe((val: number) => { 90 | console.log(`Observer${val} done!`); 91 | })); 92 | busies.push(observable4.subscribe((val: number) => { 93 | console.log(`Observer${val} done!`); 94 | })); 95 | this.data.busy = busies; 96 | this.data = Object.assign({}, this.data); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/component/ng-busy/ng-busy.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import { NgBusyComponent } from './ng-busy.component'; 4 | import {BusyConfigHolderService} from '../../service/busy-config-holder.service'; 5 | import {ChangeDetectorRef, ElementRef, EventEmitter} from '@angular/core'; 6 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; 7 | import {By} from '@angular/platform-browser'; 8 | import {InstanceConfigHolderService} from '../../service/instance-config-holder.service'; 9 | 10 | export class MockElementRef extends ElementRef {} 11 | 12 | describe('NgBusyComponent', () => { 13 | let component: NgBusyComponent; 14 | let fixture: ComponentFixture; 15 | let busyEmitter: EventEmitter; 16 | const instanceConfig: InstanceConfigHolderService = new InstanceConfigHolderService(); 17 | 18 | beforeEach(waitForAsync(() => { 19 | instanceConfig.config = { 20 | wrapperClass: 'the_actual_class', 21 | template: MockElementRef, 22 | delay: 0, 23 | minDuration: 0, 24 | backdrop: false, 25 | message: 'the_actual_msg' 26 | }; 27 | TestBed.configureTestingModule({ 28 | declarations: [ NgBusyComponent ], 29 | imports: [BrowserAnimationsModule], 30 | providers: [BusyConfigHolderService, ChangeDetectorRef, 31 | {provide: 'busyEmitter', useValue: new EventEmitter()}, 32 | {provide: 'instanceConfigHolder', useValue: instanceConfig}] 33 | }) 34 | .compileComponents(); 35 | })); 36 | 37 | beforeEach(() => { 38 | fixture = TestBed.createComponent(NgBusyComponent); 39 | component = fixture.componentInstance; 40 | fixture.detectChanges(); 41 | busyEmitter = TestBed.get('busyEmitter'); 42 | }); 43 | 44 | it('should create', () => { 45 | expect(component).toBeTruthy(); 46 | }); 47 | 48 | it('should be empty after init', waitForAsync(() => { 49 | fixture.detectChanges(); 50 | expect(fixture.debugElement.query(By.css('.the_actual_class'))).toBeNull(); 51 | })); 52 | 53 | it('should be empty if isActive is false', waitForAsync(() => { 54 | busyEmitter.emit(false); 55 | fixture.detectChanges(); 56 | expect(fixture.debugElement.query(By.css('.the_actual_class'))).toBeNull(); 57 | })); 58 | 59 | it('div.the_actual_class should be load if isActive is true', waitForAsync(() => { 60 | busyEmitter.emit(true); 61 | fixture.detectChanges(); 62 | expect(fixture.debugElement.query(By.css('.the_actual_class'))).not.toBeNull(); 63 | })); 64 | 65 | it('div.the_actual_class should be load by the change of isActive', waitForAsync(() => { 66 | busyEmitter.emit(true); 67 | fixture.detectChanges(); 68 | expect(fixture.debugElement.query(By.css('.the_actual_class'))).not.toBeNull(); 69 | busyEmitter.emit(false); 70 | fixture.detectChanges(); 71 | expect(fixture.debugElement.query(By.css('.the_actual_class'))).toBeNull(); 72 | busyEmitter.emit(true); 73 | fixture.detectChanges(); 74 | expect(fixture.debugElement.query(By.css('.the_actual_class'))).not.toBeNull(); 75 | busyEmitter.emit(false); 76 | fixture.detectChanges(); 77 | expect(fixture.debugElement.query(By.css('.the_actual_class'))).toBeNull(); 78 | })); 79 | }); 80 | -------------------------------------------------------------------------------- /src/app/modules/ng-busy-demo/service/template.service.ts: -------------------------------------------------------------------------------- 1 | import {Inject, Injectable, TemplateRef} from '@angular/core'; 2 | import {OPTIONS_TEMPLATE} from '../component/custom-busy-component/custom-busy-component.component'; 3 | import {InstanceConfigHolderService} from '../../../../../projects/ng-busy/src/lib/service/instance-config-holder.service'; 4 | 5 | @Injectable() 6 | export class TemplateService { 7 | 8 | private codeCache = { 9 | 'default': `@Component({ 10 | selector: 'default-busy', 11 | template: \` 12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
{{message}}
29 |
30 |
31 | \`, 32 | }) 33 | export class DefaultBusyComponent { 34 | private _msg: string; 35 | 36 | constructor(@Inject('message') private msg: string, private _changeDetectionRef: ChangeDetectorRef) { 37 | } 38 | 39 | get message() { 40 | if (this._msg === undefined) { 41 | this.message = this.msg; 42 | } 43 | return this._msg; 44 | } 45 | 46 | set message(msg: string) { 47 | this._msg = msg; 48 | this._changeDetectionRef.detectChanges(); 49 | } 50 | }`, 51 | 'custom': `@Component({ 52 | selector: 'default-busy', 53 | template: \` 54 |
55 |
56 | {{message}} 57 |
58 |
59 | \`, 60 | }) 61 | export class CustomBusyComponent { 62 | constructor(@Inject('instanceConfigHolder') private instanceConfigHolder: InstanceConfigHolderService) { 63 | } 64 | 65 | get message() { 66 | return this.instanceConfigHolder.config.message; 67 | } 68 | }`, 69 | 'template': ` 70 |
Hi, This is from ng-template.
71 |
` 72 | }; 73 | 74 | private customTemplate: TemplateRef; 75 | 76 | getTemplate(key: string): any { 77 | if (key === 'template') { 78 | return this.customTemplate; 79 | } 80 | if (key) { 81 | return OPTIONS_TEMPLATE[key]; 82 | } else { 83 | return OPTIONS_TEMPLATE['default']; 84 | } 85 | } 86 | 87 | getCode(key: string): string { 88 | return this.codeCache[key]; 89 | } 90 | 91 | setCustomTemplate(tmpRef: TemplateRef): void { 92 | this.customTemplate = tmpRef; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "deprecation": { 15 | "severity": "warn" 16 | }, 17 | "eofline": true, 18 | "forin": true, 19 | "import-blacklist": [ 20 | true, 21 | "rxjs/Rx" 22 | ], 23 | "import-spacing": true, 24 | "indent": [ 25 | true, 26 | "spaces" 27 | ], 28 | "interface-over-type-literal": true, 29 | "label-position": true, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-arg": true, 47 | "no-bitwise": true, 48 | "no-console": [ 49 | true, 50 | "debug", 51 | "info", 52 | "time", 53 | "timeEnd", 54 | "trace" 55 | ], 56 | "no-construct": true, 57 | "no-debugger": true, 58 | "no-duplicate-super": true, 59 | "no-empty": false, 60 | "no-empty-interface": true, 61 | "no-eval": true, 62 | "no-inferrable-types": [ 63 | true, 64 | "ignore-params" 65 | ], 66 | "no-misused-new": true, 67 | "no-non-null-assertion": true, 68 | "no-shadowed-variable": true, 69 | "no-string-literal": false, 70 | "no-string-throw": true, 71 | "no-switch-case-fall-through": true, 72 | "no-trailing-whitespace": true, 73 | "no-unnecessary-initializer": true, 74 | "no-unused-expression": true, 75 | "no-var-keyword": true, 76 | "object-literal-sort-keys": false, 77 | "one-line": [ 78 | true, 79 | "check-open-brace", 80 | "check-catch", 81 | "check-else", 82 | "check-whitespace" 83 | ], 84 | "prefer-const": true, 85 | "quotemark": [ 86 | true, 87 | "single" 88 | ], 89 | "radix": true, 90 | "semicolon": [ 91 | true, 92 | "always" 93 | ], 94 | "triple-equals": [ 95 | true, 96 | "allow-null-check" 97 | ], 98 | "typedef-whitespace": [ 99 | true, 100 | { 101 | "call-signature": "nospace", 102 | "index-signature": "nospace", 103 | "parameter": "nospace", 104 | "property-declaration": "nospace", 105 | "variable-declaration": "nospace" 106 | } 107 | ], 108 | "unified-signatures": true, 109 | "variable-name": false, 110 | "whitespace": [ 111 | true, 112 | "check-branch", 113 | "check-decl", 114 | "check-operator", 115 | "check-separator", 116 | "check-type" 117 | ], 118 | "no-output-on-prefix": true, 119 | "no-inputs-metadata-property": true, 120 | "no-outputs-metadata-property": true, 121 | "no-host-metadata-property": true, 122 | "no-input-rename": true, 123 | "no-output-rename": true, 124 | "use-lifecycle-interface": true, 125 | "use-pipe-transform-interface": true, 126 | "component-class-suffix": true, 127 | "directive-class-suffix": true 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/service/busy-tracker.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, OnDestroy } from '@angular/core'; 2 | import { 3 | BehaviorSubject, Observable, Subject, tap, 4 | Subscription, concatAll, from, takeUntil, 5 | timer, map, take, filter, combineLatest 6 | } from 'rxjs'; 7 | import { isPromise } from '../util/isPromise'; 8 | 9 | export interface TrackerOptions { 10 | minDuration: number; 11 | delay: number; 12 | busyList: Array | Subscription>; 13 | } 14 | 15 | @Injectable({ 16 | providedIn: 'any' 17 | }) 18 | export class BusyTrackerService implements OnDestroy { 19 | 20 | private busyQueue: Array = []; 21 | private operations: Subject> = new Subject>(); 22 | private busyDone: Subject = new Subject(); 23 | private destroyIndicator: Subject = new Subject(); 24 | private checkSubject: Subject = new Subject(); 25 | private processingIndicator: BehaviorSubject = new BehaviorSubject(false); 26 | active: BehaviorSubject = new BehaviorSubject(false); 27 | 28 | get isActive(): boolean { 29 | return this.active.value; 30 | } 31 | 32 | get busyList() { 33 | return [...this.busyQueue]; 34 | } 35 | 36 | get isBusy() { 37 | return this.busyQueue.filter(b => !b.closed).length > 0; 38 | } 39 | 40 | constructor() { 41 | this.reset(); 42 | this.operations.pipe(takeUntil(this.destroyIndicator), concatAll()).subscribe(); 43 | this.checkSubject.pipe(takeUntil(this.destroyIndicator)).subscribe((options) => { 44 | this.processingIndicator.pipe(take(1)).subscribe((isProcessing) => { 45 | if (isProcessing === false && this.isBusy) { 46 | this.processingIndicator.next(true); 47 | timer(options.delay || 0).pipe(map(() => this.isBusy)).subscribe((stillBusy) => { 48 | if (stillBusy) { 49 | this.active.next(stillBusy); 50 | combineLatest([this.busyDone, timer(options.minDuration || 0)]) 51 | .pipe(takeUntil(this.active.pipe(filter(a => a === false)))) 52 | .subscribe(() => { 53 | this.operations.next(new Observable((subscriber) => { 54 | if (!this.isBusy) { 55 | this.reset(); 56 | } 57 | subscriber.complete(); 58 | })); 59 | }); 60 | } else { 61 | this.processingIndicator.next(false); 62 | } 63 | }); 64 | } 65 | }); 66 | }); 67 | } 68 | 69 | load(options: TrackerOptions) { 70 | this.operations.next( 71 | from(options.busyList).pipe( 72 | filter(busy => busy !== null && busy !== undefined && !busy.hasOwnProperty('__loaded_mark_by_ng_busy')), 73 | tap((busy) => Object.defineProperty(busy, '__loaded_mark_by_ng_busy', { 74 | value: true, configurable: false, enumerable: false, writable: false 75 | })), 76 | map((busy) => isPromise(busy) ? from(busy).subscribe() : busy), 77 | tap(subscription => this.appendToQueue(subscription)) 78 | ) 79 | ); 80 | this.checkSubject.next(options); 81 | } 82 | 83 | private updateActiveStatus() { 84 | this.busyQueue = this.busyQueue.filter((cur: Subscription) => cur && !cur.closed); 85 | if (this.busyQueue.length === 0) { 86 | this.busyDone.next(true); 87 | } 88 | } 89 | 90 | private reset() { 91 | this.active.next(false); 92 | this.busyQueue = []; 93 | this.processingIndicator.next(false); 94 | } 95 | 96 | private appendToQueue(busy: Subscription) { 97 | this.busyQueue.push(busy); 98 | busy.add(() => { 99 | this.operations.next(new Observable((subscriber) => { 100 | this.updateActiveStatus(); 101 | subscriber.complete(); 102 | })); 103 | }); 104 | } 105 | 106 | ngOnDestroy(): void { 107 | this.destroyIndicator.next(null); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/assets/css/busy.css: -------------------------------------------------------------------------------- 1 | .ng-busy { 2 | z-index: 1002; 3 | } 4 | .ng-busy, 5 | .ng-busy > *, 6 | .ng-busy > ng-component > * { 7 | position: absolute; 8 | top: 0px; 9 | left: 0px; 10 | right: 0px; 11 | bottom: 0px; 12 | } 13 | .ng-busy-backdrop { 14 | position: absolute; 15 | top: 0; 16 | left: 0; 17 | right: 0; 18 | bottom: 0; 19 | z-index: 1001; 20 | background: #fff; 21 | opacity: .7; 22 | } 23 | .ng-busy-default-wrapper { 24 | text-align: center; 25 | } 26 | .ng-busy-default-sign { 27 | position: relative; 28 | display: inline-block; 29 | z-index: 1003; 30 | padding: 12px 14px; 31 | border: 1px solid #d8d8d8; 32 | border-top: 0; 33 | border-radius: 4px; 34 | border-top-left-radius: 0; 35 | border-top-right-radius: 0; 36 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 37 | background: #f8f8f8; 38 | color: #333; 39 | } 40 | .ng-busy-default-text { 41 | display: inline-block; 42 | margin-left: 6px; 43 | max-width: 400px; 44 | font-size: 14px; 45 | text-align: left; 46 | } 47 | .ng-busy-default-spinner { 48 | position: relative; 49 | display: inline-block; 50 | width: 25px; 51 | height: 25px; 52 | vertical-align: middle; 53 | } 54 | .ng-busy-default-spinner div { 55 | position: absolute; 56 | left: 44.5%; 57 | top: 37%; 58 | width: 10%; 59 | height: 26%; 60 | background: #666; 61 | border-radius: 50px; 62 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); 63 | opacity: 0; 64 | -webkit-animation: busy-spinner-anim 1s linear infinite; 65 | animation: busy-spinner-anim 1s linear infinite; 66 | } 67 | .ng-busy-default-spinner .bar1 { 68 | -webkit-transform: rotate(0deg) translate(0, -142%); 69 | transform: rotate(0deg) translate(0, -142%); 70 | -webkit-animation-delay: -1s; 71 | animation-delay: -1s; 72 | } 73 | .ng-busy-default-spinner .bar2 { 74 | -webkit-transform: rotate(30deg) translate(0, -142%); 75 | transform: rotate(30deg) translate(0, -142%); 76 | -webkit-animation-delay: -0.91666667s; 77 | animation-delay: -0.91666667s; 78 | } 79 | .ng-busy-default-spinner .bar3 { 80 | -webkit-transform: rotate(60deg) translate(0, -142%); 81 | transform: rotate(60deg) translate(0, -142%); 82 | -webkit-animation-delay: -0.83333333s; 83 | animation-delay: -0.83333333s; 84 | } 85 | .ng-busy-default-spinner .bar4 { 86 | -webkit-transform: rotate(90deg) translate(0, -142%); 87 | transform: rotate(90deg) translate(0, -142%); 88 | -webkit-animation-delay: -0.75s; 89 | animation-delay: -0.75s; 90 | } 91 | .ng-busy-default-spinner .bar5 { 92 | -webkit-transform: rotate(120deg) translate(0, -142%); 93 | transform: rotate(120deg) translate(0, -142%); 94 | -webkit-animation-delay: -0.66666667s; 95 | animation-delay: -0.66666667s; 96 | } 97 | .ng-busy-default-spinner .bar6 { 98 | -webkit-transform: rotate(150deg) translate(0, -142%); 99 | transform: rotate(150deg) translate(0, -142%); 100 | -webkit-animation-delay: -0.58333333s; 101 | animation-delay: -0.58333333s; 102 | } 103 | .ng-busy-default-spinner .bar7 { 104 | -webkit-transform: rotate(180deg) translate(0, -142%); 105 | transform: rotate(180deg) translate(0, -142%); 106 | -webkit-animation-delay: -0.5s; 107 | animation-delay: -0.5s; 108 | } 109 | .ng-busy-default-spinner .bar8 { 110 | -webkit-transform: rotate(210deg) translate(0, -142%); 111 | transform: rotate(210deg) translate(0, -142%); 112 | -webkit-animation-delay: -0.41666667s; 113 | animation-delay: -0.41666667s; 114 | } 115 | .ng-busy-default-spinner .bar9 { 116 | -webkit-transform: rotate(240deg) translate(0, -142%); 117 | transform: rotate(240deg) translate(0, -142%); 118 | -webkit-animation-delay: -0.33333333s; 119 | animation-delay: -0.33333333s; 120 | } 121 | .ng-busy-default-spinner .bar10 { 122 | -webkit-transform: rotate(270deg) translate(0, -142%); 123 | transform: rotate(270deg) translate(0, -142%); 124 | -webkit-animation-delay: -0.25s; 125 | animation-delay: -0.25s; 126 | } 127 | .ng-busy-default-spinner .bar11 { 128 | -webkit-transform: rotate(300deg) translate(0, -142%); 129 | transform: rotate(300deg) translate(0, -142%); 130 | -webkit-animation-delay: -0.16666667s; 131 | animation-delay: -0.16666667s; 132 | } 133 | .ng-busy-default-spinner .bar12 { 134 | -webkit-transform: rotate(330deg) translate(0, -142%); 135 | transform: rotate(330deg) translate(0, -142%); 136 | -webkit-animation-delay: -0.08333333s; 137 | animation-delay: -0.08333333s; 138 | } 139 | @-webkit-keyframes busy-spinner-anim { 140 | from { 141 | opacity: 1; 142 | } 143 | to { 144 | opacity: 0.25; 145 | } 146 | } 147 | @keyframes busy-spinner-anim { 148 | from { 149 | opacity: 1; 150 | } 151 | to { 152 | opacity: 0.25; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular-opensource": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": {}, 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:application", 15 | "options": { 16 | "outputPath": { 17 | "base": "dist/angular-opensource" 18 | }, 19 | "index": "src/index.html", 20 | "polyfills": [ 21 | "src/polyfills.ts" 22 | ], 23 | "tsConfig": "src/tsconfig.app.json", 24 | "assets": [ 25 | "src/favicon.ico", 26 | "src/assets" 27 | ], 28 | "styles": [ 29 | "src/styles.css", 30 | "src/assets/css/bootstrap.min.css", 31 | "src/assets/css/busy.css", 32 | "src/assets/css/desert.css", 33 | "src/assets/css/doxy.css", 34 | "src/assets/css/prettify.css", 35 | "src/assets/css/sunburst.css", 36 | "src/assets/css/sons-of-obsidian.css" 37 | ], 38 | "scripts": [ 39 | "node_modules/code-prettify/loader/prettify.js" 40 | ], 41 | "extractLicenses": false, 42 | "sourceMap": true, 43 | "optimization": false, 44 | "namedChunks": true, 45 | "browser": "src/main.ts" 46 | }, 47 | "configurations": { 48 | "production": { 49 | "budgets": [ 50 | { 51 | "type": "anyComponentStyle", 52 | "maximumWarning": "6kb" 53 | } 54 | ], 55 | "fileReplacements": [ 56 | { 57 | "replace": "src/environments/environment.ts", 58 | "with": "src/environments/environment.prod.ts" 59 | } 60 | ], 61 | "optimization": true, 62 | "outputHashing": "all", 63 | "sourceMap": false, 64 | "namedChunks": false, 65 | "extractLicenses": true 66 | } 67 | }, 68 | "defaultConfiguration": "" 69 | }, 70 | "serve": { 71 | "builder": "@angular-devkit/build-angular:dev-server", 72 | "options": { 73 | "buildTarget": "angular-opensource:build" 74 | }, 75 | "configurations": { 76 | "production": { 77 | "buildTarget": "angular-opensource:build:production" 78 | } 79 | } 80 | }, 81 | "extract-i18n": { 82 | "builder": "@angular-devkit/build-angular:extract-i18n", 83 | "options": { 84 | "buildTarget": "angular-opensource:build" 85 | } 86 | }, 87 | "test": { 88 | "builder": "@angular-devkit/build-angular:karma", 89 | "options": { 90 | "main": "src/test.ts", 91 | "polyfills": "src/polyfills.ts", 92 | "tsConfig": "src/tsconfig.spec.json", 93 | "karmaConfig": "src/karma.conf.js", 94 | "styles": [ 95 | "styles.css" 96 | ], 97 | "scripts": [], 98 | "assets": [ 99 | "src/favicon.ico", 100 | "src/assets" 101 | ] 102 | } 103 | } 104 | } 105 | }, 106 | "angular-opensource-e2e": { 107 | "root": "e2e/", 108 | "projectType": "application", 109 | "architect": { 110 | "e2e": { 111 | "builder": "@angular-devkit/build-angular:protractor", 112 | "options": { 113 | "protractorConfig": "e2e/protractor.conf.js", 114 | "devServerTarget": "angular-opensource:serve" 115 | } 116 | } 117 | } 118 | }, 119 | "ng-busy": { 120 | "root": "projects/ng-busy", 121 | "sourceRoot": "projects/ng-busy/src", 122 | "projectType": "library", 123 | "prefix": "lib", 124 | "architect": { 125 | "build": { 126 | "builder": "@angular-devkit/build-angular:ng-packagr", 127 | "options": { 128 | "tsConfig": "projects/ng-busy/tsconfig.lib.json", 129 | "project": "projects/ng-busy/ng-package.json" 130 | }, 131 | "configurations": { 132 | "production": { 133 | "project": "projects/ng-busy/ng-package.prod.json" 134 | , "tsConfig": "projects/ng-busy/tsconfig.lib.prod.json" 135 | } 136 | } 137 | }, 138 | "test": { 139 | "builder": "@angular-devkit/build-angular:karma", 140 | "options": { 141 | "main": "projects/ng-busy/src/test.ts", 142 | "tsConfig": "projects/ng-busy/tsconfig.spec.json", 143 | "karmaConfig": "projects/ng-busy/karma.conf.js" 144 | } 145 | } 146 | } 147 | } 148 | }, 149 | "cli": { 150 | "analytics": false 151 | } 152 | } -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/ng-busy.directive.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ChangeDetectorRef, 3 | ComponentRef, 4 | Directive, DoCheck, 5 | EventEmitter, Injector, 6 | Input, OnDestroy, 7 | Output, 8 | Renderer2, 9 | TemplateRef, Type, 10 | ViewContainerRef 11 | } from '@angular/core'; 12 | import { BusyTrackerService } from './service/busy-tracker.service'; 13 | import { BusyConfigHolderService } from './service/busy-config-holder.service'; 14 | import { Subject, Subscription, distinctUntilChanged, skip, takeUntil } from 'rxjs'; 15 | import { IBusyConfig } from './model/busy-config'; 16 | import { NgBusyComponent } from './component/ng-busy/ng-busy.component'; 17 | import { InstanceConfigHolderService } from './service/instance-config-holder.service'; 18 | import { isPromise } from './util/isPromise'; 19 | 20 | @Directive({ 21 | selector: '[ngBusy]', 22 | providers: [BusyTrackerService, InstanceConfigHolderService], 23 | exportAs: 'ngBusy' 24 | }) 25 | export class NgBusyDirective implements DoCheck, OnDestroy { 26 | @Input('ngBusy') 27 | set options(op) { 28 | this._option = op; 29 | } 30 | 31 | get options() { 32 | return this._option; 33 | } 34 | 35 | get trackerService() { 36 | return this.tracker; 37 | } 38 | 39 | @Output() busyStart = new EventEmitter(); 40 | @Output() busyStop = new EventEmitter(); 41 | private _option: any; 42 | private optionsNorm: IBusyConfig; 43 | private busyRef: ComponentRef; 44 | private destroyIndicator: Subject = new Subject(); 45 | private configLoader: Subject = new Subject(); 46 | private busyEmitter: EventEmitter = new EventEmitter(); 47 | public template: TemplateRef | Type; 48 | public templateNgStyle: {}; 49 | 50 | constructor(private configHolder: BusyConfigHolderService, 51 | private instanceConfigHolder: InstanceConfigHolderService, 52 | private tracker: BusyTrackerService, 53 | private cdr: ChangeDetectorRef, 54 | private vcr: ViewContainerRef, 55 | private renderer: Renderer2, 56 | private injector: Injector) { 57 | tracker.active.pipe(skip(1), takeUntil(this.destroyIndicator), distinctUntilChanged()).subscribe((status) => { 58 | if (status === true) { 59 | this.recreateBusyIfNecessary(); 60 | this.busyStart.emit(); 61 | } else { 62 | this.busyStop.emit(); 63 | } 64 | this.busyEmitter.next(status); 65 | }); 66 | this.configLoader.pipe(takeUntil(this.destroyIndicator)).subscribe((config) => { 67 | const busyList = config.busy.filter(b => b?.['closed'] !== true && !b?.hasOwnProperty?.('__loaded_mark_by_ng_busy')); 68 | this.optionsNorm = config; 69 | this.instanceConfigHolder.config = this.optionsNorm; 70 | if (busyList.length > 0) { 71 | this.tracker.load({ 72 | busyList, delay: this.optionsNorm.delay, 73 | minDuration: this.optionsNorm.minDuration 74 | }); 75 | } 76 | }); 77 | } 78 | 79 | ngDoCheck() { 80 | this.configLoader.next(this.normalizeOptions(this.options)); 81 | } 82 | 83 | ngOnDestroy() { 84 | this.destroyIndicator.next(null); 85 | } 86 | 87 | private recreateBusyIfNecessary() { 88 | this.destroyComponents(); 89 | this.template = this.optionsNorm.template; 90 | this.templateNgStyle = this.optionsNorm.templateNgStyle; 91 | this.createBusy(); 92 | } 93 | 94 | private normalizeOptions(options: any): IBusyConfig { 95 | if (!options) { 96 | options = { busy: [] }; 97 | } else if (Array.isArray(options)) { 98 | options = { busy: options }; 99 | } else if (isPromise(options) || options instanceof Subscription) { 100 | options = { busy: [options] } 101 | } 102 | options = Object.assign({}, this.configHolder.config, options); 103 | if (!Array.isArray(options.busy)) { 104 | options.busy = [options.busy]; 105 | } 106 | return options; 107 | } 108 | 109 | private destroyComponents() { 110 | if (this.busyRef) { 111 | this.busyRef.destroy(); 112 | } 113 | } 114 | 115 | private createBusy() { 116 | const injector = Injector.create({ 117 | providers: [ 118 | { 119 | provide: 'instanceConfigHolder', 120 | useValue: this.instanceConfigHolder 121 | }, 122 | { 123 | provide: 'busyEmitter', 124 | useValue: this.busyEmitter 125 | } 126 | ], parent: this.injector 127 | }); 128 | this.template = this.optionsNorm.template; 129 | this.busyRef = this.vcr.createComponent(NgBusyComponent, { injector, projectableNodes: this.generateNgContent(injector) }); 130 | this.busyRef.onDestroy(() => { 131 | this.busyRef.instance.ngOnDestroy(); 132 | }); 133 | this.cdr.markForCheck(); 134 | this.busyRef.hostView.detectChanges(); 135 | } 136 | 137 | private generateNgContent(injector: Injector) { 138 | if (typeof this.template === 'string') { 139 | const element = this.renderer.createText(this.template); 140 | return [[element]]; 141 | } 142 | if (this.template instanceof TemplateRef) { 143 | const context = {}; 144 | const viewRef = this.template.createEmbeddedView(context); 145 | return [viewRef.rootNodes]; 146 | } 147 | if (typeof this.template === 'function') { 148 | const factory = this.vcr.createComponent(this.template, { injector }); 149 | factory.onDestroy(() => { 150 | factory?.instance?.ngOnDestroy?.(); 151 | }); 152 | factory.changeDetectorRef.markForCheck(); 153 | return [[factory.location.nativeElement]]; 154 | } 155 | return [[]]; 156 | } 157 | 158 | } -------------------------------------------------------------------------------- /projects/ng-busy/README.md: -------------------------------------------------------------------------------- 1 | **Notice** 2 | 3 | 1.x version is used for angular 5.x 4 | 5 | 6.x version is used for angular 6.x 6 | 7 | 7.x version is used for angular 7.x 8 | 9 | 8.x version is used for angular 8.x 10 | 11 | 9.x version is used for angular 9.x 12 | 13 | 10.x version is used for angular 10.x 14 | 15 | 11.x version is used for angular 11.x 16 | 17 | **NgBusy** can show busy/loading indicators on any promise, or on any Observable's subscription. 18 | 19 | [![Travis](https://img.shields.io/travis/victos/angular-opensource/master.svg?label=Travis%20CI&style=flat-square)](https://travis-ci.org/victos/angular-opensource) 20 | [![npm Downloads](https://img.shields.io/npm/dw/ng-busy.svg?style=flat-square)](https://www.npmjs.com/package/ng-busy) 21 | 22 | ![demo](https://raw.githubusercontent.com/devyumao/devyumao.github.io/master/angular2-busy/img/demo.gif) 23 | 24 | Rewritten from [angular2-busy](https://github.com/devyumao/angular2-busy), and add some new features in terms of Angular 2. 25 | 26 | ### Built with Angular 6.0.0 27 | 28 | ## Demo 29 | 30 | [https://github.com/victos/angular-opensource/tree/master/projects/ng-busy/](https://github.com/victos/angular-opensource/tree/master/projects/ng-busy/) 31 | 32 | ## Installation 33 | 34 | ```shell 35 | npm install --save ng-busy 36 | ``` 37 | 38 | ## Link CSS 39 | In angular.json: 40 | 41 | ```json 42 | "styles": [ 43 | ... 44 | "node_modules/ng-busy/src/style/busy.css", 45 | ... 46 | ], 47 | ``` 48 | 49 | ## Getting Started 50 | 51 | Import the `NgBusyModule` in your root application module: 52 | 53 | ```ts 54 | import {NgModule} from '@angular/core'; 55 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; 56 | import {NgBusyModule} from 'ng-busy'; 57 | 58 | @NgModule({ 59 | imports: [ 60 | // ... 61 | BrowserAnimationsModule, 62 | NgBusyModule 63 | ], 64 | // ... 65 | }) 66 | export class AppModule {} 67 | ``` 68 | 69 | 70 | Reference your promise in the `ngBusy` directive: 71 | 72 | ```ts 73 | import {Component, OnInit} from '@angular/core'; 74 | import {HttpClient} from '@angular/common/http'; 75 | 76 | @Component({ 77 | selector: 'some', 78 | template: ` 79 |
80 | ` 81 | }) 82 | class SomeComponent implements OnInit { 83 | busy: Promise; 84 | 85 | constructor(private http: HttpClient) {} 86 | 87 | ngOnInit() { 88 | this.busy = this.http.get('...').toPromise(); 89 | } 90 | } 91 | ``` 92 | 93 | Moreover, the subscription of an Observable is also supported: 94 | 95 | ```ts 96 | // ... 97 | import {Subscription} from 'rxjs'; 98 | 99 | // ... 100 | class SomeComponent implements OnInit { 101 | busy: Subscription; 102 | 103 | // ... 104 | 105 | ngOnInit() { 106 | this.busy = this.http.get('...').subscribe(); 107 | } 108 | } 109 | ``` 110 | 111 | ## Directive Syntax 112 | 113 | The `ngBusy` directive expects a ***busy thing***, which means: 114 | - A promise 115 | - Or an Observable's subscription 116 | - Or an array of them 117 | - Or a configuration object 118 | In other words, you may use flexible syntax: 119 | 120 | ```html 121 | 122 |
123 | ``` 124 | 125 | ```html 126 | 127 |
128 | ``` 129 | 130 | ## Event 131 | 132 | - busyStop : Will be triggered when the busy is done 133 | - busyStart : Will be triggered when the busy comes out. 134 | 135 | ### Usage 136 | 137 | ```html 138 | 139 |
140 | ``` 141 | 142 | ## Options 143 | 144 | | Option | Required | Default | Details | 145 | | ---- | ---- | ---- | ---- | 146 | | busy | Required | null | A busy thing (or an array of busy things) that will cause the loading indicator to show. | 147 | | message | Optional | 'Please wait...' | The message to show in the indicator which will reflect the updated values as they are changed. | 148 | | backdrop | Optional | true | A faded backdrop will be shown behind the indicator if true. | 149 | | template | Optional | A default template component | The template can be a template or a component. If provided, the custom template will be shown in place of the default indicatory template. The scope can be augmented with a `{{message}}` field containing the indicator message text. | 150 | | delay | Optional | 0 | The amount of time to wait until showing the indicator. Specified in milliseconds. 151 | | minDuration | Optional | 0 | The amount of time to keep the indicator showing even if the busy thing was completed quicker. Specified in milliseconds.| 152 | | disableAnimation | Optional | false | Disable the animation when the spinner appear | 153 | | wrapperClass | Optional | 'ng-busy' | The name(s) of the CSS classes to be applied to the wrapper element of the indicator. | 154 | | templateNgStyle | Optional | { } | An object that will be assigned to the custom component assigned to `template` option, if one was configured (see example below in Overriding Defaults). | 155 | 156 | 157 | ## Overriding Defaults 158 | 159 | The default values of options can be overriden by configuring the provider of the `BusyModule`. 160 | 161 | In the root application module, you can do this: 162 | 163 | ```ts 164 | import {NgModule} from '@angular/core'; 165 | import {NgBusyModule, BusyConfig} from 'ng-busy'; 166 | import {CustomBusyComponent} from '...' 167 | 168 | @NgModule({ 169 | imports: [ 170 | ... 171 | NgBusyModule.forRoot(new BusyConfig({ 172 | message: 'Don\'t panic!', 173 | backdrop: false, 174 | template: CustomBusyComponent, 175 | delay: 200, 176 | minDuration: 600, 177 | templateNgStyle: { "background-color": "black" } 178 | })) 179 | ], 180 | declarations: [ 181 | ... 182 | CustomBusyComponent, 183 | ... 184 | ], 185 | entryComponents: [ 186 | CustomBusyComponent 187 | ], 188 | }) 189 | export class AppModule 190 | ``` 191 | 192 | ```ts 193 | @Component({ 194 | selector: 'default-busy', 195 | template: ` 196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
{{message}}
213 |
214 |
215 | `, 216 | }) 217 | export class CustomBusyComponent { 218 | constructor(@Inject('instanceConfigHolder') private instanceConfigHolder: InstanceConfigHolderService) { 219 | } 220 | 221 | get message() { 222 | return this.instanceConfigHolder.config.message; 223 | } 224 | } 225 | ``` 226 | 227 | 228 | 229 | ## Credits 230 | 231 | Rewritten from [devyumao](https://github.com/devyumao)'s [angular2-busy](https://github.com/devyumao/angular2-busy). 232 | 233 | ## LICENSE 234 | 235 | This project is licensed under the MIT license. See the [LICENSE](https://github.com/victos/ng-busy/blob/master/LICENSE) file for more info. 236 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/service/busy-tracker.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {TestBed, inject, fakeAsync, tick} from '@angular/core/testing'; 2 | 3 | import {BusyTrackerService} from './busy-tracker.service'; 4 | import {Subscription} from 'rxjs/internal/Subscription'; 5 | import {Observable} from 'rxjs/internal/Observable'; 6 | 7 | const prepareOption = (delay: number, minDuration: number, busyList: Array | Subscription>) => { 8 | return { 9 | minDuration: minDuration, 10 | delay: delay, 11 | busyList: busyList 12 | }; 13 | }; 14 | const createPromiseWithDelay = (delay: number): Promise => { 15 | return new Promise((resolve) => { 16 | setTimeout(() => { 17 | resolve(); 18 | }, delay); 19 | }); 20 | }; 21 | const createSubscriptionWithDelay = (delay: number): Subscription => { 22 | return new Observable((o) => { 23 | setTimeout(() => { 24 | o.next(); 25 | o.complete(); 26 | }, delay); 27 | }).subscribe(() => {}); 28 | }; 29 | describe('BusyTrackerService', () => { 30 | beforeEach(() => { 31 | TestBed.configureTestingModule({ 32 | providers: [BusyTrackerService] 33 | }); 34 | }); 35 | 36 | it('should be created', inject([BusyTrackerService], (service: BusyTrackerService) => { 37 | expect(service).toBeTruthy(); 38 | })); 39 | 40 | it('after service init the isActive should be false', inject([BusyTrackerService], (service: BusyTrackerService) => { 41 | expect(service.isActive).toBe(false); 42 | expect(service.busyList.length).toBe(0); 43 | })); 44 | 45 | it('the options should work as expected', fakeAsync(inject([BusyTrackerService], (service: BusyTrackerService) => { 46 | service.load(prepareOption(200, 500, [createPromiseWithDelay(500)])); 47 | expect(service.isActive).toBe(false); 48 | tick(100); 49 | expect(service.isActive).toBe(false); 50 | tick(100); 51 | expect(service.isActive).toBe(true); 52 | tick(300); 53 | expect(service.isActive).toBe(true); 54 | tick(100); 55 | expect(service.isActive).toBe(true); 56 | tick(100); 57 | expect(service.isActive).toBe(false); 58 | expect(service.busyList.length).toBe(0); 59 | 60 | service.load(prepareOption(200, 100, [createPromiseWithDelay(500)])); 61 | expect(service.isActive).toBe(false); 62 | tick(100); 63 | expect(service.isActive).toBe(false); 64 | tick(100); 65 | expect(service.isActive).toBe(true); 66 | tick(150); 67 | expect(service.isActive).toBe(true); 68 | tick(150); 69 | expect(service.isActive).toBe(false); 70 | expect(service.busyList.length).toBe(0); 71 | 72 | service.load(prepareOption(0, 300, [createPromiseWithDelay(500)])); 73 | tick(0); 74 | expect(service.isActive).toBe(true); 75 | tick(200); 76 | expect(service.isActive).toBe(true); 77 | tick(150); 78 | expect(service.isActive).toBe(true); 79 | tick(150); 80 | expect(service.isActive).toBe(false); 81 | expect(service.busyList.length).toBe(0); 82 | 83 | service.load(prepareOption(0, 600, [createPromiseWithDelay(500)])); 84 | tick(0); 85 | expect(service.isActive).toBe(true); 86 | tick(200); 87 | expect(service.isActive).toBe(true); 88 | tick(150); 89 | expect(service.isActive).toBe(true); 90 | tick(150); 91 | expect(service.isActive).toBe(true); 92 | tick(100); 93 | expect(service.isActive).toBe(false); 94 | expect(service.busyList.length).toBe(0); 95 | 96 | service.load(prepareOption(200, 0, [createPromiseWithDelay(500)])); 97 | expect(service.isActive).toBe(false); 98 | tick(100); 99 | expect(service.isActive).toBe(false); 100 | tick(100); 101 | expect(service.isActive).toBe(true); 102 | tick(200); 103 | expect(service.isActive).toBe(true); 104 | tick(100); 105 | expect(service.isActive).toBe(false); 106 | expect(service.busyList.length).toBe(0); 107 | 108 | service.load(prepareOption(600, 0, [createPromiseWithDelay(500)])); 109 | expect(service.isActive).toBe(false); 110 | tick(300); 111 | expect(service.isActive).toBe(false); 112 | tick(240); 113 | expect(service.isActive).toBe(false); 114 | tick(60); 115 | expect(service.isActive).toBe(false); 116 | expect(service.busyList.length).toBe(0); 117 | }))); 118 | 119 | it('after load empty busyList the isActive should be false', inject([BusyTrackerService], (service: BusyTrackerService) => { 120 | service.load(prepareOption(0, 0, [])); 121 | expect(service.isActive).toBe(false); 122 | expect(service.busyList.length).toBe(0); 123 | service.load(prepareOption(10, 5, [])); 124 | expect(service.isActive).toBe(false); 125 | expect(service.busyList.length).toBe(0); 126 | })); 127 | 128 | it('when there is only one busy after load the option the isActive should be true until the busy finished', 129 | inject([BusyTrackerService], fakeAsync((service: BusyTrackerService) => { 130 | const optionsWithPromise = prepareOption(0, 0, [createPromiseWithDelay(1000)]); 131 | service.load(optionsWithPromise); 132 | tick(0); 133 | expect(service.isActive).toBe(true); 134 | tick(100); 135 | expect(service.isActive).toBe(true); 136 | tick(300); 137 | expect(service.isActive).toBe(true); 138 | tick(400); 139 | expect(service.isActive).toBe(true); 140 | tick(200); 141 | expect(service.isActive).toBe(false); 142 | expect(service.busyList.length).toBe(0); 143 | 144 | const optionsWithSubscription = prepareOption(0, 0, [createSubscriptionWithDelay(1000)]); 145 | service.load(optionsWithSubscription); 146 | tick(0); 147 | expect(service.isActive).toBe(true); 148 | tick(100); 149 | expect(service.isActive).toBe(true); 150 | tick(300); 151 | expect(service.isActive).toBe(true); 152 | tick(400); 153 | expect(service.isActive).toBe(true); 154 | tick(200); 155 | expect(service.isActive).toBe(false); 156 | expect(service.busyList.length).toBe(0); 157 | }))); 158 | 159 | it('the events should be triggered', inject([BusyTrackerService], fakeAsync((service: BusyTrackerService) => { 160 | let isStarted = false; 161 | let isStopped = true; 162 | service.active.subscribe((status) => { 163 | isStarted = status === true; 164 | isStopped = status === false; 165 | }); 166 | const options = prepareOption(0, 0, [createPromiseWithDelay(1000)]); 167 | service.load(options); 168 | tick(500); 169 | expect(isStarted).toBe(true); 170 | expect(isStopped).toBe(false); 171 | tick(500); 172 | expect(isStarted).toBe(false); 173 | expect(isStopped).toBe(true); 174 | expect(service.busyList.length).toBe(0); 175 | }))); 176 | 177 | it('when there are many busies', inject([BusyTrackerService], fakeAsync((service: BusyTrackerService) => { 178 | service.load(prepareOption(0, 0, [createPromiseWithDelay(100), createPromiseWithDelay(600), createPromiseWithDelay(200)])); 179 | tick(0); 180 | expect(service.isActive).toBe(true); 181 | tick(150); 182 | expect(service.isActive).toBe(true); 183 | tick(250); 184 | expect(service.isActive).toBe(true); 185 | tick(200); 186 | expect(service.isActive).toBe(false); 187 | expect(service.busyList.length).toBe(0); 188 | }))); 189 | 190 | it('when load options many times and add busy dynamically', inject([BusyTrackerService], fakeAsync((service: BusyTrackerService) => { 191 | service.load(prepareOption(0, 0, [createPromiseWithDelay(100), createPromiseWithDelay(600), createPromiseWithDelay(200)])); 192 | expect(service.busyList.length).toBe(3); 193 | tick(0); 194 | expect(service.isActive).toBe(true); 195 | tick(150); 196 | expect(service.isActive).toBe(true); 197 | expect(service.busyList.length).toBe(2); 198 | tick(250); 199 | expect(service.busyList.length).toBe(1); 200 | service.load(prepareOption(0, 0, [createSubscriptionWithDelay(700), createPromiseWithDelay(500), createPromiseWithDelay(100)])); 201 | expect(service.busyList.length).toBe(4); 202 | expect(service.isActive).toBe(true); 203 | tick(200); 204 | expect(service.busyList.length).toBe(2); 205 | expect(service.isActive).toBe(true); 206 | tick(400); 207 | expect(service.busyList.length).toBe(1); 208 | expect(service.isActive).toBe(true); 209 | tick(100); 210 | expect(service.isActive).toBe(false); 211 | expect(service.busyList.length).toBe(0); 212 | }))); 213 | }); 214 | -------------------------------------------------------------------------------- /projects/ng-busy/src/lib/ng-busy.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; 2 | import { BusyTrackerService } from './service/busy-tracker.service'; 3 | import { BusyConfigHolderService } from './service/busy-config-holder.service'; 4 | import { 5 | ApplicationRef, ChangeDetectionStrategy, ChangeDetectorRef, 6 | Component, 7 | DebugElement, 8 | ElementRef, Inject, 9 | Injector, 10 | Renderer2, TemplateRef, ViewChild, 11 | ViewContainerRef 12 | } from '@angular/core'; 13 | import { By } from '@angular/platform-browser'; 14 | import { NgBusyModule } from './ng-busy.module'; 15 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 16 | import { Subscription, Observable } from 'rxjs'; 17 | import { InstanceConfigHolderService } from './service/instance-config-holder.service'; 18 | 19 | const createPromiseWithDelay = (delay: number): Promise => { 20 | return new Promise((resolve) => { 21 | setTimeout(() => { 22 | resolve(); 23 | }, delay); 24 | }); 25 | }; 26 | 27 | const createSubscriptionWithDelay = (delay: number): Subscription => { 28 | return new Observable((o) => { 29 | setTimeout(() => { 30 | o.next(); 31 | o.complete(); 32 | }, delay); 33 | }).subscribe(() => { 34 | }); 35 | }; 36 | 37 | // @ts-ignore 38 | @Component({ 39 | selector: 'lib-component-template', 40 | template: ` 41 |
42 |
43 | {{message}} 44 |
45 |
46 | `, 47 | }) 48 | export class CustomBusyComponent { 49 | 50 | constructor(@Inject('instanceConfigHolder') private instanceConfigHolder: InstanceConfigHolderService) { 51 | } 52 | 53 | get message() { 54 | return this.instanceConfigHolder.config.message; 55 | } 56 | } 57 | 58 | @Component({ 59 | template: ` 60 | 61 |
Hi, This is from ng-template.
62 |
63 |
` 64 | }) 65 | class TestNgBusyComponent { 66 | options: any; 67 | @ViewChild('customTemplate', { static: true }) 68 | customTemplate: TemplateRef; 69 | } 70 | 71 | @Component({ 72 | template: ` 73 |
`, 74 | changeDetection: ChangeDetectionStrategy.OnPush 75 | }) 76 | class TestNgBusyOnPushComponent { 77 | options: any; 78 | 79 | constructor(public cdr: ChangeDetectorRef) { 80 | } 81 | } 82 | 83 | describe('NgBusyDirective', () => { 84 | let component: TestNgBusyComponent; 85 | let fixture: ComponentFixture; 86 | let busyContainer: DebugElement; 87 | let spinner; 88 | const mockElementRef: ElementRef = { nativeElement: undefined }; 89 | 90 | beforeEach(waitForAsync(() => { 91 | TestBed.configureTestingModule({ 92 | declarations: [TestNgBusyComponent, CustomBusyComponent, TestNgBusyOnPushComponent], 93 | imports: [NgBusyModule.forRoot({ 94 | wrapperClass: 'for_root_class' 95 | }), BrowserAnimationsModule], 96 | providers: [BusyConfigHolderService, BusyTrackerService, 97 | ApplicationRef, ViewContainerRef, { provide: ElementRef, useValue: mockElementRef }, Renderer2, Injector] 98 | }); 99 | 100 | })); 101 | 102 | beforeEach(() => { 103 | fixture = TestBed.createComponent(TestNgBusyComponent); 104 | component = fixture.componentInstance; 105 | busyContainer = fixture.debugElement.query(By.css('div.ng-busy-container-for-test')); 106 | mockElementRef.nativeElement = fixture.elementRef.nativeElement; 107 | fixture.detectChanges(); 108 | }); 109 | 110 | it('should not create lib-ng-busy after init the NgBusyDirective', waitForAsync(() => { 111 | const compiled = fixture.debugElement.nativeElement; 112 | component.options = undefined; 113 | fixture.detectChanges(); 114 | expect(compiled.querySelector('lib-ng-busy')).toBeNull(); 115 | })); 116 | 117 | it('should work as expected when use Subscription as busyOption', fakeAsync(() => { 118 | component.options = createSubscriptionWithDelay(1000); 119 | fixture.detectChanges(); 120 | tick(300); 121 | fixture.detectChanges(); 122 | spinner = fixture.debugElement.query(By.css('lib-ng-busy default-busy')); 123 | expect(spinner).not.toBeNull(); 124 | tick(700); 125 | fixture.detectChanges(); 126 | spinner = fixture.debugElement.query(By.css('lib-ng-busy default-busy')); 127 | expect(spinner).not.toBeNull(); 128 | tick(); 129 | })); 130 | 131 | it('should load default template when there is a busy and no template configured', fakeAsync(() => { 132 | component.options = createPromiseWithDelay(1000); 133 | fixture.detectChanges(); 134 | tick(300); 135 | fixture.detectChanges(); 136 | spinner = fixture.debugElement.query(By.css('lib-ng-busy default-busy')); 137 | expect(spinner).not.toBeNull(); 138 | tick(700); 139 | fixture.detectChanges(); 140 | spinner = fixture.debugElement.query(By.css('lib-ng-busy default-busy')); 141 | expect(spinner).not.toBeNull(); 142 | tick(); 143 | })); 144 | 145 | it('should load the template when the option template is configured', fakeAsync(() => { 146 | component.options = { 147 | busy: createPromiseWithDelay(1000), 148 | template: component.customTemplate 149 | }; 150 | fixture.detectChanges(); 151 | tick(300); 152 | fixture.detectChanges(); 153 | spinner = fixture.debugElement.query(By.css('lib-ng-busy .custom_template_for_test')) 154 | expect(spinner.nativeElement.textContent) 155 | .toBe('Hi, This is from ng-template.'); 156 | tick(700); 157 | fixture.detectChanges(); 158 | spinner = fixture.debugElement.query(By.css('lib-ng-busy .custom_template_for_test')) 159 | expect(spinner).toBeNull(); 160 | tick(); 161 | })); 162 | 163 | 164 | it('string typed template', fakeAsync(() => { 165 | component.options = { 166 | busy: createPromiseWithDelay(1000), 167 | template: 'hello', 168 | wrapperClass: 'content_class' 169 | }; 170 | fixture.detectChanges(); 171 | tick(300); 172 | fixture.detectChanges(); 173 | expect(fixture.debugElement.query(By.css('lib-ng-busy>.content_class')).nativeElement.textContent) 174 | .toBe('hello'); 175 | tick(700); 176 | fixture.detectChanges(); 177 | expect(fixture.debugElement.query(By.css('lib-ng-busy>.content_class'))).toBeNull(); 178 | tick(); 179 | })); 180 | 181 | it('not affect each other when there many busies', fakeAsync(() => { 182 | const fixture1 = TestBed.createComponent(TestNgBusyComponent); 183 | const component1 = fixture1.componentInstance; 184 | component.options = { 185 | busy: createPromiseWithDelay(1000), 186 | template: 'hello', 187 | wrapperClass: 'content_class' 188 | }; 189 | fixture.detectChanges(); 190 | fixture1.detectChanges(); 191 | tick(300); 192 | fixture.detectChanges(); 193 | fixture1.detectChanges(); 194 | expect(fixture.debugElement.query(By.css('lib-ng-busy>.content_class')).nativeElement.textContent) 195 | .toBe('hello'); 196 | expect(fixture1.debugElement.query(By.css('lib-ng-busy>.content_class'))).toBeNull(); 197 | expect(fixture1.debugElement.query(By.css('lib-ng-busy>.another_content_class'))).toBeNull(); 198 | component1.options = { 199 | busy: createPromiseWithDelay(1000), 200 | template: 'I\'m from another busy', 201 | wrapperClass: 'another_content_class' 202 | }; 203 | tick(0); 204 | fixture.detectChanges(); 205 | fixture1.detectChanges(); 206 | tick(700); 207 | fixture.detectChanges(); 208 | fixture1.detectChanges(); 209 | expect(fixture.debugElement.query(By.css('lib-ng-busy>.content_class'))).toBeNull(); 210 | expect(fixture1.debugElement.query(By.css('lib-ng-busy>.another_content_class')).nativeElement.textContent) 211 | .toBe('I\'m from another busy'); 212 | tick(300); 213 | fixture.detectChanges(); 214 | fixture1.detectChanges(); 215 | expect(fixture.debugElement.query(By.css('lib-ng-busy>.content_class'))).toBeNull(); 216 | expect(fixture1.debugElement.query(By.css('lib-ng-busy>.content_class'))).toBeNull(); 217 | expect(fixture1.debugElement.query(By.css('lib-ng-busy>.another_content_class'))).toBeNull(); 218 | tick(); 219 | })); 220 | 221 | it('component typed template', fakeAsync(() => { 222 | component.options = { 223 | busy: createPromiseWithDelay(1000), 224 | template: CustomBusyComponent, 225 | message: 'this is from component', 226 | wrapperClass: 'content_class_component' 227 | }; 228 | fixture.detectChanges(); 229 | tick(300); 230 | fixture.detectChanges(); 231 | expect(fixture.debugElement.query(By.css('lib-ng-busy>.content_class_component')).nativeElement.textContent.trim()) 232 | .toBe('this is from component'); 233 | tick(700); 234 | fixture.detectChanges(); 235 | expect(fixture.debugElement.query(By.css('lib-ng-busy>.content_class_component'))).toBeNull(); 236 | tick(); 237 | })); 238 | 239 | it('the message of the busy should be changed if the message in the option is changed', fakeAsync(() => { 240 | component.options = { 241 | busy: createPromiseWithDelay(1000), 242 | template: CustomBusyComponent, 243 | message: 'this is from component', 244 | wrapperClass: 'content_class_component' 245 | }; 246 | fixture.detectChanges(); 247 | tick(300); 248 | fixture.detectChanges(); 249 | expect(fixture.debugElement.query(By.css('lib-ng-busy>.content_class_component')).nativeElement.textContent.trim()) 250 | .toBe('this is from component'); 251 | component.options.message = 'wow, the message changed!!!'; 252 | tick(200); 253 | fixture.detectChanges(); 254 | expect(fixture.debugElement.query(By.css('lib-ng-busy>.content_class_component')).nativeElement.textContent.trim()) 255 | .toBe('wow, the message changed!!!'); 256 | tick(500); 257 | fixture.detectChanges(); 258 | expect(fixture.debugElement.query(By.css('lib-ng-busy>.content_class_component'))).toBeNull(); 259 | tick(); 260 | })); 261 | 262 | }); 263 | -------------------------------------------------------------------------------- /src/assets/css/bootstrap.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v4.0.0-alpha.2 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active{outline:0}a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}@media print{*,::after,::before{text-shadow:none!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}html{-webkit-box-sizing:border-box;box-sizing:border-box}*,::after,::before{-webkit-box-sizing:inherit;box-sizing:inherit}@-ms-viewport{width:device-width}@viewport{width:device-width}html{font-size:16px;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:1rem;line-height:1.5;color:#373a3c;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #818a91}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}a{color:#0275d8;text-decoration:none}a:focus,a:hover{color:#014c8c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}pre{margin-top:0;margin-bottom:1rem}figure{margin:0 0 1rem}img{vertical-align:middle}[role=button]{cursor:pointer}[role=button],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{background-color:transparent}caption{padding-top:.75rem;padding-bottom:.75rem;color:#818a91;text-align:left;caption-side:bottom}th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,select,textarea{margin:0;line-height:inherit;border-radius:0}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit}input[type=search]{-webkit-box-sizing:inherit;box-sizing:inherit;-webkit-appearance:none}output{display:inline-block}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1{font-size:2.5rem}h2{font-size:2rem}h3{font-size:1.75rem}h4{font-size:1.5rem}h5{font-size:1.25rem}h6{font-size:1rem}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.75rem}.h4{font-size:1.5rem}.h5{font-size:1.25rem}.h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300}.display-2{font-size:5.5rem;font-weight:300}.display-3{font-size:4.5rem;font-weight:300}.display-4{font-size:3.5rem;font-weight:300}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:5px}.dl-horizontal{margin-right:-1.875rem;margin-left:-1.875rem}.dl-horizontal::after{display:table;clear:both;content:""}.initialism{font-size:90%;text-transform:uppercase}.blockquote{padding:.5rem 1rem;margin-bottom:1rem;font-size:1.25rem;border-left:.25rem solid #eceeef}.blockquote-footer{display:block;font-size:80%;line-height:1.5;color:#818a91}.blockquote-footer::before{content:"\2014 \00A0"}.blockquote-reverse{padding-right:1rem;padding-left:0;text-align:right;border-right:.25rem solid #eceeef;border-left:0}.blockquote-reverse .blockquote-footer::before{content:""}.blockquote-reverse .blockquote-footer::after{content:"\00A0 \2014"}.carousel-inner>.carousel-item>a>img,.carousel-inner>.carousel-item>img,.img-fluid{display:block;max-width:100%;height:auto}.img-rounded{border-radius:.3rem}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:.25rem;line-height:1.5;background-color:#fff;border:1px solid #ddd;border-radius:.25rem;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#818a91}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:.2rem .4rem;font-size:90%;color:#bd4147;background-color:#f7f7f9;border-radius:.25rem}kbd{padding:.2rem .4rem;font-size:90%;color:#fff;background-color:#333;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;margin-top:0;margin-bottom:1rem;font-size:90%;line-height:1.5;color:#373a3c}pre code{padding:0;font-size:inherit;color:inherit;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:.9375rem;padding-left:.9375rem;margin-right:auto;margin-left:auto}.container::after{display:table;clear:both;content:""}@media (min-width:544px){.container{max-width:576px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:940px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{padding-right:.9375rem;padding-left:.9375rem;margin-right:auto;margin-left:auto}.container-fluid::after{display:table;clear:both;content:""}.row{margin-right:-.9375rem;margin-left:-.9375rem}.row::after{display:table;clear:both;content:""}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:.9375rem;padding-left:.9375rem}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-1{width:8.333333%}.col-xs-2{width:16.666667%}.col-xs-3{width:25%}.col-xs-4{width:33.333333%}.col-xs-5{width:41.666667%}.col-xs-6{width:50%}.col-xs-7{width:58.333333%}.col-xs-8{width:66.666667%}.col-xs-9{width:75%}.col-xs-10{width:83.333333%}.col-xs-11{width:91.666667%}.col-xs-12{width:100%}.col-xs-pull-0{right:auto}.col-xs-pull-1{right:8.333333%}.col-xs-pull-2{right:16.666667%}.col-xs-pull-3{right:25%}.col-xs-pull-4{right:33.333333%}.col-xs-pull-5{right:41.666667%}.col-xs-pull-6{right:50%}.col-xs-pull-7{right:58.333333%}.col-xs-pull-8{right:66.666667%}.col-xs-pull-9{right:75%}.col-xs-pull-10{right:83.333333%}.col-xs-pull-11{right:91.666667%}.col-xs-pull-12{right:100%}.col-xs-push-0{left:auto}.col-xs-push-1{left:8.333333%}.col-xs-push-2{left:16.666667%}.col-xs-push-3{left:25%}.col-xs-push-4{left:33.333333%}.col-xs-push-5{left:41.666667%}.col-xs-push-6{left:50%}.col-xs-push-7{left:58.333333%}.col-xs-push-8{left:66.666667%}.col-xs-push-9{left:75%}.col-xs-push-10{left:83.333333%}.col-xs-push-11{left:91.666667%}.col-xs-push-12{left:100%}.col-xs-offset-0{margin-left:0}.col-xs-offset-1{margin-left:8.333333%}.col-xs-offset-2{margin-left:16.666667%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-4{margin-left:33.333333%}.col-xs-offset-5{margin-left:41.666667%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-7{margin-left:58.333333%}.col-xs-offset-8{margin-left:66.666667%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-10{margin-left:83.333333%}.col-xs-offset-11{margin-left:91.666667%}.col-xs-offset-12{margin-left:100%}@media (min-width:544px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-1{width:8.333333%}.col-sm-2{width:16.666667%}.col-sm-3{width:25%}.col-sm-4{width:33.333333%}.col-sm-5{width:41.666667%}.col-sm-6{width:50%}.col-sm-7{width:58.333333%}.col-sm-8{width:66.666667%}.col-sm-9{width:75%}.col-sm-10{width:83.333333%}.col-sm-11{width:91.666667%}.col-sm-12{width:100%}.col-sm-pull-0{right:auto}.col-sm-pull-1{right:8.333333%}.col-sm-pull-2{right:16.666667%}.col-sm-pull-3{right:25%}.col-sm-pull-4{right:33.333333%}.col-sm-pull-5{right:41.666667%}.col-sm-pull-6{right:50%}.col-sm-pull-7{right:58.333333%}.col-sm-pull-8{right:66.666667%}.col-sm-pull-9{right:75%}.col-sm-pull-10{right:83.333333%}.col-sm-pull-11{right:91.666667%}.col-sm-pull-12{right:100%}.col-sm-push-0{left:auto}.col-sm-push-1{left:8.333333%}.col-sm-push-2{left:16.666667%}.col-sm-push-3{left:25%}.col-sm-push-4{left:33.333333%}.col-sm-push-5{left:41.666667%}.col-sm-push-6{left:50%}.col-sm-push-7{left:58.333333%}.col-sm-push-8{left:66.666667%}.col-sm-push-9{left:75%}.col-sm-push-10{left:83.333333%}.col-sm-push-11{left:91.666667%}.col-sm-push-12{left:100%}.col-sm-offset-0{margin-left:0}.col-sm-offset-1{margin-left:8.333333%}.col-sm-offset-2{margin-left:16.666667%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-4{margin-left:33.333333%}.col-sm-offset-5{margin-left:41.666667%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-7{margin-left:58.333333%}.col-sm-offset-8{margin-left:66.666667%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-10{margin-left:83.333333%}.col-sm-offset-11{margin-left:91.666667%}.col-sm-offset-12{margin-left:100%}}@media (min-width:768px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-1{width:8.333333%}.col-md-2{width:16.666667%}.col-md-3{width:25%}.col-md-4{width:33.333333%}.col-md-5{width:41.666667%}.col-md-6{width:50%}.col-md-7{width:58.333333%}.col-md-8{width:66.666667%}.col-md-9{width:75%}.col-md-10{width:83.333333%}.col-md-11{width:91.666667%}.col-md-12{width:100%}.col-md-pull-0{right:auto}.col-md-pull-1{right:8.333333%}.col-md-pull-2{right:16.666667%}.col-md-pull-3{right:25%}.col-md-pull-4{right:33.333333%}.col-md-pull-5{right:41.666667%}.col-md-pull-6{right:50%}.col-md-pull-7{right:58.333333%}.col-md-pull-8{right:66.666667%}.col-md-pull-9{right:75%}.col-md-pull-10{right:83.333333%}.col-md-pull-11{right:91.666667%}.col-md-pull-12{right:100%}.col-md-push-0{left:auto}.col-md-push-1{left:8.333333%}.col-md-push-2{left:16.666667%}.col-md-push-3{left:25%}.col-md-push-4{left:33.333333%}.col-md-push-5{left:41.666667%}.col-md-push-6{left:50%}.col-md-push-7{left:58.333333%}.col-md-push-8{left:66.666667%}.col-md-push-9{left:75%}.col-md-push-10{left:83.333333%}.col-md-push-11{left:91.666667%}.col-md-push-12{left:100%}.col-md-offset-0{margin-left:0}.col-md-offset-1{margin-left:8.333333%}.col-md-offset-2{margin-left:16.666667%}.col-md-offset-3{margin-left:25%}.col-md-offset-4{margin-left:33.333333%}.col-md-offset-5{margin-left:41.666667%}.col-md-offset-6{margin-left:50%}.col-md-offset-7{margin-left:58.333333%}.col-md-offset-8{margin-left:66.666667%}.col-md-offset-9{margin-left:75%}.col-md-offset-10{margin-left:83.333333%}.col-md-offset-11{margin-left:91.666667%}.col-md-offset-12{margin-left:100%}}@media (min-width:992px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-1{width:8.333333%}.col-lg-2{width:16.666667%}.col-lg-3{width:25%}.col-lg-4{width:33.333333%}.col-lg-5{width:41.666667%}.col-lg-6{width:50%}.col-lg-7{width:58.333333%}.col-lg-8{width:66.666667%}.col-lg-9{width:75%}.col-lg-10{width:83.333333%}.col-lg-11{width:91.666667%}.col-lg-12{width:100%}.col-lg-pull-0{right:auto}.col-lg-pull-1{right:8.333333%}.col-lg-pull-2{right:16.666667%}.col-lg-pull-3{right:25%}.col-lg-pull-4{right:33.333333%}.col-lg-pull-5{right:41.666667%}.col-lg-pull-6{right:50%}.col-lg-pull-7{right:58.333333%}.col-lg-pull-8{right:66.666667%}.col-lg-pull-9{right:75%}.col-lg-pull-10{right:83.333333%}.col-lg-pull-11{right:91.666667%}.col-lg-pull-12{right:100%}.col-lg-push-0{left:auto}.col-lg-push-1{left:8.333333%}.col-lg-push-2{left:16.666667%}.col-lg-push-3{left:25%}.col-lg-push-4{left:33.333333%}.col-lg-push-5{left:41.666667%}.col-lg-push-6{left:50%}.col-lg-push-7{left:58.333333%}.col-lg-push-8{left:66.666667%}.col-lg-push-9{left:75%}.col-lg-push-10{left:83.333333%}.col-lg-push-11{left:91.666667%}.col-lg-push-12{left:100%}.col-lg-offset-0{margin-left:0}.col-lg-offset-1{margin-left:8.333333%}.col-lg-offset-2{margin-left:16.666667%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-4{margin-left:33.333333%}.col-lg-offset-5{margin-left:41.666667%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-7{margin-left:58.333333%}.col-lg-offset-8{margin-left:66.666667%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-10{margin-left:83.333333%}.col-lg-offset-11{margin-left:91.666667%}.col-lg-offset-12{margin-left:100%}}@media (min-width:1200px){.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{float:left}.col-xl-1{width:8.333333%}.col-xl-2{width:16.666667%}.col-xl-3{width:25%}.col-xl-4{width:33.333333%}.col-xl-5{width:41.666667%}.col-xl-6{width:50%}.col-xl-7{width:58.333333%}.col-xl-8{width:66.666667%}.col-xl-9{width:75%}.col-xl-10{width:83.333333%}.col-xl-11{width:91.666667%}.col-xl-12{width:100%}.col-xl-pull-0{right:auto}.col-xl-pull-1{right:8.333333%}.col-xl-pull-2{right:16.666667%}.col-xl-pull-3{right:25%}.col-xl-pull-4{right:33.333333%}.col-xl-pull-5{right:41.666667%}.col-xl-pull-6{right:50%}.col-xl-pull-7{right:58.333333%}.col-xl-pull-8{right:66.666667%}.col-xl-pull-9{right:75%}.col-xl-pull-10{right:83.333333%}.col-xl-pull-11{right:91.666667%}.col-xl-pull-12{right:100%}.col-xl-push-0{left:auto}.col-xl-push-1{left:8.333333%}.col-xl-push-2{left:16.666667%}.col-xl-push-3{left:25%}.col-xl-push-4{left:33.333333%}.col-xl-push-5{left:41.666667%}.col-xl-push-6{left:50%}.col-xl-push-7{left:58.333333%}.col-xl-push-8{left:66.666667%}.col-xl-push-9{left:75%}.col-xl-push-10{left:83.333333%}.col-xl-push-11{left:91.666667%}.col-xl-push-12{left:100%}.col-xl-offset-0{margin-left:0}.col-xl-offset-1{margin-left:8.333333%}.col-xl-offset-2{margin-left:16.666667%}.col-xl-offset-3{margin-left:25%}.col-xl-offset-4{margin-left:33.333333%}.col-xl-offset-5{margin-left:41.666667%}.col-xl-offset-6{margin-left:50%}.col-xl-offset-7{margin-left:58.333333%}.col-xl-offset-8{margin-left:66.666667%}.col-xl-offset-9{margin-left:75%}.col-xl-offset-10{margin-left:83.333333%}.col-xl-offset-11{margin-left:91.666667%}.col-xl-offset-12{margin-left:100%}}.table{width:100%;max-width:100%;margin-bottom:1rem}.table td,.table th{padding:.75rem;line-height:1.5;vertical-align:top;border-top:1px solid #eceeef}.table thead th{vertical-align:bottom;border-bottom:2px solid #eceeef}.table tbody+tbody{border-top:2px solid #eceeef}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #eceeef}.table-bordered td,.table-bordered th{border:1px solid #eceeef}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover tbody tr:hover{background-color:#f5f5f5}.table-active,.table-active>td,.table-active>th{background-color:#f5f5f5}.table-hover .table-active:hover{background-color:#e8e8e8}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:#e8e8e8}.table-success,.table-success>td,.table-success>th{background-color:#dff0d8}.table-hover .table-success:hover{background-color:#d0e9c6}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#d0e9c6}.table-info,.table-info>td,.table-info>th{background-color:#d9edf7}.table-hover .table-info:hover{background-color:#c4e3f3}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#c4e3f3}.table-warning,.table-warning>td,.table-warning>th{background-color:#fcf8e3}.table-hover .table-warning:hover{background-color:#faf2cc}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#faf2cc}.table-danger,.table-danger>td,.table-danger>th{background-color:#f2dede}.table-hover .table-danger:hover{background-color:#ebcccc}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#ebcccc}.table-responsive{display:block;width:100%;min-height:.01%;overflow-x:auto}.thead-inverse th{color:#fff;background-color:#373a3c}.thead-default th{color:#55595c;background-color:#eceeef}.table-inverse{color:#eceeef;background-color:#373a3c}.table-inverse.table-bordered{border:0}.table-inverse td,.table-inverse th,.table-inverse thead th{border-color:#55595c}.table-reflow thead{float:left}.table-reflow tbody{display:block;white-space:nowrap}.table-reflow td,.table-reflow th{border-top:1px solid #eceeef;border-left:1px solid #eceeef}.table-reflow td:last-child,.table-reflow th:last-child{border-right:1px solid #eceeef}.table-reflow tbody:last-child tr:last-child td,.table-reflow tbody:last-child tr:last-child th,.table-reflow tfoot:last-child tr:last-child td,.table-reflow tfoot:last-child tr:last-child th,.table-reflow thead:last-child tr:last-child td,.table-reflow thead:last-child tr:last-child th{border-bottom:1px solid #eceeef}.table-reflow tr{float:left}.table-reflow tr td,.table-reflow tr th{display:block!important;border:1px solid #eceeef}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#55595c;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:.25rem}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{border-color:#66afe9;outline:0}.form-control::-webkit-input-placeholder{color:#999;opacity:1}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999;opacity:1}.form-control::placeholder{color:#999;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#eceeef;opacity:1}.form-control:disabled{cursor:not-allowed}.form-control-file,.form-control-range{display:block}.form-control-label{padding:.375rem .75rem;margin-bottom:0}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:2.25rem}.input-group-sm input[type=date].form-control,.input-group-sm input[type=time].form-control,.input-group-sm input[type=datetime-local].form-control,.input-group-sm input[type=month].form-control,input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:1.8625rem}.input-group-lg input[type=date].form-control,.input-group-lg input[type=time].form-control,.input-group-lg input[type=datetime-local].form-control,.input-group-lg input[type=month].form-control,input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:3.166667rem}}.form-control-static{min-height:2.25rem;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0}.form-control-static.form-control-lg,.form-control-static.form-control-sm,.input-group-lg>.form-control-static.form-control,.input-group-lg>.form-control-static.input-group-addon,.input-group-lg>.input-group-btn>.form-control-static.btn,.input-group-sm>.form-control-static.form-control,.input-group-sm>.form-control-static.input-group-addon,.input-group-sm>.input-group-btn>.form-control-static.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{padding:.275rem .75rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{padding:.75rem 1.25rem;font-size:1.25rem;line-height:1.333333;border-radius:.3rem}.form-group{margin-bottom:1rem}.checkbox,.radio{position:relative;display:block;margin-bottom:.75rem}.checkbox label,.radio label{padding-left:1.25rem;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox label input:only-child,.radio label input:only-child{position:static}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:.25rem;margin-left:-1.25rem}.checkbox+.checkbox,.radio+.radio{margin-top:-.25rem}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:1.25rem;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:.75rem}input[type=checkbox].disabled,input[type=checkbox]:disabled,input[type=radio].disabled,input[type=radio]:disabled{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label{cursor:not-allowed}.form-control-danger,.form-control-success,.form-control-warning{padding-right:2.25rem;background-repeat:no-repeat;background-position:center right .5625rem;-webkit-background-size:1.4625rem 1.4625rem;background-size:1.4625rem 1.4625rem}.has-success .checkbox,.has-success .checkbox-inline,.has-success .form-control-label,.has-success .radio,.has-success .radio-inline,.has-success .text-help,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#5cb85c}.has-success .form-control{border-color:#5cb85c}.has-success .input-group-addon{color:#5cb85c;background-color:#eaf6ea;border-color:#5cb85c}.has-success .form-control-feedback{color:#5cb85c}.has-success .form-control-success{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjNWNiODVjIiBkPSJNMjMzLjggNjEwYy0xMy4zIDAtMjYtNi0zNC0xNi44TDkwLjUgNDQ4LjhDNzYuMyA0MzAgODAgNDAzLjMgOTguOCAzODljMTguOC0xNC4yIDQ1LjUtMTAuNCA1OS44IDguNGw3MiA5NUw0NTEuMyAyNDJjMTIuNS0yMCAzOC44LTI2LjIgNTguOC0xMy43IDIwIDEyLjQgMjYgMzguNyAxMy43IDU4LjhMMjcwIDU5MGMtNy40IDEyLTIwLjIgMTkuNC0zNC4zIDIwaC0yeiIvPjwvc3ZnPg==)}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .form-control-label,.has-warning .radio,.has-warning .radio-inline,.has-warning .text-help,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#f0ad4e}.has-warning .form-control{border-color:#f0ad4e}.has-warning .input-group-addon{color:#f0ad4e;background-color:#fff;border-color:#f0ad4e}.has-warning .form-control-feedback{color:#f0ad4e}.has-warning .form-control-warning{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjZjBhZDRlIiBkPSJNNjAzIDY0MC4ybC0yNzguNS01MDljLTMuOC02LjYtMTAuOC0xMC42LTE4LjUtMTAuNnMtMTQuNyA0LTE4LjUgMTAuNkw5IDY0MC4yYy0zLjcgNi41LTMuNiAxNC40LjIgMjAuOCAzLjggNi41IDEwLjggMTAuNCAxOC4zIDEwLjRoNTU3YzcuNiAwIDE0LjYtNCAxOC40LTEwLjQgMy41LTYuNCAzLjYtMTQuNCAwLTIwLjh6bS0yNjYuNC0zMGgtNjEuMlY1NDloNjEuMnY2MS4yem0wLTEwN2gtNjEuMlYzMDRoNjEuMnYxOTl6Ii8+PC9zdmc+)}.has-danger .checkbox,.has-danger .checkbox-inline,.has-danger .form-control-label,.has-danger .radio,.has-danger .radio-inline,.has-danger .text-help,.has-danger.checkbox label,.has-danger.checkbox-inline label,.has-danger.radio label,.has-danger.radio-inline label{color:#d9534f}.has-danger .form-control{border-color:#d9534f}.has-danger .input-group-addon{color:#d9534f;background-color:#fdf7f7;border-color:#d9534f}.has-danger .form-control-feedback{color:#d9534f}.has-danger .form-control-danger{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjZDk1MzRmIiBkPSJNNDQ3IDU0NC40Yy0xNC40IDE0LjQtMzcuNiAxNC40LTUyIDBsLTg5LTkyLjctODkgOTIuN2MtMTQuNSAxNC40LTM3LjcgMTQuNC01MiAwLTE0LjQtMTQuNC0xNC40LTM3LjYgMC01Mmw5Mi40LTk2LjMtOTIuNC05Ni4zYy0xNC40LTE0LjQtMTQuNC0zNy42IDAtNTJzMzcuNi0xNC4zIDUyIDBsODkgOTIuOCA4OS4yLTkyLjdjMTQuNC0xNC40IDM3LjYtMTQuNCA1MiAwIDE0LjMgMTQuNCAxNC4zIDM3LjYgMCA1MkwzNTQuNiAzOTZsOTIuNCA5Ni40YzE0LjQgMTQuNCAxNC40IDM3LjYgMCA1MnoiLz48L3N2Zz4=)}@media (min-width:544px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .form-control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.btn{display:inline-block;padding:.375rem 1rem;font-size:1rem;font-weight:400;line-height:1.5;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;border-radius:.25rem}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:focus,.btn:hover{text-decoration:none}.btn.focus{text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0}.btn.disabled,.btn:disabled{cursor:not-allowed;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary:hover{color:#fff;background-color:#025aa5;border-color:#01549b}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#025aa5;border-color:#01549b}.btn-primary.active,.btn-primary:active,.open>.btn-primary.dropdown-toggle{color:#fff;background-color:#025aa5;background-image:none;border-color:#01549b}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.btn-primary.dropdown-toggle.focus,.open>.btn-primary.dropdown-toggle:focus,.open>.btn-primary.dropdown-toggle:hover{color:#fff;background-color:#014682;border-color:#01315a}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary:disabled.focus,.btn-primary:disabled:focus{background-color:#0275d8;border-color:#0275d8}.btn-primary.disabled:hover,.btn-primary:disabled:hover{background-color:#0275d8;border-color:#0275d8}.btn-secondary{color:#373a3c;background-color:#fff;border-color:#ccc}.btn-secondary:hover{color:#373a3c;background-color:#e6e6e6;border-color:#adadad}.btn-secondary.focus,.btn-secondary:focus{color:#373a3c;background-color:#e6e6e6;border-color:#adadad}.btn-secondary.active,.btn-secondary:active,.open>.btn-secondary.dropdown-toggle{color:#373a3c;background-color:#e6e6e6;background-image:none;border-color:#adadad}.btn-secondary.active.focus,.btn-secondary.active:focus,.btn-secondary.active:hover,.btn-secondary:active.focus,.btn-secondary:active:focus,.btn-secondary:active:hover,.open>.btn-secondary.dropdown-toggle.focus,.open>.btn-secondary.dropdown-toggle:focus,.open>.btn-secondary.dropdown-toggle:hover{color:#373a3c;background-color:#d4d4d4;border-color:#8c8c8c}.btn-secondary.disabled.focus,.btn-secondary.disabled:focus,.btn-secondary:disabled.focus,.btn-secondary:disabled:focus{background-color:#fff;border-color:#ccc}.btn-secondary.disabled:hover,.btn-secondary:disabled:hover{background-color:#fff;border-color:#ccc}.btn-info{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#2aabd2}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#2aabd2}.btn-info.active,.btn-info:active,.open>.btn-info.dropdown-toggle{color:#fff;background-color:#31b0d5;background-image:none;border-color:#2aabd2}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.btn-info.dropdown-toggle.focus,.open>.btn-info.dropdown-toggle:focus,.open>.btn-info.dropdown-toggle:hover{color:#fff;background-color:#269abc;border-color:#1f7e9a}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info:disabled.focus,.btn-info:disabled:focus{background-color:#5bc0de;border-color:#5bc0de}.btn-info.disabled:hover,.btn-info:disabled:hover{background-color:#5bc0de;border-color:#5bc0de}.btn-success{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#419641}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#419641}.btn-success.active,.btn-success:active,.open>.btn-success.dropdown-toggle{color:#fff;background-color:#449d44;background-image:none;border-color:#419641}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.btn-success.dropdown-toggle.focus,.open>.btn-success.dropdown-toggle:focus,.open>.btn-success.dropdown-toggle:hover{color:#fff;background-color:#398439;border-color:#2d672d}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success:disabled.focus,.btn-success:disabled:focus{background-color:#5cb85c;border-color:#5cb85c}.btn-success.disabled:hover,.btn-success:disabled:hover{background-color:#5cb85c;border-color:#5cb85c}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#eb9316}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#eb9316}.btn-warning.active,.btn-warning:active,.open>.btn-warning.dropdown-toggle{color:#fff;background-color:#ec971f;background-image:none;border-color:#eb9316}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.btn-warning.dropdown-toggle.focus,.open>.btn-warning.dropdown-toggle:focus,.open>.btn-warning.dropdown-toggle:hover{color:#fff;background-color:#d58512;border-color:#b06d0f}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning:disabled.focus,.btn-warning:disabled:focus{background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning.disabled:hover,.btn-warning:disabled:hover{background-color:#f0ad4e;border-color:#f0ad4e}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#c12e2a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#c12e2a}.btn-danger.active,.btn-danger:active,.open>.btn-danger.dropdown-toggle{color:#fff;background-color:#c9302c;background-image:none;border-color:#c12e2a}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.btn-danger.dropdown-toggle.focus,.open>.btn-danger.dropdown-toggle:focus,.open>.btn-danger.dropdown-toggle:hover{color:#fff;background-color:#ac2925;border-color:#8b211e}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger:disabled.focus,.btn-danger:disabled:focus{background-color:#d9534f;border-color:#d9534f}.btn-danger.disabled:hover,.btn-danger:disabled:hover{background-color:#d9534f;border-color:#d9534f}.btn-primary-outline{color:#0275d8;background-color:transparent;background-image:none;border-color:#0275d8}.btn-primary-outline.active,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline:focus,.open>.btn-primary-outline.dropdown-toggle{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary-outline:hover{color:#fff;background-color:#0275d8;border-color:#0275d8}.btn-primary-outline.disabled.focus,.btn-primary-outline.disabled:focus,.btn-primary-outline:disabled.focus,.btn-primary-outline:disabled:focus{border-color:#43a7fd}.btn-primary-outline.disabled:hover,.btn-primary-outline:disabled:hover{border-color:#43a7fd}.btn-secondary-outline{color:#ccc;background-color:transparent;background-image:none;border-color:#ccc}.btn-secondary-outline.active,.btn-secondary-outline.focus,.btn-secondary-outline:active,.btn-secondary-outline:focus,.open>.btn-secondary-outline.dropdown-toggle{color:#fff;background-color:#ccc;border-color:#ccc}.btn-secondary-outline:hover{color:#fff;background-color:#ccc;border-color:#ccc}.btn-secondary-outline.disabled.focus,.btn-secondary-outline.disabled:focus,.btn-secondary-outline:disabled.focus,.btn-secondary-outline:disabled:focus{border-color:#fff}.btn-secondary-outline.disabled:hover,.btn-secondary-outline:disabled:hover{border-color:#fff}.btn-info-outline{color:#5bc0de;background-color:transparent;background-image:none;border-color:#5bc0de}.btn-info-outline.active,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline:focus,.open>.btn-info-outline.dropdown-toggle{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info-outline:hover{color:#fff;background-color:#5bc0de;border-color:#5bc0de}.btn-info-outline.disabled.focus,.btn-info-outline.disabled:focus,.btn-info-outline:disabled.focus,.btn-info-outline:disabled:focus{border-color:#b0e1ef}.btn-info-outline.disabled:hover,.btn-info-outline:disabled:hover{border-color:#b0e1ef}.btn-success-outline{color:#5cb85c;background-color:transparent;background-image:none;border-color:#5cb85c}.btn-success-outline.active,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline:focus,.open>.btn-success-outline.dropdown-toggle{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success-outline:hover{color:#fff;background-color:#5cb85c;border-color:#5cb85c}.btn-success-outline.disabled.focus,.btn-success-outline.disabled:focus,.btn-success-outline:disabled.focus,.btn-success-outline:disabled:focus{border-color:#a3d7a3}.btn-success-outline.disabled:hover,.btn-success-outline:disabled:hover{border-color:#a3d7a3}.btn-warning-outline{color:#f0ad4e;background-color:transparent;background-image:none;border-color:#f0ad4e}.btn-warning-outline.active,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline:focus,.open>.btn-warning-outline.dropdown-toggle{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning-outline:hover{color:#fff;background-color:#f0ad4e;border-color:#f0ad4e}.btn-warning-outline.disabled.focus,.btn-warning-outline.disabled:focus,.btn-warning-outline:disabled.focus,.btn-warning-outline:disabled:focus{border-color:#f8d9ac}.btn-warning-outline.disabled:hover,.btn-warning-outline:disabled:hover{border-color:#f8d9ac}.btn-danger-outline{color:#d9534f;background-color:transparent;background-image:none;border-color:#d9534f}.btn-danger-outline.active,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline:focus,.open>.btn-danger-outline.dropdown-toggle{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger-outline:hover{color:#fff;background-color:#d9534f;border-color:#d9534f}.btn-danger-outline.disabled.focus,.btn-danger-outline.disabled:focus,.btn-danger-outline:disabled.focus,.btn-danger-outline:disabled:focus{border-color:#eba5a3}.btn-danger-outline.disabled:hover,.btn-danger-outline:disabled:hover{border-color:#eba5a3}.btn-link{font-weight:400;color:#0275d8;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link:disabled{background-color:transparent}.btn-link,.btn-link:active,.btn-link:focus{border-color:transparent}.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#014c8c;text-decoration:underline;background-color:transparent}.btn-link:disabled:focus,.btn-link:disabled:hover{color:#818a91;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:.75rem 1.25rem;font-size:1.25rem;line-height:1.333333;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .75rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height;-o-transition-property:height;transition-property:height}.dropdown,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-right:.25rem;margin-left:.25rem;vertical-align:middle;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-left:.3em solid transparent}.dropdown-toggle:focus{outline:0}.dropup .dropdown-toggle::after{border-top:0;border-bottom:.3em solid}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:1rem;color:#373a3c;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-divider{height:1px;margin:.5rem 0;overflow:hidden;background-color:#e5e5e5}.dropdown-item{display:block;width:100%;padding:3px 20px;clear:both;font-weight:400;line-height:1.5;color:#373a3c;text-align:inherit;white-space:nowrap;background:0 0;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#2b2d2f;text-decoration:none;background-color:#f5f5f5}.dropdown-item.active,.dropdown-item.active:focus,.dropdown-item.active:hover{color:#fff;text-decoration:none;background-color:#0275d8;outline:0}.dropdown-item.disabled,.dropdown-item.disabled:focus,.dropdown-item.disabled:hover{color:#818a91}.dropdown-item.disabled:focus,.dropdown-item.disabled:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:"progid:DXImageTransform.Microsoft.gradient(enabled = false)"}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:.875rem;line-height:1.5;color:#818a91;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:.3em solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:2}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar::after{display:table;clear:both;content:""}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group-lg.btn-group>.btn+.dropdown-toggle,.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn .caret{margin-left:0}.btn-group-lg>.btn .caret,.btn-lg .caret{border-width:.3em .3em 0;border-bottom-width:0}.dropup .btn-group-lg>.btn .caret,.dropup .btn-lg .caret{border-width:0 .3em .3em}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group::after{display:table;clear:both;content:""}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:.25rem;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:.25rem}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:active,.input-group .form-control:focus,.input-group .form-control:hover{z-index:3}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1;color:#55595c;text-align:center;background-color:#eceeef;border:1px solid #ccc;border-radius:.25rem}.input-group-addon.form-control-sm,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:.275rem .75rem;font-size:.875rem;border-radius:.2rem}.input-group-addon.form-control-lg,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:.75rem 1.25rem;font-size:1.25rem;border-radius:.3rem}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:3}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.input-group-btn:last-child>.btn-group:active,.input-group-btn:last-child>.btn-group:focus,.input-group-btn:last-child>.btn-group:hover,.input-group-btn:last-child>.btn:active,.input-group-btn:last-child>.btn:focus,.input-group-btn:last-child>.btn:hover{z-index:3}.c-input{position:relative;display:inline;padding-left:1.5rem;color:#555;cursor:pointer}.c-input>input{position:absolute;z-index:-1;opacity:0}.c-input>input:checked~.c-indicator{color:#fff;background-color:#0074d9}.c-input>input:focus~.c-indicator{-webkit-box-shadow:0 0 0 .075rem #fff,0 0 0 .2rem #0074d9;box-shadow:0 0 0 .075rem #fff,0 0 0 .2rem #0074d9}.c-input>input:active~.c-indicator{color:#fff;background-color:#84c6ff}.c-input+.c-input{margin-left:1rem}.c-indicator{position:absolute;top:0;left:0;display:block;width:1rem;height:1rem;font-size:65%;line-height:1rem;color:#eee;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#eee;background-repeat:no-repeat;background-position:center center;-webkit-background-size:50% 50%;background-size:50% 50%}.c-checkbox .c-indicator{border-radius:.25rem}.c-checkbox input:checked~.c-indicator{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgOCA4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA4IDgiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iI0ZGRkZGRiIgZD0iTTYuNCwxTDUuNywxLjdMMi45LDQuNUwyLjEsMy43TDEuNCwzTDAsNC40bDAuNywwLjdsMS41LDEuNWwwLjcsMC43bDAuNy0wLjdsMy41LTMuNWwwLjctMC43TDYuNCwxTDYuNCwxeiINCgkvPg0KPC9zdmc+DQo=)}.c-checkbox input:indeterminate~.c-indicator{background-color:#0074d9;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iOHB4IiBoZWlnaHQ9IjhweCIgdmlld0JveD0iMCAwIDggOCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOCA4IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik0wLDN2Mmg4VjNIMHoiLz4NCjwvc3ZnPg0K)}.c-radio .c-indicator{border-radius:50%}.c-radio input:checked~.c-indicator{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNy4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgOCA4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA4IDgiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iI0ZGRkZGRiIgZD0iTTQsMUMyLjMsMSwxLDIuMywxLDRzMS4zLDMsMywzczMtMS4zLDMtM1M1LjcsMSw0LDF6Ii8+DQo8L3N2Zz4NCg==)}.c-inputs-stacked .c-input{display:inline}.c-inputs-stacked .c-input::after{display:block;margin-bottom:.25rem;content:""}.c-inputs-stacked .c-input+.c-input{margin-left:0}.c-select{display:inline-block;max-width:100%;-webkit-appearance:none;padding:.375rem 1.75rem .375rem .75rem;padding-right:.75rem\9;color:#55595c;vertical-align:middle;background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAUCAMAAACzvE1FAAAADFBMVEUzMzMzMzMzMzMzMzMKAG/3AAAAA3RSTlMAf4C/aSLHAAAAPElEQVR42q3NMQ4AIAgEQTn//2cLdRKppSGzBYwzVXvznNWs8C58CiussPJj8h6NwgorrKRdTvuV9v16Afn0AYFOB7aYAAAAAElFTkSuQmCC) no-repeat right .75rem center;background-image:none\9;-webkit-background-size:8px 10px;background-size:8px 10px;border:1px solid #ccc;-moz-appearance:none}.c-select:focus{border-color:#51a7e8;outline:0}.c-select::-ms-expand{opacity:0}.c-select-sm{padding-top:3px;padding-bottom:3px;font-size:12px}.c-select-sm:not([multiple]){height:26px;min-height:26px}.file{position:relative;display:inline-block;height:2.5rem;cursor:pointer}.file input{min-width:14rem;margin:0;filter:alpha(opacity=0);opacity:0}.file-custom{position:absolute;top:0;right:0;left:0;z-index:5;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#555;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#fff;border:1px solid #ddd;border-radius:.25rem}.file-custom::after{content:"Choose file..."}.file-custom::before{position:absolute;top:-.075rem;right:-.075rem;bottom:-.075rem;z-index:6;display:block;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#555;content:"Browse";background-color:#eee;border:1px solid #ddd;border-radius:0 .25rem .25rem 0}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:inline-block}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#818a91}.nav-link.disabled,.nav-link.disabled:focus,.nav-link.disabled:hover{color:#818a91;cursor:not-allowed;background-color:transparent}.nav-inline .nav-item{display:inline-block}.nav-inline .nav-item+.nav-item,.nav-inline .nav-link+.nav-link{margin-left:1rem}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs::after{display:table;clear:both;content:""}.nav-tabs .nav-item{float:left;margin-bottom:-1px}.nav-tabs .nav-item+.nav-item{margin-left:.2rem}.nav-tabs .nav-link{display:block;padding:.5em 1em;border:1px solid transparent;border-radius:.25rem .25rem 0 0}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#eceeef #eceeef #ddd}.nav-tabs .nav-link.disabled,.nav-tabs .nav-link.disabled:focus,.nav-tabs .nav-link.disabled:hover{color:#818a91;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.open .nav-link,.nav-tabs .nav-item.open .nav-link:focus,.nav-tabs .nav-item.open .nav-link:hover,.nav-tabs .nav-link.active,.nav-tabs .nav-link.active:focus,.nav-tabs .nav-link.active:hover{color:#55595c;background-color:#fff;border-color:#ddd #ddd transparent}.nav-pills::after{display:table;clear:both;content:""}.nav-pills .nav-item{float:left}.nav-pills .nav-item+.nav-item{margin-left:.2rem}.nav-pills .nav-link{display:block;padding:.5em 1em;border-radius:.25rem}.nav-pills .nav-item.open .nav-link,.nav-pills .nav-item.open .nav-link:focus,.nav-pills .nav-item.open .nav-link:hover,.nav-pills .nav-link.active,.nav-pills .nav-link.active:focus,.nav-pills .nav-link.active:hover{color:#fff;cursor:default;background-color:#0275d8}.nav-stacked .nav-item{display:block;float:none}.nav-stacked .nav-item+.nav-item{margin-top:.2rem;margin-left:0}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;padding:.5rem 1rem}.navbar::after{display:table;clear:both;content:""}@media (min-width:544px){.navbar{border-radius:.25rem}}.navbar-full{z-index:1000}@media (min-width:544px){.navbar-full{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:544px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0}.navbar-fixed-bottom{bottom:0}.navbar-sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1030;width:100%}@media (min-width:544px){.navbar-sticky-top{border-radius:0}}.navbar-brand{float:left;padding-top:.25rem;padding-bottom:.25rem;margin-right:1rem;font-size:1.25rem}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}.navbar-divider{float:left;width:1px;padding-top:.425rem;padding-bottom:.425rem;margin-right:1rem;margin-left:1rem;overflow:hidden}.navbar-divider::before{content:"\00a0"}.navbar-toggler{padding:.5rem .75rem;font-size:1.25rem;line-height:1;background:0 0;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}@media (min-width:544px){.navbar-toggleable-xs{display:block!important}}@media (min-width:768px){.navbar-toggleable-sm{display:block!important}}@media (min-width:992px){.navbar-toggleable-md{display:block!important}}.navbar-nav .nav-item{float:left}.navbar-nav .nav-link{display:block;padding-top:.425rem;padding-bottom:.425rem}.navbar-nav .nav-link+.nav-link{margin-left:1rem}.navbar-nav .nav-item+.nav-item{margin-left:1rem}.navbar-light .navbar-brand{color:rgba(0,0,0,.8)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.8)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.6)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .active>.nav-link:focus,.navbar-light .navbar-nav .active>.nav-link:hover,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.active:focus,.navbar-light .navbar-nav .nav-link.active:hover,.navbar-light .navbar-nav .nav-link.open,.navbar-light .navbar-nav .nav-link.open:focus,.navbar-light .navbar-nav .nav-link.open:hover,.navbar-light .navbar-nav .open>.nav-link,.navbar-light .navbar-nav .open>.nav-link:focus,.navbar-light .navbar-nav .open>.nav-link:hover{color:rgba(0,0,0,.8)}.navbar-light .navbar-divider{background-color:rgba(0,0,0,.075)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .active>.nav-link:focus,.navbar-dark .navbar-nav .active>.nav-link:hover,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.active:focus,.navbar-dark .navbar-nav .nav-link.active:hover,.navbar-dark .navbar-nav .nav-link.open,.navbar-dark .navbar-nav .nav-link.open:focus,.navbar-dark .navbar-nav .nav-link.open:hover,.navbar-dark .navbar-nav .open>.nav-link,.navbar-dark .navbar-nav .open>.nav-link:focus,.navbar-dark .navbar-nav .open>.nav-link:hover{color:#fff}.navbar-dark .navbar-divider{background-color:rgba(255,255,255,.075)}.card{position:relative;display:block;margin-bottom:.75rem;background-color:#fff;border:1px solid #e5e5e5;border-radius:.25rem}.card-block{padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card>.list-group:first-child .list-group-item:first-child{border-radius:.25rem .25rem 0 0}.card>.list-group:last-child .list-group-item:last-child{border-radius:0 0 .25rem .25rem}.card-header{padding:.75rem 1.25rem;background-color:#f5f5f5;border-bottom:1px solid #e5e5e5}.card-header:first-child{border-radius:.25rem .25rem 0 0}.card-footer{padding:.75rem 1.25rem;background-color:#f5f5f5;border-top:1px solid #e5e5e5}.card-footer:last-child{border-radius:0 0 .25rem .25rem}.card-primary{background-color:#0275d8;border-color:#0275d8}.card-success{background-color:#5cb85c;border-color:#5cb85c}.card-info{background-color:#5bc0de;border-color:#5bc0de}.card-warning{background-color:#f0ad4e;border-color:#f0ad4e}.card-danger{background-color:#d9534f;border-color:#d9534f}.card-primary-outline{background-color:transparent;border-color:#0275d8}.card-secondary-outline{background-color:transparent;border-color:#ccc}.card-info-outline{background-color:transparent;border-color:#5bc0de}.card-success-outline{background-color:transparent;border-color:#5cb85c}.card-warning-outline{background-color:transparent;border-color:#f0ad4e}.card-danger-outline{background-color:transparent;border-color:#d9534f}.card-inverse .card-footer,.card-inverse .card-header{border-bottom:1px solid rgba(255,255,255,.2)}.card-inverse .card-blockquote,.card-inverse .card-footer,.card-inverse .card-header,.card-inverse .card-title{color:#fff}.card-inverse .card-blockquote>footer,.card-inverse .card-link,.card-inverse .card-text{color:rgba(255,255,255,.65)}.card-inverse .card-link:focus,.card-inverse .card-link:hover{color:#fff}.card-blockquote{padding:0;margin-bottom:0;border-left:0}.card-img{border-radius:.25rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img-top{border-radius:.25rem .25rem 0 0}.card-img-bottom{border-radius:0 0 .25rem .25rem}@media (min-width:544px){.card-deck{display:table;table-layout:fixed;border-spacing:1.25rem 0}.card-deck .card{display:table-cell;width:1%;vertical-align:top}.card-deck-wrapper{margin-right:-1.25rem;margin-left:-1.25rem}}@media (min-width:544px){.card-group{display:table;width:100%;table-layout:fixed}.card-group .card{display:table-cell;vertical-align:top}.card-group .card+.card{margin-left:0;border-left:0}.card-group .card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group .card:first-child .card-img-top{border-top-right-radius:0}.card-group .card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group .card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group .card:last-child .card-img-top{border-top-left-radius:0}.card-group .card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group .card:not(:first-child):not(:last-child){border-radius:0}.card-group .card:not(:first-child):not(:last-child) .card-img-bottom,.card-group .card:not(:first-child):not(:last-child) .card-img-top{border-radius:0}}@media (min-width:544px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#eceeef;border-radius:.25rem}.breadcrumb::after{display:table;clear:both;content:""}.breadcrumb>li{float:left}.breadcrumb>li+li::before{padding-right:.5rem;padding-left:.5rem;color:#818a91;content:"/"}.breadcrumb>.active{color:#818a91}.pagination{display:inline-block;padding-left:0;margin-top:1rem;margin-bottom:1rem;border-radius:.25rem}.page-item{display:inline}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link,.page-item.active .page-link:focus,.page-item.active .page-link:hover{z-index:2;color:#fff;cursor:default;background-color:#0275d8;border-color:#0275d8}.page-item.disabled .page-link,.page-item.disabled .page-link:focus,.page-item.disabled .page-link:hover{color:#818a91;cursor:not-allowed;background-color:#fff;border-color:#ddd}.page-link{position:relative;float:left;padding:.5rem .75rem;margin-left:-1px;line-height:1.5;color:#0275d8;text-decoration:none;background-color:#fff;border:1px solid #ddd}.page-link:focus,.page-link:hover{color:#014c8c;background-color:#eceeef;border-color:#ddd}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.333333}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.275rem .75rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.pager{padding-left:0;margin-top:1rem;margin-bottom:1rem;text-align:center;list-style:none}.pager::after{display:table;clear:both;content:""}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eceeef}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover{color:#818a91;cursor:not-allowed;background-color:#fff}.pager .disabled>span{color:#818a91;cursor:not-allowed;background-color:#fff}.pager-next>a,.pager-next>span{float:right}.pager-prev>a,.pager-prev>span{float:left}.label{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.label:empty{display:none}.btn .label{position:relative;top:-1px}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.label-default{background-color:#818a91}.label-default[href]:focus,.label-default[href]:hover{background-color:#687077}.label-primary{background-color:#0275d8}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#025aa5}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#eceeef;border-radius:.3rem}@media (min-width:544px){.jumbotron{padding:4rem 2rem}}.jumbotron-hr{border-top-color:#d0d5d8}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{padding:15px;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:35px}.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d0e9c6}.alert-success hr{border-top-color:#c1e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bcdff1}.alert-info hr{border-top-color:#a6d5ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faf2cc}.alert-warning hr{border-top-color:#f7ecb5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebcccc}.alert-danger hr{border-top-color:#e4b9b9}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:block;width:100%;height:1rem;margin-bottom:1rem}.progress[value]{-webkit-appearance:none;color:#0074d9;border:0;-moz-appearance:none;appearance:none}.progress[value]::-webkit-progress-bar{background-color:#eee;border-radius:.25rem}.progress[value]::-webkit-progress-value::before{content:attr(value)}.progress[value]::-webkit-progress-value{background-color:#0074d9;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.progress[value="100"]::-webkit-progress-value{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}@media screen and (min-width:0\0){.progress{background-color:#eee;border-radius:.25rem}.progress-bar{display:inline-block;height:1rem;text-indent:-999rem;background-color:#0074d9;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.progress[width^="0"]{min-width:2rem;color:#818a91;background-color:transparent;background-image:none}.progress[width="100%"]{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}}.progress-striped[value]::-webkit-progress-value{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:1rem 1rem;background-size:1rem 1rem}.progress-striped[value]::-moz-progress-bar{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}@media screen and (min-width:0\0){.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:1rem 1rem;background-size:1rem 1rem}}.progress-animated[value]::-webkit-progress-value{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-animated[value]::-moz-progress-bar{animation:progress-bar-stripes 2s linear infinite}@media screen and (min-width:0\0){.progress-animated .progress-bar-striped{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}}.progress-success[value]::-webkit-progress-value{background-color:#5cb85c}.progress-success[value]::-moz-progress-bar{background-color:#5cb85c}@media screen and (min-width:0\0){.progress-success .progress-bar{background-color:#5cb85c}}.progress-info[value]::-webkit-progress-value{background-color:#5bc0de}.progress-info[value]::-moz-progress-bar{background-color:#5bc0de}@media screen and (min-width:0\0){.progress-info .progress-bar{background-color:#5bc0de}}.progress-warning[value]::-webkit-progress-value{background-color:#f0ad4e}.progress-warning[value]::-moz-progress-bar{background-color:#f0ad4e}@media screen and (min-width:0\0){.progress-warning .progress-bar{background-color:#f0ad4e}}.progress-danger[value]::-webkit-progress-value{background-color:#d9534f}.progress-danger[value]::-moz-progress-bar{background-color:#d9534f}@media screen and (min-width:0\0){.progress-danger .progress-bar{background-color:#d9534f}}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right{padding-left:10px}.media-left{padding-right:10px}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:0}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-flush .list-group-item{border-width:1px 0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}a.list-group-item,button.list-group-item{width:100%;color:#555;text-align:inherit}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#818a91;cursor:not-allowed;background-color:#eceeef}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#818a91}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#0275d8;border-color:#0275d8}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#a8d6fe}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9{padding-bottom:42.857143%}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.embed-responsive-1by1{padding-bottom:100%}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:transform .3s ease-out,-o-transform .3s ease-out;transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out,-o-transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.in{opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header::after{display:table;clear:both;content:""}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.5}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer::after{display:table;clear:both;content:""}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:544px){.modal-dialog{width:600px;margin:30px auto}.modal-sm{width:300px}}@media (min-width:768px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:.875rem;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;opacity:0;line-break:auto}.tooltip.in{opacity:.9}.tooltip.bs-tether-element-attached-bottom,.tooltip.tooltip-top{padding:5px 0;margin-top:-3px}.tooltip.bs-tether-element-attached-bottom .tooltip-arrow,.tooltip.tooltip-top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.bs-tether-element-attached-left,.tooltip.tooltip-right{padding:0 5px;margin-left:3px}.tooltip.bs-tether-element-attached-left .tooltip-arrow,.tooltip.tooltip-right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.bs-tether-element-attached-top,.tooltip.tooltip-bottom{padding:5px 0;margin-top:3px}.tooltip.bs-tether-element-attached-top .tooltip-arrow,.tooltip.tooltip-bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bs-tether-element-attached-right,.tooltip.tooltip-left{padding:0 5px;margin-left:-3px}.tooltip.bs-tether-element-attached-right .tooltip-arrow,.tooltip.tooltip-left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:.875rem;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;line-break:auto}.popover.bs-tether-element-attached-bottom,.popover.popover-top{margin-top:-10px}.popover.bs-tether-element-attached-bottom .popover-arrow,.popover.popover-top .popover-arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.bs-tether-element-attached-bottom .popover-arrow::after,.popover.popover-top .popover-arrow::after{bottom:1px;margin-left:-10px;content:"";border-top-color:#fff;border-bottom-width:0}.popover.bs-tether-element-attached-left,.popover.popover-right{margin-left:10px}.popover.bs-tether-element-attached-left .popover-arrow,.popover.popover-right .popover-arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.bs-tether-element-attached-left .popover-arrow::after,.popover.popover-right .popover-arrow::after{bottom:-10px;left:1px;content:"";border-right-color:#fff;border-left-width:0}.popover.bs-tether-element-attached-top,.popover.popover-bottom{margin-top:10px}.popover.bs-tether-element-attached-top .popover-arrow,.popover.popover-bottom .popover-arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-top .popover-arrow::after,.popover.popover-bottom .popover-arrow::after{top:1px;margin-left:-10px;content:"";border-top-width:0;border-bottom-color:#fff}.popover.bs-tether-element-attached-right,.popover.popover-left{margin-left:-10px}.popover.bs-tether-element-attached-right .popover-arrow,.popover.popover-left .popover-arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-right .popover-arrow::after,.popover.popover-left .popover-arrow::after{right:1px;bottom:-10px;content:"";border-right-width:0;border-left-color:#fff}.popover-title{padding:8px 14px;margin:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:-.7rem -.7rem 0 0}.popover-content{padding:9px 14px}.popover-arrow,.popover-arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover-arrow{border-width:11px}.popover-arrow::after{content:"";border-width:10px}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.carousel-item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.carousel-item>a>img,.carousel-inner>.carousel-item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.carousel-item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:transform .6s ease-in-out,-o-transform .6s ease-in-out;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out,-o-transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.carousel-item.active.right,.carousel-inner>.carousel-item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.carousel-item.active.left,.carousel-inner>.carousel-item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.carousel-item.active,.carousel-inner>.carousel-item.next.left,.carousel-inner>.carousel-item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);opacity:.5}.carousel-control.left{background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-prev::before{content:"\2039"}.carousel-control .icon-next::before{content:"\203a"}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:transparent;border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media (min-width:544px){.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .icon-prev{margin-left:-15px}.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix::after{display:table;clear:both;content:""}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-xs-left{float:left!important}.pull-xs-right{float:right!important}.pull-xs-none{float:none!important}@media (min-width:544px){.pull-sm-left{float:left!important}.pull-sm-right{float:right!important}.pull-sm-none{float:none!important}}@media (min-width:768px){.pull-md-left{float:left!important}.pull-md-right{float:right!important}.pull-md-none{float:none!important}}@media (min-width:992px){.pull-lg-left{float:left!important}.pull-lg-right{float:right!important}.pull-lg-none{float:none!important}}@media (min-width:1200px){.pull-xl-left{float:left!important}.pull-xl-right{float:right!important}.pull-xl-none{float:none!important}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.invisible{visibility:hidden!important}.text-hide{font:"0/0" a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-xs-left{text-align:left!important}.text-xs-right{text-align:right!important}.text-xs-center{text-align:center!important}@media (min-width:544px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-normal{font-weight:400}.font-weight-bold{font-weight:700}.font-italic{font-style:italic}.text-muted{color:#818a91}.text-primary{color:#0275d8!important}a.text-primary:focus,a.text-primary:hover{color:#025aa5}.text-success{color:#5cb85c!important}a.text-success:focus,a.text-success:hover{color:#449d44}.text-info{color:#5bc0de!important}a.text-info:focus,a.text-info:hover{color:#31b0d5}.text-warning{color:#f0ad4e!important}a.text-warning:focus,a.text-warning:hover{color:#ec971f}.text-danger{color:#d9534f!important}a.text-danger:focus,a.text-danger:hover{color:#c9302c}.bg-inverse{color:#eceeef;background-color:#373a3c}.bg-faded{background-color:#f7f7f9}.bg-primary{color:#fff!important;background-color:#0275d8!important}a.bg-primary:focus,a.bg-primary:hover{background-color:#025aa5}.bg-success{color:#fff!important;background-color:#5cb85c!important}a.bg-success:focus,a.bg-success:hover{background-color:#449d44}.bg-info{color:#fff!important;background-color:#5bc0de!important}a.bg-info:focus,a.bg-info:hover{background-color:#31b0d5}.bg-warning{color:#fff!important;background-color:#f0ad4e!important}a.bg-warning:focus,a.bg-warning:hover{background-color:#ec971f}.bg-danger{color:#fff!important;background-color:#d9534f!important}a.bg-danger:focus,a.bg-danger:hover{background-color:#c9302c}.m-x-auto{margin-right:auto!important;margin-left:auto!important}.m-a-0{margin:0 0!important}.m-t-0{margin-top:0!important}.m-r-0{margin-right:0!important}.m-b-0{margin-bottom:0!important}.m-l-0{margin-left:0!important}.m-x-0{margin-right:0!important;margin-left:0!important}.m-y-0{margin-top:0!important;margin-bottom:0!important}.m-a-1{margin:1rem 1rem!important}.m-t-1{margin-top:1rem!important}.m-r-1{margin-right:1rem!important}.m-b-1{margin-bottom:1rem!important}.m-l-1{margin-left:1rem!important}.m-x-1{margin-right:1rem!important;margin-left:1rem!important}.m-y-1{margin-top:1rem!important;margin-bottom:1rem!important}.m-a-2{margin:1.5rem 1.5rem!important}.m-t-2{margin-top:1.5rem!important}.m-r-2{margin-right:1.5rem!important}.m-b-2{margin-bottom:1.5rem!important}.m-l-2{margin-left:1.5rem!important}.m-x-2{margin-right:1.5rem!important;margin-left:1.5rem!important}.m-y-2{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-a-3{margin:3rem 3rem!important}.m-t-3{margin-top:3rem!important}.m-r-3{margin-right:3rem!important}.m-b-3{margin-bottom:3rem!important}.m-l-3{margin-left:3rem!important}.m-x-3{margin-right:3rem!important;margin-left:3rem!important}.m-y-3{margin-top:3rem!important;margin-bottom:3rem!important}.p-a-0{padding:0 0!important}.p-t-0{padding-top:0!important}.p-r-0{padding-right:0!important}.p-b-0{padding-bottom:0!important}.p-l-0{padding-left:0!important}.p-x-0{padding-right:0!important;padding-left:0!important}.p-y-0{padding-top:0!important;padding-bottom:0!important}.p-a-1{padding:1rem 1rem!important}.p-t-1{padding-top:1rem!important}.p-r-1{padding-right:1rem!important}.p-b-1{padding-bottom:1rem!important}.p-l-1{padding-left:1rem!important}.p-x-1{padding-right:1rem!important;padding-left:1rem!important}.p-y-1{padding-top:1rem!important;padding-bottom:1rem!important}.p-a-2{padding:1.5rem 1.5rem!important}.p-t-2{padding-top:1.5rem!important}.p-r-2{padding-right:1.5rem!important}.p-b-2{padding-bottom:1.5rem!important}.p-l-2{padding-left:1.5rem!important}.p-x-2{padding-right:1.5rem!important;padding-left:1.5rem!important}.p-y-2{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-a-3{padding:3rem 3rem!important}.p-t-3{padding-top:3rem!important}.p-r-3{padding-right:3rem!important}.p-b-3{padding-bottom:3rem!important}.p-l-3{padding-left:3rem!important}.p-x-3{padding-right:3rem!important;padding-left:3rem!important}.p-y-3{padding-top:3rem!important;padding-bottom:3rem!important}.pos-f-t{position:fixed;top:0;right:0;left:0;z-index:1030}.hidden-xs-up{display:none!important}@media (max-width:543px){.hidden-xs-down{display:none!important}}@media (min-width:544px){.hidden-sm-up{display:none!important}}@media (max-width:767px){.hidden-sm-down{display:none!important}}@media (min-width:768px){.hidden-md-up{display:none!important}}@media (max-width:991px){.hidden-md-down{display:none!important}}@media (min-width:992px){.hidden-lg-up{display:none!important}}@media (max-width:1199px){.hidden-lg-down{display:none!important}}@media (min-width:1200px){.hidden-xl-up{display:none!important}}.hidden-xl-down{display:none!important}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} 6 | /*# sourceMappingURL=bootstrap.min.css.map */ --------------------------------------------------------------------------------