From 21797f39018e5ccfa6cfdb5cc17d2c466d9c28e6 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Sat, 14 Mar 2020 17:32:52 -0400 Subject: [PATCH 01/38] Added preliminary localization support to almost all strings in the program --- package.json | 1 + src/app/app.component.html | 8 +- .../create-playlist.component.html | 7 +- .../subscribe-dialog.component.html | 16 +-- .../subscription-info-dialog.component.html | 14 +- .../download-item.component.html | 2 +- src/app/file-card/file-card.component.html | 4 +- .../input-dialog/input-dialog.component.html | 1 + src/app/main/main.component.html | 122 +++++++++++++----- src/app/player/player.component.html | 2 +- src/app/settings/settings.component.html | 98 +++++++------- .../subscription-file-card.component.html | 6 +- .../subscription/subscription.component.html | 4 +- .../subscriptions.component.html | 20 +-- src/polyfills.ts | 4 + 15 files changed, 189 insertions(+), 120 deletions(-) diff --git a/package.json b/package.json index 73966f1..2801163 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@angular/core": "^8.2.11", "@angular/forms": "^8.2.11", "@angular/http": "^7.2.15", + "@angular/localize": "^9.0.6", "@angular/material": "^8.2.3", "@angular/platform-browser": "^8.2.11", "@angular/platform-browser-dynamic": "^8.2.11", diff --git a/src/app/app.component.html b/src/app/app.component.html index fb2927b..9403aeb 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -14,12 +14,12 @@ @@ -30,8 +30,8 @@ - Home - Subscriptions + Home + Subscriptions diff --git a/src/app/create-playlist/create-playlist.component.html b/src/app/create-playlist/create-playlist.component.html index 5447200..c361625 100644 --- a/src/app/create-playlist/create-playlist.component.html +++ b/src/app/create-playlist/create-playlist.component.html @@ -1,13 +1,14 @@ -

Create a playlist

+

Create a playlist

- +
- {{(type === 'audio') ? 'Audio files' : 'Videos'}} + Audio files + Videos {{file.id}} diff --git a/src/app/dialogs/subscribe-dialog/subscribe-dialog.component.html b/src/app/dialogs/subscribe-dialog/subscribe-dialog.component.html index 7e8d004..10f81b7 100644 --- a/src/app/dialogs/subscribe-dialog/subscribe-dialog.component.html +++ b/src/app/dialogs/subscribe-dialog/subscribe-dialog.component.html @@ -1,25 +1,25 @@ -

Subscribe to playlist or channel

+

Subscribe to playlist or channel

- - The playlist or channel URL + + The playlist or channel URL
- - This is optional + + This is optional
- Download all uploads + Download all uploads
- Download videos uploaded in the last + Download videos uploaded in the last @@ -34,7 +34,7 @@ - +
diff --git a/src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.html b/src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.html index eec94eb..1ebff5a 100644 --- a/src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.html +++ b/src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.html @@ -2,26 +2,26 @@
- Type: + Type:  {{(sub.isPlaylist ? 'Playlist' : 'Channel')}}
- URL: + URL:  {{sub.url}}
- ID: + ID:  {{sub.id}}
- Archive: + Archive:  {{sub.archive}}
- - + + - + \ No newline at end of file diff --git a/src/app/download-item/download-item.component.html b/src/app/download-item/download-item.component.html index 3ca4144..5c5a02f 100644 --- a/src/app/download-item/download-item.component.html +++ b/src/app/download-item/download-item.component.html @@ -4,7 +4,7 @@
{{queueNumber}}.
-
ID: {{url_id}}
+
ID: {{url_id}}
diff --git a/src/app/file-card/file-card.component.html b/src/app/file-card/file-card.component.html index 5dc8773..39184ce 100644 --- a/src/app/file-card/file-card.component.html +++ b/src/app/file-card/file-card.component.html @@ -3,8 +3,8 @@
{{title}}
- ID: {{name}} -
Count: {{count}}
+ ID: {{name}} +
Count: {{count}}
Thumbnail diff --git a/src/app/input-dialog/input-dialog.component.html b/src/app/input-dialog/input-dialog.component.html index a636cf6..09acfb5 100644 --- a/src/app/input-dialog/input-dialog.component.html +++ b/src/app/input-dialog/input-dialog.component.html @@ -7,6 +7,7 @@
+ diff --git a/src/app/main/main.component.html b/src/app/main/main.component.html index 4c6807a..110b1d0 100644 --- a/src/app/main/main.component.html +++ b/src/app/main/main.component.html @@ -2,7 +2,7 @@
- Youtube Downloader + Youtube Downloader
@@ -12,13 +12,19 @@
- Please enter a valid URL! + + Please enter a valid URL! +
- Quality + + + Quality + + @@ -42,22 +48,43 @@
{{result.uploaded}}
- - + +

- Only Audio - Multi-download mode + + + Only Audio + + + + + Multi-download Mode + +
- - + +
@@ -66,35 +93,60 @@ - Advanced + + Advanced + -

Simulated command: {{this.simulatedOutput}}

+

+ + Simulated command: + +  {{this.simulatedOutput}}

- Use custom args + + + Use custom args + + - - No need to include URL, just everything after. + + + + No need to include URL, just everything after. + +
- Use custom output + + + Use custom output + + - - Documentation. Path is relative to the config download path. Don't include extension. + + + Documentation. + Path is relative to the config download path. Don't include extension. +
- Use authentication + + + Use authentication + + - +
- +
@@ -138,10 +190,14 @@ - Audio + + Audio + - Your audio files are here + + Your audio files are here +
@@ -154,7 +210,7 @@
-
Playlists
+
Playlists
@@ -165,7 +221,9 @@
- No playlists available. Create one from your downloading audio files by clicking the blue plus button. + + No playlists available. Create one from your downloading audio files by clicking the blue plus button. +
@@ -173,10 +231,14 @@ - Video + + Video + - Your video files are here + + Your video files are here +
@@ -190,7 +252,7 @@
-
Playlists
+
Playlists
@@ -203,7 +265,9 @@
- No playlists available. Create one from your downloading video files by clicking the blue plus button. + + No playlists available. Create one from your downloading video files by clicking the blue plus button. +
diff --git a/src/app/player/player.component.html b/src/app/player/player.component.html index f424988..10b9f56 100644 --- a/src/app/player/player.component.html +++ b/src/app/player/player.component.html @@ -19,7 +19,7 @@
- +
diff --git a/src/app/settings/settings.component.html b/src/app/settings/settings.component.html index 6594c44..ec76f1c 100644 --- a/src/app/settings/settings.component.html +++ b/src/app/settings/settings.component.html @@ -1,25 +1,25 @@ -

Settings

- +

Settings

+ - Host + Host
- - Base URL this app will be accessed from, without the port. + + URL this app will be accessed from, without the port.
- - The desired port. Default is 17442. + + The desired port. Default is 17442.
@@ -31,24 +31,24 @@ - Encryption + Encryption
- Use encryption + Use encryption
- +
- +
@@ -59,29 +59,29 @@ - Downloader + Downloader
- - Path for audio only downloads. It is relative to YTDL-Material's root folder. + + Path for audio only downloads. It is relative to YTDL-Material's root folder.
- - Path for video downloads. It is relative to YTDL-Material's root folder. + + Path for video downloads. It is relative to YTDL-Material's root folder.
- - Global custom args for downloads on the home page. + + Global custom args for downloads on the home page.
@@ -92,28 +92,28 @@ - Extra + Extra
- +
- File manager enabled + File manager enabled
- Allow quality select + Allow quality select
- Download only mode + Download only mode
- Allow multi-download mode + Allow multi-download mode
@@ -123,18 +123,18 @@ - API + API
- Use YouTube API + Use YouTube API
@@ -145,20 +145,20 @@ - Themes + Themes
- Default - Dark + Default + Dark
- Allow theme change + Allow theme change
@@ -168,30 +168,30 @@ - Subscriptions + Subscriptions
- Allow subscriptions + Allow subscriptions
- - Base path for videos from your subscribed channels and playlists. It is relative to YTDL-Material's root folder. + + Base path for videos from your subscribed channels and playlists. It is relative to YTDL-Material's root folder.
- - Unit is seconds, only include numbers. + + Unit is seconds, only include numbers.
- Use youtube-dl archive -

With youtube-dl's archive feature, downloaded videos from your subscriptions get recorded in a text file in the subscriptions archive sub-directory.

-

This enables the ability to permanently delete videos from your subscriptions without unsubscribing, and allows you to record which videos you downloaded in case of data loss.

+ Use youtube-dl archive +

With youtube-dl's archive feature, downloaded videos from your subscriptions get recorded in a text file in the subscriptions archive sub-directory.

+

This enables the ability to permanently delete videos from your subscriptions without unsubscribing, and allows you to record which videos you downloaded in case of data loss.

@@ -201,22 +201,22 @@ - Advanced + Advanced
- Use default downloading agent + Use default downloading agent
- +
- Allow advanced download + Allow advanced download
@@ -225,7 +225,11 @@
- - + +
\ No newline at end of file diff --git a/src/app/subscription/subscription-file-card/subscription-file-card.component.html b/src/app/subscription/subscription-file-card/subscription-file-card.component.html index 32ab2c7..4537dd6 100644 --- a/src/app/subscription/subscription-file-card/subscription-file-card.component.html +++ b/src/app/subscription/subscription-file-card/subscription-file-card.component.html @@ -1,11 +1,11 @@
- Length: {{formattedDuration}} + Length: {{formattedDuration}}
- - + +
diff --git a/src/app/subscription/subscription/subscription.component.html b/src/app/subscription/subscription/subscription.component.html index bb4c5d5..d94a0a4 100644 --- a/src/app/subscription/subscription/subscription.component.html +++ b/src/app/subscription/subscription/subscription.component.html @@ -12,11 +12,11 @@
-

Videos

+

Videos

- + search
diff --git a/src/app/subscriptions/subscriptions.component.html b/src/app/subscriptions/subscriptions.component.html index 80572fd..5bf76bb 100644 --- a/src/app/subscriptions/subscriptions.component.html +++ b/src/app/subscriptions/subscriptions.component.html @@ -1,20 +1,17 @@
-

Your subscriptions

+

Your subscriptions


-

Channels

+

Channels

{{ sub.name }}
- Name not available. Channel retrieval in progress. - - - + Name not available. Channel retrieval in progress.
diff --git a/src/assets/default.json b/src/assets/default.json index 94aad55..7a41fcc 100644 --- a/src/assets/default.json +++ b/src/assets/default.json @@ -1,44 +1,45 @@ { - "YoutubeDLMaterial": { - "Host": { - "url": "http://localhost", - "port": "17442" - }, - "Encryption": { - "use-encryption": false, - "cert-file-path": "/etc/letsencrypt/live/example.com/fullchain.pem", - "key-file-path": "/etc/letsencrypt/live/example.com/privkey.pem" - }, - "Downloader": { - "path-audio": "audio/", - "path-video": "video/", - "custom_args": "" - }, - "Extra": { - "title_top": "Youtube Downloader", - "file_manager_enabled": true, - "allow_quality_select": true, - "download_only_mode": false, - "allow_multi_download_mode": true - }, - "API": { - "use_youtube_API": false, - "youtube_API_key": "" - }, - "Themes": { - "default_theme": "default", - "allow_theme_change": true - }, - "Subscriptions": { - "allow_subscriptions": true, - "subscriptions_base_path": "subscriptions/", - "subscriptions_check_interval": "300", - "subscriptions_use_youtubedl_archive": true - }, - "Advanced": { - "use_default_downloading_agent": true, - "custom_downloading_agent": "", - "allow_advanced_download": true - } + "YoutubeDLMaterial": { + "Host": { + "url": "http://localhost", + "port": "17442" + }, + "Encryption": { + "use-encryption": false, + "cert-file-path": "/etc/letsencrypt/live/example.com/fullchain.pem", + "key-file-path": "/etc/letsencrypt/live/example.com/privkey.pem" + }, + "Downloader": { + "path-audio": "audio/", + "path-video": "video/", + "use_youtubedl_archive": true, + "custom_args": "" + }, + "Extra": { + "title_top": "Youtube Downloader", + "file_manager_enabled": true, + "allow_quality_select": true, + "download_only_mode": false, + "allow_multi_download_mode": true + }, + "API": { + "use_youtube_API": false, + "youtube_API_key": "" + }, + "Themes": { + "default_theme": "default", + "allow_theme_change": true + }, + "Subscriptions": { + "allow_subscriptions": true, + "subscriptions_base_path": "subscriptions/", + "subscriptions_check_interval": "300", + "subscriptions_use_youtubedl_archive": true + }, + "Advanced": { + "use_default_downloading_agent": true, + "custom_downloading_agent": "", + "allow_advanced_download": true } } +} \ No newline at end of file From d39f6f7a177f58894214dc5e005d1b2bccbba154 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Sun, 15 Mar 2020 20:28:18 -0400 Subject: [PATCH 15/38] File cards modified to support blacklisting videos when using youtube-dl archive --- src/app/app.module.ts | 5 +---- src/app/file-card/file-card.component.html | 7 ++++++- src/app/file-card/file-card.component.ts | 5 +++-- src/app/main/main.component.html | 8 ++++---- src/app/main/main.component.ts | 6 ++++++ .../subscription-file-card.component.html | 2 +- 6 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 8be4234..e6b6152 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,7 +1,6 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule, LOCALE_ID } from '@angular/core'; import { registerLocaleData } from '@angular/common'; -import { LocaleService } from '@soluling/angular'; import { MatButtonModule } from '@angular/material/button'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatCardModule } from '@angular/material/card'; @@ -111,9 +110,7 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible AppRoutingModule, ], providers: [ - PostsService, - LocaleService, - { provide: LOCALE_ID, deps: [LocaleService], useFactory: (service: LocaleService) => service.localeId }, + PostsService ], bootstrap: [AppComponent] }) diff --git a/src/app/file-card/file-card.component.html b/src/app/file-card/file-card.component.html index 39184ce..1c796c5 100644 --- a/src/app/file-card/file-card.component.html +++ b/src/app/file-card/file-card.component.html @@ -15,5 +15,10 @@
- + + + + + + diff --git a/src/app/file-card/file-card.component.ts b/src/app/file-card/file-card.component.ts index 7e39fc7..770976e 100644 --- a/src/app/file-card/file-card.component.ts +++ b/src/app/file-card/file-card.component.ts @@ -21,6 +21,7 @@ export class FileCardComponent implements OnInit { @Output() removeFile: EventEmitter = new EventEmitter(); @Input() isPlaylist = false; @Input() count = null; + @Input() use_youtubedl_archive = false; type; image_loaded = false; image_errored = false; @@ -40,9 +41,9 @@ export class FileCardComponent implements OnInit { this.type = this.isAudio ? 'audio' : 'video'; } - deleteFile() { + deleteFile(blacklistMode = false) { if (!this.isPlaylist) { - this.postsService.deleteFile(this.name, this.isAudio).subscribe(result => { + this.postsService.deleteFile(this.name, this.isAudio, blacklistMode).subscribe(result => { if (result === true) { this.openSnackBar('Delete success!', 'OK.'); this.removeFile.emit(this.name); diff --git a/src/app/main/main.component.html b/src/app/main/main.component.html index 110b1d0..dc11d79 100644 --- a/src/app/main/main.component.html +++ b/src/app/main/main.component.html @@ -204,7 +204,7 @@ + [length]="file.duration" [isAudio]="true" [use_youtubedl_archive]="use_youtubedl_archive"> @@ -215,7 +215,7 @@ + [length]="null" [isAudio]="true" [isPlaylist]="true" [count]="playlist.fileNames.length" [use_youtubedl_archive]="use_youtubedl_archive"> @@ -245,7 +245,7 @@ + [length]="file.duration" [isAudio]="false" [use_youtubedl_archive]="use_youtubedl_archive"> @@ -257,7 +257,7 @@ + [length]="null" [isAudio]="false" [isPlaylist]="true" [count]="playlist.fileNames.length" [use_youtubedl_archive]="use_youtubedl_archive"> diff --git a/src/app/main/main.component.ts b/src/app/main/main.component.ts index ba36282..975da5e 100644 --- a/src/app/main/main.component.ts +++ b/src/app/main/main.component.ts @@ -72,6 +72,7 @@ export class MainComponent implements OnInit { allowMultiDownloadMode = false; audioFolderPath; videoFolderPath; + use_youtubedl_archive = false; globalCustomArgs = null; allowAdvancedDownload = false; useDefaultDownloadingAgent = true; @@ -241,6 +242,7 @@ export class MainComponent implements OnInit { this.allowMultiDownloadMode = result['YoutubeDLMaterial']['Extra']['allow_multi_download_mode']; this.audioFolderPath = result['YoutubeDLMaterial']['Downloader']['path-audio']; this.videoFolderPath = result['YoutubeDLMaterial']['Downloader']['path-video']; + this.use_youtubedl_archive = result['YoutubeDLMaterial']['Downloader']['use_youtubedl_archive']; this.globalCustomArgs = result['YoutubeDLMaterial']['Downloader']['custom_args']; this.youtubeSearchEnabled = result['YoutubeDLMaterial']['API'] && result['YoutubeDLMaterial']['API']['use_youtube_API'] && result['YoutubeDLMaterial']['API']['youtube_API_key']; @@ -594,6 +596,8 @@ export class MainComponent implements OnInit { } }, error => { // can't access server this.downloadingfile = false; + this.current_download = null; + new_download['downloading'] = false; this.openSnackBar('Download failed!', 'OK.'); }); } else { @@ -626,6 +630,8 @@ export class MainComponent implements OnInit { } }, error => { // can't access server this.downloadingfile = false; + this.current_download = null; + new_download['downloading'] = false; this.openSnackBar('Download failed!', 'OK.'); }); } diff --git a/src/app/subscription/subscription-file-card/subscription-file-card.component.html b/src/app/subscription/subscription-file-card/subscription-file-card.component.html index 4537dd6..a2972a9 100644 --- a/src/app/subscription/subscription-file-card/subscription-file-card.component.html +++ b/src/app/subscription/subscription-file-card/subscription-file-card.component.html @@ -3,7 +3,7 @@ Length: {{formattedDuration}}
- + From f1c09a5fa918e0f4dcb06df392bcd6785efa717b Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Sun, 15 Mar 2020 20:30:48 -0400 Subject: [PATCH 16/38] Added firefox extension zip to repo --- .../youtubedl-material-firefox-extension.zip | Bin 0 -> 4487 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 chrome-extension/youtubedl-material-firefox-extension.zip diff --git a/chrome-extension/youtubedl-material-firefox-extension.zip b/chrome-extension/youtubedl-material-firefox-extension.zip new file mode 100644 index 0000000000000000000000000000000000000000..54d612014896cbd2020c5353c08f04981dc8ca6e GIT binary patch literal 4487 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 literal 0 HcmV?d00001 From 84c9ec1300dfb056274de35cc7e54ce23f4c8a92 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Sun, 15 Mar 2020 20:31:04 -0400 Subject: [PATCH 17/38] Updated file card image appearance --- src/app/file-card/file-card.component.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/file-card/file-card.component.css b/src/app/file-card/file-card.component.css index f17823f..7376b16 100644 --- a/src/app/file-card/file-card.component.css +++ b/src/app/file-card/file-card.component.css @@ -17,8 +17,9 @@ } .image { - max-width:100%; - max-height:100%; + width: 100%; + height: 100%; + border-radius: 0px 0px 4px 4px; } .example-full-width-height { From 44bff55a88f472bd64d5a7cc8c1d2594ebeb2319 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Sun, 15 Mar 2020 20:35:51 -0400 Subject: [PATCH 18/38] Adds youtube dl args to simulated output --- src/app/main/main.component.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/main/main.component.ts b/src/app/main/main.component.ts index 975da5e..9c356ce 100644 --- a/src/app/main/main.component.ts +++ b/src/app/main/main.component.ts @@ -885,6 +885,10 @@ export class MainComponent implements OnInit { full_string_array.push(...additional_params); } + if (this.use_youtubedl_archive) { + full_string_array.push('--download-archive', 'archive.txt'); + } + if (globalArgsExists) { full_string_array = full_string_array.concat(this.globalCustomArgs.split(' ')); } From b765830584acd6cead9455cb9453dcf671b67555 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Sun, 15 Mar 2020 20:37:26 -0400 Subject: [PATCH 19/38] Using youtubedl archive for downloads defaults to false --- src/assets/default.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/default.json b/src/assets/default.json index 7a41fcc..6a7e5b8 100644 --- a/src/assets/default.json +++ b/src/assets/default.json @@ -12,7 +12,7 @@ "Downloader": { "path-audio": "audio/", "path-video": "video/", - "use_youtubedl_archive": true, + "use_youtubedl_archive": false, "custom_args": "" }, "Extra": { From da399601e105572ac3d123450dc05ff612472822 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Sun, 15 Mar 2020 20:59:21 -0400 Subject: [PATCH 20/38] Added ability to select any supported custom downloader --- backend/app.js | 18 +++++++++++++----- src/app/settings/settings.component.html | 18 ++++++++++++------ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/backend/app.js b/backend/app.js index b50dd99..0c08a84 100644 --- a/backend/app.js +++ b/backend/app.js @@ -58,7 +58,13 @@ let debugMode = process.env.YTDL_MODE === 'debug'; if (debugMode) console.log('YTDL-Material in debug mode!'); var validDownloadingAgents = [ - 'aria2c' + 'aria2c', + 'avconv', + 'axel', + 'curl', + 'ffmpeg', + 'httpie', + 'wget' ] // don't overwrite config if it already happened.. NOT @@ -143,6 +149,8 @@ async function loadConfig() { if (!useDefaultDownloadingAgent && validDownloadingAgents.indexOf(customDownloadingAgent) !== -1 ) { console.log(`INFO: Using non-default downloading agent \'${customDownloadingAgent}\'`) + } else { + customDownloadingAgent = null; } if (usingEncryption) @@ -659,8 +667,8 @@ app.post('/api/tomp3', async function(req, res) { downloadConfig.splice(3, 0, qualityPath); } - if (!useDefaultDownloadingAgent && customDownloadingAgent === 'aria2c') { - downloadConfig.splice(0, 0, '--external-downloader', 'aria2c'); + if (!useDefaultDownloadingAgent && customDownloadingAgent) { + downloadConfig.splice(0, 0, '--external-downloader', customDownloadingAgent); } if (useYoutubeDLArchive) { @@ -783,8 +791,8 @@ app.post('/api/tomp4', async function(req, res) { downloadConfig.push('--username', youtubeUsername, '--password', youtubePassword); } - if (!useDefaultDownloadingAgent && customDownloadingAgent === 'aria2c') { - downloadConfig.splice(0, 0, '--external-downloader', 'aria2c'); + if (!useDefaultDownloadingAgent && customDownloadingAgent) { + downloadConfig.splice(0, 0, '--external-downloader', customDownloadingAgent); } if (useYoutubeDLArchive) { diff --git a/src/app/settings/settings.component.html b/src/app/settings/settings.component.html index 1b0dd3b..8c0135d 100644 --- a/src/app/settings/settings.component.html +++ b/src/app/settings/settings.component.html @@ -223,13 +223,19 @@
Use default downloading agent
-
- - - - +
+ + Select a downloader + aria2c + avconv + axel + curl + ffmpeg + httpie + wget +
-
+
Allow advanced download
From 2cd35cccd1da675f331d961c8e4d82a57dd16221 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Sun, 15 Mar 2020 22:05:00 -0400 Subject: [PATCH 21/38] Added about page --- src/app/app.component.html | 4 +++ src/app/app.component.ts | 7 +++++ src/app/app.module.ts | 4 ++- .../about-dialog/about-dialog.component.html | 23 ++++++++++++++++ .../about-dialog/about-dialog.component.scss | 3 +++ .../about-dialog.component.spec.ts | 25 ++++++++++++++++++ .../about-dialog/about-dialog.component.ts | 21 +++++++++++++++ src/assets/images/GitHub-64px.png | Bin 0 -> 2625 bytes 8 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/app/dialogs/about-dialog/about-dialog.component.html create mode 100644 src/app/dialogs/about-dialog/about-dialog.component.scss create mode 100644 src/app/dialogs/about-dialog/about-dialog.component.spec.ts create mode 100644 src/app/dialogs/about-dialog/about-dialog.component.ts create mode 100644 src/assets/images/GitHub-64px.png diff --git a/src/app/app.component.html b/src/app/app.component.html index 9403aeb..8291ae3 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -21,6 +21,10 @@ settings Settings +
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index b5cb7b9..6f01687 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -21,6 +21,7 @@ import { Router, NavigationStart, NavigationEnd } from '@angular/router'; import { OverlayContainer } from '@angular/cdk/overlay'; import { THEMES_CONFIG } from '../themes'; import { SettingsComponent } from './settings/settings.component'; +import { AboutDialogComponent } from './dialogs/about-dialog/about-dialog.component'; @Component({ selector: 'app-root', @@ -165,5 +166,11 @@ onSetTheme(theme, old_theme) { }); } + openAboutDialog() { + const dialogRef = this.dialog.open(AboutDialogComponent, { + width: '80vw' + }); + } + } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index e6b6152..a430fff 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -48,6 +48,7 @@ import { SubscriptionInfoDialogComponent } from './dialogs/subscription-info-dia import { SettingsComponent } from './settings/settings.component'; import es from '@angular/common/locales/es'; +import { AboutDialogComponent } from './dialogs/about-dialog/about-dialog.component'; registerLocaleData(es, 'es'); export function isVisible({ event, element, scrollContainer, offset }: IsVisibleProps) { @@ -68,7 +69,8 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible SubscriptionComponent, SubscriptionFileCardComponent, SubscriptionInfoDialogComponent, - SettingsComponent + SettingsComponent, + AboutDialogComponent ], imports: [ BrowserModule, diff --git a/src/app/dialogs/about-dialog/about-dialog.component.html b/src/app/dialogs/about-dialog/about-dialog.component.html new file mode 100644 index 0000000..dde7daf --- /dev/null +++ b/src/app/dialogs/about-dialog/about-dialog.component.html @@ -0,0 +1,23 @@ +

About YoutubeDL-Material

+ + +
+

+ YoutubeDL-Material is an open-source YouTube downloader built under Google's Material Design specifications. You can seamlessly download your favorite videos as video or audio files, and even subscribe to your favorite channels and playlists to keep updated with their new videos. +

+

+ YoutubeDL-Material has some awesome features included! An extensive API, Docker support, and localization (translation) support. Read up on all the supported features by clicking on the GitHub icon below. +

+

+ Found a bug or have a suggestion? Click here to create an issue! +

+ + + +

Installed version: {{version}} - View latest update

+
+
+ + + + \ No newline at end of file diff --git a/src/app/dialogs/about-dialog/about-dialog.component.scss b/src/app/dialogs/about-dialog/about-dialog.component.scss new file mode 100644 index 0000000..b1d084c --- /dev/null +++ b/src/app/dialogs/about-dialog/about-dialog.component.scss @@ -0,0 +1,3 @@ +i { + margin-right: 1px; +} \ No newline at end of file diff --git a/src/app/dialogs/about-dialog/about-dialog.component.spec.ts b/src/app/dialogs/about-dialog/about-dialog.component.spec.ts new file mode 100644 index 0000000..7fc637d --- /dev/null +++ b/src/app/dialogs/about-dialog/about-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AboutDialogComponent } from './about-dialog.component'; + +describe('AboutDialogComponent', () => { + let component: AboutDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AboutDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AboutDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/dialogs/about-dialog/about-dialog.component.ts b/src/app/dialogs/about-dialog/about-dialog.component.ts new file mode 100644 index 0000000..475328a --- /dev/null +++ b/src/app/dialogs/about-dialog/about-dialog.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-about-dialog', + templateUrl: './about-dialog.component.html', + styleUrls: ['./about-dialog.component.scss'] +}) +export class AboutDialogComponent implements OnInit { + + projectLink = 'https://github.com/Tzahi12345/YoutubeDL-Material'; + issuesLink = 'https://github.com/Tzahi12345/YoutubeDL-Material/issues'; + latestUpdateLink = 'https://github.com/Tzahi12345/YoutubeDL-Material/releases/latest' + + version = 'v3.5'; + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/assets/images/GitHub-64px.png b/src/assets/images/GitHub-64px.png new file mode 100644 index 0000000000000000000000000000000000000000..182a1a3f734fc1b7d712c68b04c29bad9460d6cd GIT binary patch literal 2625 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 W4I>>0bz>}E>ge79v Date: Mon, 16 Mar 2020 01:22:09 -0400 Subject: [PATCH 22/38] Changed location of db and config to one unified directory, 'appdata' Archive files now get generated if nonexistent during deletions Simplified docker-compose.yml to not require environment variables. Added volume for appdata folder which will be automatically shipped with docker builds --- backend/app.js | 26 ++++++++++++++----- backend/{config => appdata}/default.json | 0 backend/{config => appdata}/encrypted.json | 0 backend/config.js | 2 +- backend/consts.js | 2 -- backend/subscriptions.js | 2 +- docker-compose.yml | 30 +++------------------- 7 files changed, 24 insertions(+), 38 deletions(-) rename backend/{config => appdata}/default.json (100%) rename backend/{config => appdata}/encrypted.json (100%) diff --git a/backend/app.js b/backend/app.js index 0c08a84..d616e57 100644 --- a/backend/app.js +++ b/backend/app.js @@ -19,7 +19,7 @@ var subscriptions_api = require('./subscriptions') var app = express(); const FileSync = require('lowdb/adapters/FileSync') -const adapter = new FileSync('db.json'); +const adapter = new FileSync('./appdata/db.json'); const db = low(adapter) // Set some defaults @@ -41,7 +41,6 @@ var usingEncryption = null; var basePath = null; var audioFolderPath = null; var videoFolderPath = null; -var useYoutubeDLArchive = null; var downloadOnlyMode = null; var useDefaultDownloadingAgent = null; var customDownloadingAgent = null; @@ -140,7 +139,6 @@ async function loadConfig() { usingEncryption = config_api.getConfigItem('ytdl_use_encryption'); audioFolderPath = config_api.getConfigItem('ytdl_audio_folder_path'); videoFolderPath = config_api.getConfigItem('ytdl_video_folder_path'); - useYoutubeDLArchive = config_api.getConfigItem('ytdl_use_youtubedl_archive'); downloadOnlyMode = config_api.getConfigItem('ytdl_download_only_mode'); useDefaultDownloadingAgent = config_api.getConfigItem('ytdl_use_default_downloading_agent'); customDownloadingAgent = config_api.getConfigItem('ytdl_custom_downloading_agent'); @@ -414,6 +412,7 @@ async function deleteAudioFile(name, blacklistMode = false) { } } + let useYoutubeDLArchive = config_api.getConfigItem('ytdl_use_youtubedl_archive'); if (useYoutubeDLArchive) { const archive_path = audioFolderPath + 'archive.txt'; @@ -424,8 +423,13 @@ async function deleteAudioFile(name, blacklistMode = false) { if (jsonobj) id = jsonobj.id; // use subscriptions API to remove video from the archive file, and write it to the blacklist - const line = id ? subscriptions_api.removeIDFromArchive(archive_path, id) : null; - if (blacklistMode && line) writeToBlacklist('audio', line); + if (fs.existsSync(archive_path)) { + const line = id ? subscriptions_api.removeIDFromArchive(archive_path, id) : null; + if (blacklistMode && line) writeToBlacklist('audio', line); + } else { + console.log('Could not find archive file for audio files. Creating...'); + fs.closeSync(fs.openSync(archive_path, 'w')); + } } if (jsonExists) fs.unlinkSync(jsonPath); @@ -466,6 +470,7 @@ async function deleteVideoFile(name, customPath = null, blacklistMode = false) { } } + let useYoutubeDLArchive = config_api.getConfigItem('ytdl_use_youtubedl_archive'); if (useYoutubeDLArchive) { const archive_path = videoFolderPath + 'archive.txt'; @@ -476,8 +481,13 @@ async function deleteVideoFile(name, customPath = null, blacklistMode = false) { if (jsonobj) id = jsonobj.id; // use subscriptions API to remove video from the archive file, and write it to the blacklist - const line = id ? subscriptions_api.removeIDFromArchive(archive_path, id) : null; - if (blacklistMode && line) writeToBlacklist('video', line); + if (fs.existsSync(archive_path)) { + const line = id ? subscriptions_api.removeIDFromArchive(archive_path, id) : null; + if (blacklistMode && line) writeToBlacklist('video', line); + } else { + console.log('Could not find archive file for videos. Creating...'); + fs.closeSync(fs.openSync(archive_path, 'w')); + } } if (jsonExists) fs.unlinkSync(jsonPath); @@ -671,6 +681,7 @@ app.post('/api/tomp3', async function(req, res) { downloadConfig.splice(0, 0, '--external-downloader', customDownloadingAgent); } + let useYoutubeDLArchive = config_api.getConfigItem('ytdl_use_youtubedl_archive'); if (useYoutubeDLArchive) { let archive_path = audioFolderPath + 'archive.txt'; // create archive file if it doesn't exist @@ -795,6 +806,7 @@ app.post('/api/tomp4', async function(req, res) { downloadConfig.splice(0, 0, '--external-downloader', customDownloadingAgent); } + let useYoutubeDLArchive = config_api.getConfigItem('ytdl_use_youtubedl_archive'); if (useYoutubeDLArchive) { let archive_path = videoFolderPath + 'archive.txt'; // create archive file if it doesn't exist diff --git a/backend/config/default.json b/backend/appdata/default.json similarity index 100% rename from backend/config/default.json rename to backend/appdata/default.json diff --git a/backend/config/encrypted.json b/backend/appdata/encrypted.json similarity index 100% rename from backend/config/encrypted.json rename to backend/appdata/encrypted.json diff --git a/backend/config.js b/backend/config.js index f61d321..fd6d854 100644 --- a/backend/config.js +++ b/backend/config.js @@ -3,7 +3,7 @@ const fs = require('fs'); let CONFIG_ITEMS = require('./consts.js')['CONFIG_ITEMS']; const debugMode = process.env.YTDL_MODE === 'debug'; -let configPath = debugMode ? '../src/assets/default.json' : 'config/default.json'; +let configPath = debugMode ? '../src/assets/default.json' : 'appdata/default.json'; // https://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key Object.byString = function(o, s) { diff --git a/backend/consts.js b/backend/consts.js index 73e4087..767dc0a 100644 --- a/backend/consts.js +++ b/backend/consts.js @@ -1,5 +1,3 @@ -var config = require('config'); - let CONFIG_ITEMS = { // Host 'ytdl_url': { diff --git a/backend/subscriptions.js b/backend/subscriptions.js index 8fa9ce6..d324d74 100644 --- a/backend/subscriptions.js +++ b/backend/subscriptions.js @@ -8,7 +8,7 @@ var path = require('path'); var youtubedl = require('youtube-dl'); const config_api = require('./config'); -const adapter = new FileSync('db.json'); +const adapter = new FileSync('./appdata/db.json'); const db = low(adapter) const debugMode = process.env.YTDL_MODE === 'debug'; diff --git a/docker-compose.yml b/docker-compose.yml index 6db5ceb..f03bdea 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,35 +4,11 @@ services: ytdl_material: build: . environment: - # config items - ytdl_url: http://localhost:8998 - ytdl_port: '17442' - ytdl_use_encryption: 'false' - ytdl_cert_file_path: /etc/letsencrypt/live/example.com/fullchain.pem - ytdl_key_file_path: /etc/letsencrypt/live/example.com/privkey.pem - ytdl_audio_folder_path: audio/ - ytdl_video_folder_path: video/ - ytdl_custom_args: '' - ytdl_title_top: Youtube Downloader - ytdl_file_manager_enabled: 'true' - ytdl_allow_quality_select: 'true' - ytdl_download_only_mode: 'false' - ytdl_allow_multi_download_mode: 'true' - ytdl_use_youtube_api: 'false' - ytdl_youtube_api_key: 'false' - ytdl_default_theme: default - ytdl_allow_theme_change: 'true' - ytdl_allow_subscriptions: 'true' - ytdl_subscriptions_base_path: subscriptions/ - ytdl_subscriptions_check_interval: '300' - ytdl_subscriptions_use_youtubedl_archive: 'true' - ytdl_use_default_downloading_agent: 'true' - ytdl_custom_downloading_agent: 'false' - ytdl_allow_advanced_download: 'false' - # do not touch this write_ytdl_config: 'true' ALLOW_CONFIG_MUTATIONS: 'true' restart: always + volumes: + - ./appdata:/app/config ports: - "8998:17442" - image: tzahi12345/youtubedl-material:3.4 \ No newline at end of file + image: tzahi12345/youtubedl-material:experimental \ No newline at end of file From 25b953cebd3edb2ea149cb1356b01741c0aa29f1 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Mon, 16 Mar 2020 01:22:48 -0400 Subject: [PATCH 23/38] Updated look of file cards again to prevent aspect ratio from being changed --- src/app/file-card/file-card.component.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/file-card/file-card.component.css b/src/app/file-card/file-card.component.css index 7376b16..342885f 100644 --- a/src/app/file-card/file-card.component.css +++ b/src/app/file-card/file-card.component.css @@ -18,8 +18,6 @@ .image { width: 100%; - height: 100%; - border-radius: 0px 0px 4px 4px; } .example-full-width-height { @@ -38,6 +36,8 @@ padding: 0px; margin: 8px 0px 0px -5px; width: calc(100% + 5px + 5px); + overflow: hidden; + border-radius: 0px 0px 4px 4px; } .max-two-lines { From 1d29dd8df4ee2ee18f0ed08356277e64336ab8f5 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Mon, 16 Mar 2020 01:23:08 -0400 Subject: [PATCH 24/38] Updated translations --- src/assets/i18n/messages.es.json | 26 ++-- src/locale/messages.xlf | 210 +++++++++++++++++++++---------- 2 files changed, 165 insertions(+), 71 deletions(-) diff --git a/src/assets/i18n/messages.es.json b/src/assets/i18n/messages.es.json index c197eaa..e72f728 100644 --- a/src/assets/i18n/messages.es.json +++ b/src/assets/i18n/messages.es.json @@ -5,18 +5,18 @@ "a52dae09be10ca3a65da918533ced3d3f4992238": "Archivos de video", "038ebcb2a89155d90c24fa1c17bfe83dbadc3c20": "Descargador de Youtube", "6d2ec8898344c8955542b0542c942038ef28bb80": "Por favor entre una URL válida", - "a38ae1082fec79ba1f379978337385a539a28e73": "Calidad", + "a38ae1082fec79ba1f379978337385a539a28e73": "Calidad:", "4be966a9dcfbc9b54dfcc604b831c0289f847fa4": "Usa URL", - "d3f02f845e62cebd75fde451ab8479d2a8ad784d": "Ver", + "d3f02f845e62cebd75fde451ab8479d2a8ad784d": "Ver:", "4a9889d36910edc8323d7bab60858ab3da6d91df": "Solo audio", "96a01fafe135afc58b0f8071a4ab00234495ce18": "Descarga múltiple", "6a21ba5fb0ac804a525bf9ab168038c3ee88e661": "Descarga", - "6a3777f913cf3f288664f0632b9f24794fdcc24e": "Cancela", + "6a3777f913cf3f288664f0632b9f24794fdcc24e": "Cancelar", "322ed150e02666fe2259c5b4614eac7066f4ffa0": "Avanzado", "b7ffe7c6586d6f3f18a9246806a7c7d5538ab43e": "Commando simulado:", "4e4c721129466be9c3862294dc40241b64045998": "Usar argumentos personalizados", "ad2f8ac8b7de7945b80c8e424484da94e597125f": "Argumentos personalizados", - "ccc7e92cbdd35e901acf9ad80941abee07bd8f60": "No es necesario incluir URL, solo todo después", + "ccc7e92cbdd35e901acf9ad80941abee07bd8f60": "No es necesario incluir URL, solo todo después ", "3a92a3443c65a52f37ca7efb8f453b35dbefbf29": "Usar salida personalizada", "d9c02face477f2f9cdaae318ccee5f89856851fb": "Salida personalizada", "fcfd4675b4c90f08d18d3abede9a9a4dff4cfdc7": "Documentación", @@ -32,7 +32,9 @@ "960582a8b9d7942716866ecfb7718309728f2916": "Tus archivos de video son aquí", "0f59c46ca29e9725898093c9ea6b586730d0624e": "No hay listas de reproducción disponibles. Cree uno de tus archivos de video haciendo clic en el botón azul más.", "ca3dbbc7f3e011bffe32a10a3ea45cc84f30ecf1": "ID:", - "e684046d73bcee88e82f7ff01e2852789a05fc32": "Cuenta:", + "e684046d73bcee88e82f7ff01e2852789a05fc32": "Count:", + "826b25211922a1b46436589233cb6f1a163d89b7": "Eliminar", + "34504b488c24c27e68089be549f0eeae6ebaf30b": "Eliminar y ", "121cc5391cd2a5115bc2b3160379ee5b36cd7716": "Configuraciones", "fe22ca53e651df951dac25b67c17894b0980f767": "Host", "801b98c6f02fe3b32f6afa3ee854c99ed83474e6": "URL", @@ -49,6 +51,7 @@ "46826331da1949bd6fb74624447057099c9d20cd": "Ruta de la carpeta de video", "17c92e6d47a213fa95b5aa344b3f258147123f93": "Ruta de descarga de videos. Es relativo a la carpeta raíz de YTDL-Material.", "f41145afc02fd47ef0576ac79acd2c47ebbf4901": "Argumentos personalizados globales para descargas en la página de inicio.", + "78e49b7339b4fa7184dd21bcaae107ce9b7076f6": "Usa el archivo de youtube-dl", "d5f69691f9f05711633128b5a3db696783266b58": "Extra", "61f8fd90b5f8cb20c70371feb2ee5e1fac5a9095": "Título superior", "78d3531417c0d4ba4c90f0d4ae741edc261ec8df": "Administrador de archivos habilitado", @@ -69,16 +72,23 @@ "bc9892814ee2d119ae94378c905ea440a249b84a": "Ruta base para videos de sus canales y listas de reproducción suscritos. Es relativo a la carpeta raíz de YTDL-Material.", "5bef4b25ba680da7fff06b86a91b1fc7e6a926e3": "Intervalo de comprobación", "0f56a7449b77630c114615395bbda4cab398efd8": "La unidad es segundos, solo incluye números.", - "78e49b7339b4fa7184dd21bcaae107ce9b7076f6": "Usa el archivo de youtube-dl", "fa9fe4255231dd1cc6b29d3d254a25cb7c764f0f": "Con la función de archivo de youtube-dl,", "09006404cccc24b7a8f8d1ce0b39f2761ab841d8": "los videos descargados de sus suscripciones se graban en un archivo de texto en el subdirectorio del archivo de suscripciones.", "29ed79a98fc01e7f9537777598e31dbde3aa7981": "Esto permite eliminar videos de sus suscripciones de forma permanente sin darse de baja y le permite grabar los videos que descargó en caso de pérdida de datos.", "bc2e854e111ecf2bd7db170da5e3c2ed08181d88": "Avanzado", "5fab47f146b0a4b809dcebf3db9da94df6299ea1": "Usar agente de descarga predeterminado", - "cdf75b1bdda80487e2ce1ff264ae171cbc5dc3b1": "Agente personalizado", "dc3d990391c944d1fbfc7cfb402f7b5e112fb3a8": "Permitir descarga avanzada", "52c9a103b812f258bcddc3d90a6e3f46871d25fe": "Salvar", "d7b35c384aecd25a516200d6921836374613dfe7": "Cancelar", + "cec82c0a545f37420d55a9b6c45c20546e82f94e": "Sobre YoutubeDL-Material", + "199c17e5d6a419313af3c325f06dcbb9645ca618": "es un descargador de código abierto de YouTube creado bajo las especificaciones de \"Material Design\" de Google. Puede descargar sin problemas sus videos favoritos como archivos de video o audio, e incluso suscribirse a sus canales favoritos y listas de reproducción para mantenerse actualizado con sus nuevos videos.", + "c072eebcb5b1f1eef6fb2ee1756e839dd302f3de": "tiene algunas características increíbles incluidas! Una amplia API, soporte de Docker y soporte de localización (traducción). Lea todas las funciones admitidas haciendo clic en el icono de GitHub a continuación.", + "b33536f59b94ec935a16bd6869d836895dc5300c": "¿Encontró un error o tiene una sugerencia?", + "9b3cedfa83c6d7acb3210953289d1be4aab115c7": "¡Haga clic aquí", + "e1f398f38ff1534303d4bb80bd6cece245f24016": "para crear una cuestión!", + "a45e3b05f0529dc5246d70ef62304c94426d4c81": "Versión instalada:", + "effdc7dfbbc49c08d25ea1748fca00c38c918abd": "Ver la última actualización", + "004b222ff9ef9dd4771b777950ca1d0e4cd4348a": "Sobre", "92eee6be6de0b11c924e3ab27db30257159c0a7c": "Inicio", "5b3075e8dc3f3921ec316b0bd83b6d14a06c1a4f": "Guardar cambios", "a9806cf78ce00eb2613eeca11354a97e033377b8": "Suscríbase a la lista de reproducción o al canal", @@ -100,7 +110,7 @@ "2e0a410652cb07d069f576b61eab32586a18320d": "Nombre no disponible. Recuperación de listas de reproducción en progreso.", "587b57ced54965d8874c3fd0e9dfedb987e5df04": "No tienes suscripciones a listas de reproducción.", "7e892ba15f2c6c17e83510e273b3e10fc32ea016": "Buscar", - "2054791b822475aeaea95c0119113de3200f5e1c": "Duración:", + "2054791b822475aeaea95c0119113de3200f5e1c": "Longitud:", "94e01842dcee90531caa52e4147f70679bac87fe": "Eliminar y volver a descargar", "2031adb51e07a41844e8ba7704b054e98345c9c1": "Borrar para siempre" } \ No newline at end of file diff --git a/src/locale/messages.xlf b/src/locale/messages.xlf index 8ec6073..21f8758 100644 --- a/src/locale/messages.xlf +++ b/src/locale/messages.xlf @@ -1,6 +1,6 @@ - + Create a playlist @@ -160,7 +160,7 @@ app/settings/settings.component.html - 83 + 92 Custom args placeholder @@ -334,6 +334,22 @@ Playlist video count + + Delete + + app/file-card/file-card.component.html + 21 + + Delete video button + + + Delete and blacklist + + app/file-card/file-card.component.html + 22 + + Delete and blacklist video button + Settings @@ -350,7 +366,7 @@ Host app/settings/settings.component.html - 8 + 17 Host settings title @@ -358,7 +374,7 @@ URL app/settings/settings.component.html - 15 + 24 app/dialogs/subscribe-dialog/subscribe-dialog.component.html @@ -370,7 +386,7 @@ URL this app will be accessed from, without the port. app/settings/settings.component.html - 16 + 25 URL setting input hint @@ -378,7 +394,7 @@ Port app/settings/settings.component.html - 21 + 30 Port input placeholder @@ -386,7 +402,7 @@ The desired port. Default is 17442. app/settings/settings.component.html - 22 + 31 Port setting input hint @@ -394,7 +410,7 @@ Encryption app/settings/settings.component.html - 34 + 43 Encryption settings title @@ -402,7 +418,7 @@ Use encryption app/settings/settings.component.html - 40 + 49 Use encryption setting @@ -410,7 +426,7 @@ Cert file path app/settings/settings.component.html - 45 + 54 Cert file path input placeholder @@ -418,7 +434,7 @@ Key file path app/settings/settings.component.html - 51 + 60 Key file path input placeholder @@ -426,7 +442,7 @@ Downloader app/settings/settings.component.html - 62 + 71 Downloader settings title @@ -434,7 +450,7 @@ Audio folder path app/settings/settings.component.html - 69 + 78 Audio folder path input placeholder @@ -442,7 +458,7 @@ Path for audio only downloads. It is relative to YTDL-Material's root folder. app/settings/settings.component.html - 70 + 79 Aduio path setting input hint @@ -450,7 +466,7 @@ Video folder path app/settings/settings.component.html - 76 + 85 Video folder path input placeholder @@ -458,7 +474,7 @@ Path for video downloads. It is relative to YTDL-Material's root folder. app/settings/settings.component.html - 77 + 86 Video path setting input hint @@ -466,15 +482,27 @@ Global custom args for downloads on the home page. app/settings/settings.component.html - 84 + 93 Custom args setting input hint + + Use youtube-dl archive + + app/settings/settings.component.html + 98 + + + app/settings/settings.component.html + 206 + + Use youtubedl archive setting + Extra app/settings/settings.component.html - 95 + 109 Extra settings title @@ -482,7 +510,7 @@ Top title app/settings/settings.component.html - 102 + 116 Top title input placeholder @@ -490,7 +518,7 @@ File manager enabled app/settings/settings.component.html - 107 + 121 File manager enabled setting @@ -498,7 +526,7 @@ Allow quality select app/settings/settings.component.html - 110 + 124 Allow quality seelct setting @@ -506,7 +534,7 @@ Download only mode app/settings/settings.component.html - 113 + 127 Download only mode setting @@ -514,7 +542,7 @@ Allow multi-download mode app/settings/settings.component.html - 116 + 130 Allow multi-downloade mode setting @@ -522,7 +550,7 @@ API app/settings/settings.component.html - 126 + 140 API settings title @@ -530,7 +558,7 @@ Use YouTube API app/settings/settings.component.html - 132 + 146 Use YouTube API setting @@ -538,7 +566,7 @@ Youtube API Key app/settings/settings.component.html - 136 + 150 Youtube API Key setting placeholder @@ -546,7 +574,7 @@ Generating a key is easy! app/settings/settings.component.html - 137 + 151 Youtube API Key setting hint @@ -554,7 +582,7 @@ Themes app/settings/settings.component.html - 148 + 162 Themes settings title @@ -562,7 +590,7 @@ Default app/settings/settings.component.html - 155 + 169 Default theme label @@ -570,7 +598,7 @@ Dark app/settings/settings.component.html - 156 + 170 app/app.component.html @@ -582,7 +610,7 @@ Allow theme change app/settings/settings.component.html - 161 + 175 Allow theme change setting @@ -590,11 +618,11 @@ Subscriptions app/settings/settings.component.html - 171 + 185 app/app.component.html - 34 + 38 Subscriptions settings title @@ -602,7 +630,7 @@ Allow subscriptions app/settings/settings.component.html - 177 + 191 Allow subscriptions setting @@ -610,7 +638,7 @@ Subscriptions base path app/settings/settings.component.html - 181 + 195 Subscriptions base path input setting placeholder @@ -618,7 +646,7 @@ Base path for videos from your subscribed channels and playlists. It is relative to YTDL-Material's root folder. app/settings/settings.component.html - 182 + 196 Subscriptions base path setting input hint @@ -626,7 +654,7 @@ Check interval app/settings/settings.component.html - 187 + 201 Check interval input setting placeholder @@ -634,23 +662,15 @@ Unit is seconds, only include numbers. app/settings/settings.component.html - 188 + 202 Check interval setting input hint - - Use youtube-dl archive - - app/settings/settings.component.html - 192 - - Use youtube-dl archive setting - With youtube-dl's archive app/settings/settings.component.html - 193 + 207 youtube-dl archive explanation prefix link @@ -658,7 +678,7 @@ feature, downloaded videos from your subscriptions get recorded in a text file in the subscriptions archive sub-directory. app/settings/settings.component.html - 193 + 207 youtube-dl archive explanation middle @@ -666,7 +686,7 @@ This enables the ability to permanently delete videos from your subscriptions without unsubscribing, and allows you to record which videos you downloaded in case of data loss. app/settings/settings.component.html - 194 + 208 youtube-dl archive explanation suffix @@ -674,7 +694,7 @@ Advanced app/settings/settings.component.html - 204 + 218 Advanced settings title @@ -682,23 +702,15 @@ Use default downloading agent app/settings/settings.component.html - 210 + 224 Use default downloading agent setting - - Custom agent - - app/settings/settings.component.html - 214 - - Custom agent setting placeholder - Allow advanced download app/settings/settings.component.html - 219 + 239 Allow advanced downloading setting @@ -706,7 +718,7 @@ Save app/settings/settings.component.html - 229 + 249 Settings save button @@ -714,7 +726,7 @@ Cancel app/settings/settings.component.html - 232 + 252 app/dialogs/subscribe-dialog/subscribe-dialog.component.html @@ -722,11 +734,83 @@ Settings cancel button + + About YoutubeDL-Material + + app/dialogs/about-dialog/about-dialog.component.html + 1 + + About dialog title + + + is an open-source YouTube downloader built under Google's Material Design specifications. You can seamlessly download your favorite videos as video or audio files, and even subscribe to your favorite channels and playlists to keep updated with their new videos. + + app/dialogs/about-dialog/about-dialog.component.html + 6 + + About first paragraph + + + has some awesome features included! An extensive API, Docker support, and localization (translation) support. Read up on all the supported features by clicking on the GitHub icon below. + + app/dialogs/about-dialog/about-dialog.component.html + 9 + + About second paragraph + + + Found a bug or have a suggestion? + + app/dialogs/about-dialog/about-dialog.component.html + 12 + + About bug prefix + + + Click here + + app/dialogs/about-dialog/about-dialog.component.html + 12 + + About bug click here + + + to create an issue! + + app/dialogs/about-dialog/about-dialog.component.html + 12 + + About bug suffix + + + Installed version: + + app/dialogs/about-dialog/about-dialog.component.html + 17 + + Version label + + + View latest update + + app/dialogs/about-dialog/about-dialog.component.html + 17 + + View latest update + + + About + + app/app.component.html + 26 + + About menu label + Home app/app.component.html - 33 + 37 Navigation menu Home Page title From f08506d690d828689b39cbd0295c5d901139c381 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Mon, 16 Mar 2020 01:23:35 -0400 Subject: [PATCH 25/38] When locale 'en' is selected, no translation is retrieved --- src/main.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main.ts b/src/main.ts index 8dfc77d..77ff462 100644 --- a/src/main.ts +++ b/src/main.ts @@ -13,7 +13,7 @@ if (environment.production) { } const locale = localStorage.getItem('locale'); -if (locale) { +if (locale && locale !== 'en') { getTranslations(`./assets/i18n/messages.${locale}.json`).then( (data: ParsedTranslationBundle) => { loadTranslations(data as any); @@ -31,7 +31,6 @@ if (locale) { }); }); } else { - console.log('no locale'); import('./app/app.module').then(module => { platformBrowserDynamic() .bootstrapModule(module.AppModule) From 3bdacd4b52885951cffbe7ab1b612e07cc65b134 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 05:29:25 -0400 Subject: [PATCH 26/38] Added additional volumes to docker compose --- docker-compose.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index f03bdea..5fa8c4e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,10 @@ services: ALLOW_CONFIG_MUTATIONS: 'true' restart: always volumes: - - ./appdata:/app/config + - ./appdata:/app/appdata + - ./audio:/app/audio + - ./video:/app/video + - ./subscriptions:/app/subscriptions ports: - "8998:17442" image: tzahi12345/youtubedl-material:experimental \ No newline at end of file From 1a79b489abca25fbb6811e30156c4f38dc87dd5d Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 06:58:05 -0400 Subject: [PATCH 27/38] Added video info dialog File cards and subscription file cards now use video info dialog so that users can see info on each individual video Ellipsis are now added client-side to video titles in file cards --- backend/app.js | 40 ++++++++++++------- package.json | 1 + src/app/app.module.ts | 4 +- .../video-info-dialog.component.html | 28 +++++++++++++ .../video-info-dialog.component.scss | 18 +++++++++ .../video-info-dialog.component.spec.ts | 25 ++++++++++++ .../video-info-dialog.component.ts | 22 ++++++++++ src/app/file-card/file-card.component.css | 8 ++++ src/app/file-card/file-card.component.html | 12 +++--- src/app/file-card/file-card.component.ts | 18 +++++++-- src/app/main/main.component.html | 4 +- .../subscription-file-card.component.html | 1 + .../subscription-file-card.component.ts | 15 +++++-- 13 files changed, 168 insertions(+), 28 deletions(-) create mode 100644 src/app/dialogs/video-info-dialog/video-info-dialog.component.html create mode 100644 src/app/dialogs/video-info-dialog/video-info-dialog.component.scss create mode 100644 src/app/dialogs/video-info-dialog/video-info-dialog.component.spec.ts create mode 100644 src/app/dialogs/video-info-dialog/video-info-dialog.component.ts diff --git a/backend/app.js b/backend/app.js index d616e57..3fdd32c 100644 --- a/backend/app.js +++ b/backend/app.js @@ -84,12 +84,16 @@ app.use(bodyParser.json()); // objects -function File(id, title, thumbnailURL, isAudio, duration) { +function File(id, title, thumbnailURL, isAudio, duration, url = null, uploader = null, size = null, path = null) { this.id = id; this.title = title; this.thumbnailURL = thumbnailURL; this.isAudio = isAudio; this.duration = duration; + this.url = url; + this.uploader = uploader; + this.size = size; + this.path = path; } // actual functions @@ -951,20 +955,21 @@ app.post('/api/getMp3s', function(req, res) { for (let i = 0; i < files.length; i++) { let file = files[i]; var file_path = file.substring(audioFolderPath.length, file.length); + + var stats = fs.statSync(file); + var id = file_path.substring(0, file_path.length-4); var jsonobj = getJSONMp3(id); if (!jsonobj) continue; var title = jsonobj.title; - - if (title.length > 14) // edits title if it's too long - { - title = title.substring(0,12) + "..."; - } + var url = jsonobj.webpage_url; + var uploader = jsonobj.uploader; + var size = stats.size; var thumbnail = jsonobj.thumbnail; var duration = jsonobj.duration; var isaudio = true; - var file_obj = new File(id, title, thumbnail, isaudio, duration); + var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file); mp3s.push(file_obj); } @@ -984,20 +989,21 @@ app.post('/api/getMp4s', function(req, res) { for (let i = 0; i < files.length; i++) { let file = files[i]; var file_path = file.substring(videoFolderPath.length, file.length); + + var stats = fs.statSync(file); + var id = file_path.substring(0, file_path.length-4); var jsonobj = getJSONMp4(id); if (!jsonobj) continue; var title = jsonobj.title; - - if (title.length > 14) // edits title if it's too long - { - title = title.substring(0,12) + "..."; - } + var url = jsonobj.webpage_url; + var uploader = jsonobj.uploader; + var size = stats.size; var thumbnail = jsonobj.thumbnail; var duration = jsonobj.duration; var isaudio = false; - var file_obj = new File(id, title, thumbnail, isaudio, duration); + var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file); mp4s.push(file_obj); } @@ -1101,6 +1107,8 @@ app.post('/api/getSubscription', async (req, res) => { for (let i = 0; i < files.length; i++) { let file = files[i]; var file_path = file.substring(appended_base_path.length, file.length); + var stats = fs.statSync(file); + var id = file_path.substring(0, file_path.length-4); var jsonobj = getJSONMp4(id, appended_base_path); if (!jsonobj) continue; @@ -1108,8 +1116,12 @@ app.post('/api/getSubscription', async (req, res) => { var thumbnail = jsonobj.thumbnail; var duration = jsonobj.duration; + var url = jsonobj.webpage_url; + var uploader = jsonobj.uploader; + var size = stats.size; + var isaudio = false; - var file_obj = new File(id, title, thumbnail, isaudio, duration); + var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file); parsed_files.push(file_obj); } diff --git a/package.json b/package.json index dcbef0f..64c1aec 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@locl/core": "0.0.1-beta.2", "core-js": "^2.4.1", "file-saver": "^2.0.2", + "filesize": "^6.1.0", "ng-lazyload-image": "^7.0.1", "ng4-configure": "^0.1.7", "ngx-content-loading": "^0.1.3", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a430fff..e88d6fb 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -49,6 +49,7 @@ import { SettingsComponent } from './settings/settings.component'; import es from '@angular/common/locales/es'; import { AboutDialogComponent } from './dialogs/about-dialog/about-dialog.component'; +import { VideoInfoDialogComponent } from './dialogs/video-info-dialog/video-info-dialog.component'; registerLocaleData(es, 'es'); export function isVisible({ event, element, scrollContainer, offset }: IsVisibleProps) { @@ -70,7 +71,8 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible SubscriptionFileCardComponent, SubscriptionInfoDialogComponent, SettingsComponent, - AboutDialogComponent + AboutDialogComponent, + VideoInfoDialogComponent ], imports: [ BrowserModule, diff --git a/src/app/dialogs/video-info-dialog/video-info-dialog.component.html b/src/app/dialogs/video-info-dialog/video-info-dialog.component.html new file mode 100644 index 0000000..234b77d --- /dev/null +++ b/src/app/dialogs/video-info-dialog/video-info-dialog.component.html @@ -0,0 +1,28 @@ +

{{file.title}}

+ + +
+
Name: 
+
{{file.title}}
+
+
+
URL: 
+ +
+
+
Uploader: 
+
{{file.uploader ? file.uploader : 'N/A'}}
+
+
+
File size: 
+
{{filesize(file.size)}}
+
+
+
Path: 
+
{{file.path}}
+
+
+ + + + \ No newline at end of file diff --git a/src/app/dialogs/video-info-dialog/video-info-dialog.component.scss b/src/app/dialogs/video-info-dialog/video-info-dialog.component.scss new file mode 100644 index 0000000..6e7c4f9 --- /dev/null +++ b/src/app/dialogs/video-info-dialog/video-info-dialog.component.scss @@ -0,0 +1,18 @@ +.info-item { + margin-bottom: 12px; + width: 100%; +} + +.info-item-value { + font-size: 13px; + display: inline-block; + width: 70%; +} + +.spacer {flex: 1 1 auto;} + +.info-item-label { + display: inline-block; + width: 30%; + vertical-align: top; +} diff --git a/src/app/dialogs/video-info-dialog/video-info-dialog.component.spec.ts b/src/app/dialogs/video-info-dialog/video-info-dialog.component.spec.ts new file mode 100644 index 0000000..126ea43 --- /dev/null +++ b/src/app/dialogs/video-info-dialog/video-info-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { VideoInfoDialogComponent } from './video-info-dialog.component'; + +describe('VideoInfoDialogComponent', () => { + let component: VideoInfoDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ VideoInfoDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(VideoInfoDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/dialogs/video-info-dialog/video-info-dialog.component.ts b/src/app/dialogs/video-info-dialog/video-info-dialog.component.ts new file mode 100644 index 0000000..4bfc8e3 --- /dev/null +++ b/src/app/dialogs/video-info-dialog/video-info-dialog.component.ts @@ -0,0 +1,22 @@ +import { Component, OnInit, Inject } from '@angular/core'; +import filesize from 'filesize'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; + +@Component({ + selector: 'app-video-info-dialog', + templateUrl: './video-info-dialog.component.html', + styleUrls: ['./video-info-dialog.component.scss'] +}) +export class VideoInfoDialogComponent implements OnInit { + file: any; + filesize; + constructor(@Inject(MAT_DIALOG_DATA) public data: any) { } + + ngOnInit(): void { + this.filesize = filesize; + if (this.data) { + this.file = this.data.file; + } + } + +} diff --git a/src/app/file-card/file-card.component.css b/src/app/file-card/file-card.component.css index 342885f..a581bca 100644 --- a/src/app/file-card/file-card.component.css +++ b/src/app/file-card/file-card.component.css @@ -51,6 +51,14 @@ -webkit-line-clamp: 2; } +.file-link { + width: 80%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; +} + @media (max-width: 576px){ .example-card { diff --git a/src/app/file-card/file-card.component.html b/src/app/file-card/file-card.component.html index 1c796c5..fd4317d 100644 --- a/src/app/file-card/file-card.component.html +++ b/src/app/file-card/file-card.component.html @@ -1,8 +1,9 @@
- {{title}} -
+
+ {{title}} +
ID: {{name}}
Count: {{count}}
@@ -15,10 +16,11 @@
- - + + + - + diff --git a/src/app/file-card/file-card.component.ts b/src/app/file-card/file-card.component.ts index 770976e..1c896c2 100644 --- a/src/app/file-card/file-card.component.ts +++ b/src/app/file-card/file-card.component.ts @@ -5,6 +5,8 @@ import {EventEmitter} from '@angular/core'; import { MainComponent } from 'app/main/main.component'; import { Subject, Observable } from 'rxjs'; import 'rxjs/add/observable/merge'; +import { MatDialog } from '@angular/material/dialog'; +import { VideoInfoDialogComponent } from 'app/dialogs/video-info-dialog/video-info-dialog.component'; @Component({ selector: 'app-file-card', @@ -12,7 +14,7 @@ import 'rxjs/add/observable/merge'; styleUrls: ['./file-card.component.css'] }) export class FileCardComponent implements OnInit { - + @Input() file: any; @Input() title: string; @Input() length: string; @Input() name: string; @@ -29,8 +31,10 @@ export class FileCardComponent implements OnInit { scrollSubject; scrollAndLoad; - constructor(private postsService: PostsService, public snackBar: MatSnackBar, public mainComponent: MainComponent) { - this.scrollSubject = new Subject(); + constructor(private postsService: PostsService, public snackBar: MatSnackBar, public mainComponent: MainComponent, + private dialog: MatDialog) { + + this.scrollSubject = new Subject(); this.scrollAndLoad = Observable.merge( Observable.fromEvent(window, 'scroll'), this.scrollSubject @@ -57,6 +61,14 @@ export class FileCardComponent implements OnInit { } + openSubscriptionInfoDialog() { + const dialogRef = this.dialog.open(VideoInfoDialogComponent, { + data: { + file: this.file, + } + }); + } + onImgError(event) { this.image_errored = true; } diff --git a/src/app/main/main.component.html b/src/app/main/main.component.html index dc11d79..982a917 100644 --- a/src/app/main/main.component.html +++ b/src/app/main/main.component.html @@ -203,7 +203,7 @@
- @@ -244,7 +244,7 @@
- diff --git a/src/app/subscription/subscription-file-card/subscription-file-card.component.html b/src/app/subscription/subscription-file-card/subscription-file-card.component.html index a2972a9..81897db 100644 --- a/src/app/subscription/subscription-file-card/subscription-file-card.component.html +++ b/src/app/subscription/subscription-file-card/subscription-file-card.component.html @@ -4,6 +4,7 @@
+ diff --git a/src/app/subscription/subscription-file-card/subscription-file-card.component.ts b/src/app/subscription/subscription-file-card/subscription-file-card.component.ts index c2c23e2..6c9b3b7 100644 --- a/src/app/subscription/subscription-file-card/subscription-file-card.component.ts +++ b/src/app/subscription/subscription-file-card/subscription-file-card.component.ts @@ -3,6 +3,8 @@ import { Observable, Subject } from 'rxjs'; import { MatSnackBar } from '@angular/material/snack-bar'; import { Router } from '@angular/router'; import { PostsService } from 'app/posts.services'; +import { MatDialog } from '@angular/material/dialog'; +import { VideoInfoDialogComponent } from 'app/dialogs/video-info-dialog/video-info-dialog.component'; @Component({ selector: 'app-subscription-file-card', @@ -25,7 +27,7 @@ export class SubscriptionFileCardComponent implements OnInit { @Output() goToFileEmit = new EventEmitter(); @Output() reloadSubscription = new EventEmitter(); - constructor(private snackBar: MatSnackBar, private postsService: PostsService) { + constructor(private snackBar: MatSnackBar, private postsService: PostsService, private dialog: MatDialog) { this.scrollSubject = new Subject(); this.scrollAndLoad = Observable.merge( Observable.fromEvent(window, 'scroll'), @@ -55,6 +57,14 @@ export class SubscriptionFileCardComponent implements OnInit { this.goToFileEmit.emit(this.file.id); } + openSubscriptionInfoDialog() { + const dialogRef = this.dialog.open(VideoInfoDialogComponent, { + data: { + file: this.file, + } + }); + } + deleteAndRedownload() { this.postsService.deleteSubscriptionFile(this.sub, this.file.id, false).subscribe(res => { this.reloadSubscription.emit(true); @@ -77,8 +87,7 @@ export class SubscriptionFileCardComponent implements OnInit { } -function fancyTimeFormat(time) -{ +function fancyTimeFormat(time) { // Hours, minutes and seconds const hrs = ~~(time / 3600); const mins = ~~((time % 3600) / 60); From 9dc607e7ee553448de4d345a5a68ba50275f441c Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 18:07:35 -0400 Subject: [PATCH 28/38] fixed bug where no subscriptions resulted in a client error --- src/app/subscriptions/subscriptions.component.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/subscriptions/subscriptions.component.ts b/src/app/subscriptions/subscriptions.component.ts index 9614e87..0f89c61 100644 --- a/src/app/subscriptions/subscriptions.component.ts +++ b/src/app/subscriptions/subscriptions.component.ts @@ -33,6 +33,9 @@ export class SubscriptionsComponent implements OnInit { this.postsService.getAllSubscriptions().subscribe(res => { this.subscriptions_loading = false; this.subscriptions = res['subscriptions']; + if (!this.subscriptions) { + return; + } for (let i = 0; i < this.subscriptions.length; i++) { const sub = this.subscriptions[i]; From a5e1906196e3f4d338aca4a4827296c897564123 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 18:14:11 -0400 Subject: [PATCH 29/38] Fixed bug that prevented auto start from working --- src/app/main/main.component.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app/main/main.component.ts b/src/app/main/main.component.ts index 9c356ce..73ca33e 100644 --- a/src/app/main/main.component.ts +++ b/src/app/main/main.component.ts @@ -214,14 +214,6 @@ export class MainComponent implements OnInit { constructor(private postsService: PostsService, private youtubeSearch: YoutubeSearchService, public snackBar: MatSnackBar, private router: Router, public dialog: MatDialog, private platform: Platform, private route: ActivatedRoute) { this.audioOnly = false; - - this.configLoad(); - - this.postsService.settings_changed.subscribe(changed => { - if (changed) { - this.loadConfig(); - } - }); } async configLoad() { @@ -299,6 +291,14 @@ export class MainComponent implements OnInit { // app initialization. ngOnInit() { + this.configLoad(); + + this.postsService.settings_changed.subscribe(changed => { + if (changed) { + this.loadConfig(); + } + }); + this.iOS = this.platform.IOS; // get checkboxes From aa80f52838acaad1241de8aacda66a336b361d22 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 18:15:07 -0400 Subject: [PATCH 30/38] Updated firefox extension to v0.3, focused on making the settings menu look nicer --- chrome-extension/css/bootstrap.min.css | 7 ++++ chrome-extension/js/bootstrap.min.js | 7 ++++ chrome-extension/js/jquery-3.4.1.min.js | 2 + chrome-extension/js/popper.min.js | 5 +++ chrome-extension/options.html | 49 ++++++++++++++++--------- chrome-extension/options.js | 7 ++-- 6 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 chrome-extension/css/bootstrap.min.css create mode 100644 chrome-extension/js/bootstrap.min.js create mode 100644 chrome-extension/js/jquery-3.4.1.min.js create mode 100644 chrome-extension/js/popper.min.js diff --git a/chrome-extension/css/bootstrap.min.css b/chrome-extension/css/bootstrap.min.css new file mode 100644 index 0000000..6561b6f --- /dev/null +++ b/chrome-extension/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.0.0 (https://getbootstrap.com) + * Copyright 2011-2018 The Bootstrap Authors + * Copyright 2011-2018 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}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]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}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}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[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.2;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}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:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.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-lg-auto,.col-md,.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-md-auto,.col-sm,.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-sm-auto,.col-xl,.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-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-sm-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-sm-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-sm-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-sm-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-sm-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-sm-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-sm-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-sm-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-sm-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-sm-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-sm-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-sm-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-sm-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-sm-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-md-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-md-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-md-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-md-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-md-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-md-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-md-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-md-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-md-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-md-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-md-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-md-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-md-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-md-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-lg-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-lg-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-lg-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-lg-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-lg-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-lg-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-lg-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-lg-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-lg-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-lg-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-lg-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-lg-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-lg-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-lg-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-xl-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-xl-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-xl-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-xl-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-xl-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-xl-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-xl-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-xl-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-xl-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-xl-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-xl-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-xl-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-xl-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-xl-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.input-group-append>.form-control-plaintext.btn,.input-group-lg>.input-group-append>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-prepend>.form-control-plaintext.btn,.input-group-lg>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.input-group-append>.form-control-plaintext.btn,.input-group-sm>.input-group-append>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-prepend>.form-control-plaintext.btn,.input-group-sm>.input-group-prepend>.form-control-plaintext.input-group-text{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.875rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(40,167,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{background-color:#71dd8a}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label::before,.was-validated .custom-file-input:valid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::before,.was-validated .custom-file-input:invalid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group{width:auto}.form-inline .form-check{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled).active,.btn:not(:disabled):not(.disabled):active{background-image:none}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;background-color:transparent}.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent;border-color:transparent}.btn-link.focus,.btn-link:focus{text-decoration:underline;border-color:transparent;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}.dropdown,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropup .dropdown-menu{margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.btn-group,.btn-group-vertical{position:relative;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-webkit-box-flex:0;-ms-flex:0 1 auto;flex:0 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.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:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.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-left:-1px}.btn-toolbar{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.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-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file:focus,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control{margin-left:-1px}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::before{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label,.input-group>.custom-file:not(:first-child) .custom-file-label::before{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-webkit-box;display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:active~.custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{margin-bottom:0}.custom-control-label::before{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;content:"";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:inset 0 1px 2px rgba(0,0,0,.075),0 0 5px rgba(128,189,255,.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-control{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:focus~.custom-file-control::before{border-color:#80bdff}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(calc(2.25rem + 2px) - 1px * 2);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.nav{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .dropup .dropdown-menu{top:auto;bottom:100%}}.navbar-expand{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .dropup .dropdown-menu{top:auto;bottom:100%}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.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 .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;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-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1 0 0%;flex:1 0 0%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-webkit-box-flex:1;-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.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-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.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-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.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{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-webkit-box;display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.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{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.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:.25rem .5rem;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}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-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:-webkit-box;display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;background-color:#007bff;transition:width .6s ease}.progress-bar-striped{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}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.media-body{-webkit-box-flex:1;-ms-flex:1;flex:1}.list-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.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-item:focus,.list-group-item:hover{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left: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}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:focus,.close:hover{color:#000;text-decoration:none;opacity:.75}.close:not(:disabled):not(.disabled){cursor:pointer}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-dialog-centered{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-content{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;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.show{opacity:.5}.modal-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";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;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";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;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top] .arrow,.bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right] .arrow,.bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::before{left:0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom] .arrow,.bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem .5rem}.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left] .arrow,.bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::before{right:0;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-webkit-box-flex:0;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{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}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.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::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-sm-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-md-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-lg-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-xl-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;-webkit-clip-path:inset(50%);clip-path:inset(50%);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;-webkit-clip-path:none;clip-path:none}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.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-light{font-weight:300!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-muted{color:#6c757d!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{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}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/chrome-extension/js/bootstrap.min.js b/chrome-extension/js/bootstrap.min.js new file mode 100644 index 0000000..534d533 --- /dev/null +++ b/chrome-extension/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.0.0 (https://getbootstrap.com) + * Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e(t.bootstrap={},t.jQuery,t.Popper)}(this,function(t,e,n){"use strict";function i(t,e){for(var n=0;n0?i:null}catch(t){return null}},reflow:function(t){return t.offsetHeight},triggerTransitionEnd:function(n){t(n).trigger(e.end)},supportsTransitionEnd:function(){return Boolean(e)},isElement:function(t){return(t[0]||t).nodeType},typeCheckConfig:function(t,e,n){for(var s in n)if(Object.prototype.hasOwnProperty.call(n,s)){var r=n[s],o=e[s],a=o&&i.isElement(o)?"element":(l=o,{}.toString.call(l).match(/\s([a-zA-Z]+)/)[1].toLowerCase());if(!new RegExp(r).test(a))throw new Error(t.toUpperCase()+': Option "'+s+'" provided type "'+a+'" but expected type "'+r+'".')}var l}};return e=("undefined"==typeof window||!window.QUnit)&&{end:"transitionend"},t.fn.emulateTransitionEnd=n,i.supportsTransitionEnd()&&(t.event.special[i.TRANSITION_END]={bindType:e.end,delegateType:e.end,handle:function(e){if(t(e.target).is(this))return e.handleObj.handler.apply(this,arguments)}}),i}(e),L=(a="alert",h="."+(l="bs.alert"),c=(o=e).fn[a],u={CLOSE:"close"+h,CLOSED:"closed"+h,CLICK_DATA_API:"click"+h+".data-api"},f="alert",d="fade",_="show",g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){t=t||this._element;var e=this._getRootElement(t);this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.removeData(this._element,l),this._element=null},e._getRootElement=function(t){var e=P.getSelectorFromElement(t),n=!1;return e&&(n=o(e)[0]),n||(n=o(t).closest("."+f)[0]),n},e._triggerCloseEvent=function(t){var e=o.Event(u.CLOSE);return o(t).trigger(e),e},e._removeElement=function(t){var e=this;o(t).removeClass(_),P.supportsTransitionEnd()&&o(t).hasClass(d)?o(t).one(P.TRANSITION_END,function(n){return e._destroyElement(t,n)}).emulateTransitionEnd(150):this._destroyElement(t)},e._destroyElement=function(t){o(t).detach().trigger(u.CLOSED).remove()},t._jQueryInterface=function(e){return this.each(function(){var n=o(this),i=n.data(l);i||(i=new t(this),n.data(l,i)),"close"===e&&i[e](this)})},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},s(t,null,[{key:"VERSION",get:function(){return"4.0.0"}}]),t}(),o(document).on(u.CLICK_DATA_API,'[data-dismiss="alert"]',g._handleDismiss(new g)),o.fn[a]=g._jQueryInterface,o.fn[a].Constructor=g,o.fn[a].noConflict=function(){return o.fn[a]=c,g._jQueryInterface},g),R=(m="button",E="."+(v="bs.button"),T=".data-api",y=(p=e).fn[m],C="active",I="btn",A="focus",b='[data-toggle^="button"]',D='[data-toggle="buttons"]',S="input",w=".active",N=".btn",O={CLICK_DATA_API:"click"+E+T,FOCUS_BLUR_DATA_API:"focus"+E+T+" blur"+E+T},k=function(){function t(t){this._element=t}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=p(this._element).closest(D)[0];if(n){var i=p(this._element).find(S)[0];if(i){if("radio"===i.type)if(i.checked&&p(this._element).hasClass(C))t=!1;else{var s=p(n).find(w)[0];s&&p(s).removeClass(C)}if(t){if(i.hasAttribute("disabled")||n.hasAttribute("disabled")||i.classList.contains("disabled")||n.classList.contains("disabled"))return;i.checked=!p(this._element).hasClass(C),p(i).trigger("change")}i.focus(),e=!1}}e&&this._element.setAttribute("aria-pressed",!p(this._element).hasClass(C)),t&&p(this._element).toggleClass(C)},e.dispose=function(){p.removeData(this._element,v),this._element=null},t._jQueryInterface=function(e){return this.each(function(){var n=p(this).data(v);n||(n=new t(this),p(this).data(v,n)),"toggle"===e&&n[e]()})},s(t,null,[{key:"VERSION",get:function(){return"4.0.0"}}]),t}(),p(document).on(O.CLICK_DATA_API,b,function(t){t.preventDefault();var e=t.target;p(e).hasClass(I)||(e=p(e).closest(N)),k._jQueryInterface.call(p(e),"toggle")}).on(O.FOCUS_BLUR_DATA_API,b,function(t){var e=p(t.target).closest(N)[0];p(e).toggleClass(A,/^focus(in)?$/.test(t.type))}),p.fn[m]=k._jQueryInterface,p.fn[m].Constructor=k,p.fn[m].noConflict=function(){return p.fn[m]=y,k._jQueryInterface},k),j=function(t){var e="carousel",n="bs.carousel",i="."+n,o=t.fn[e],a={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0},l={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean"},h="next",c="prev",u="left",f="right",d={SLIDE:"slide"+i,SLID:"slid"+i,KEYDOWN:"keydown"+i,MOUSEENTER:"mouseenter"+i,MOUSELEAVE:"mouseleave"+i,TOUCHEND:"touchend"+i,LOAD_DATA_API:"load"+i+".data-api",CLICK_DATA_API:"click"+i+".data-api"},_="carousel",g="active",p="slide",m="carousel-item-right",v="carousel-item-left",E="carousel-item-next",T="carousel-item-prev",y={ACTIVE:".active",ACTIVE_ITEM:".active.carousel-item",ITEM:".carousel-item",NEXT_PREV:".carousel-item-next, .carousel-item-prev",INDICATORS:".carousel-indicators",DATA_SLIDE:"[data-slide], [data-slide-to]",DATA_RIDE:'[data-ride="carousel"]'},C=function(){function o(e,n){this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this._config=this._getConfig(n),this._element=t(e)[0],this._indicatorsElement=t(this._element).find(y.INDICATORS)[0],this._addEventListeners()}var C=o.prototype;return C.next=function(){this._isSliding||this._slide(h)},C.nextWhenVisible=function(){!document.hidden&&t(this._element).is(":visible")&&"hidden"!==t(this._element).css("visibility")&&this.next()},C.prev=function(){this._isSliding||this._slide(c)},C.pause=function(e){e||(this._isPaused=!0),t(this._element).find(y.NEXT_PREV)[0]&&P.supportsTransitionEnd()&&(P.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},C.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},C.to=function(e){var n=this;this._activeElement=t(this._element).find(y.ACTIVE_ITEM)[0];var i=this._getItemIndex(this._activeElement);if(!(e>this._items.length-1||e<0))if(this._isSliding)t(this._element).one(d.SLID,function(){return n.to(e)});else{if(i===e)return this.pause(),void this.cycle();var s=e>i?h:c;this._slide(s,this._items[e])}},C.dispose=function(){t(this._element).off(i),t.removeData(this._element,n),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},C._getConfig=function(t){return t=r({},a,t),P.typeCheckConfig(e,t,l),t},C._addEventListeners=function(){var e=this;this._config.keyboard&&t(this._element).on(d.KEYDOWN,function(t){return e._keydown(t)}),"hover"===this._config.pause&&(t(this._element).on(d.MOUSEENTER,function(t){return e.pause(t)}).on(d.MOUSELEAVE,function(t){return e.cycle(t)}),"ontouchstart"in document.documentElement&&t(this._element).on(d.TOUCHEND,function(){e.pause(),e.touchTimeout&&clearTimeout(e.touchTimeout),e.touchTimeout=setTimeout(function(t){return e.cycle(t)},500+e._config.interval)}))},C._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},C._getItemIndex=function(e){return this._items=t.makeArray(t(e).parent().find(y.ITEM)),this._items.indexOf(e)},C._getItemByDirection=function(t,e){var n=t===h,i=t===c,s=this._getItemIndex(e),r=this._items.length-1;if((i&&0===s||n&&s===r)&&!this._config.wrap)return e;var o=(s+(t===c?-1:1))%this._items.length;return-1===o?this._items[this._items.length-1]:this._items[o]},C._triggerSlideEvent=function(e,n){var i=this._getItemIndex(e),s=this._getItemIndex(t(this._element).find(y.ACTIVE_ITEM)[0]),r=t.Event(d.SLIDE,{relatedTarget:e,direction:n,from:s,to:i});return t(this._element).trigger(r),r},C._setActiveIndicatorElement=function(e){if(this._indicatorsElement){t(this._indicatorsElement).find(y.ACTIVE).removeClass(g);var n=this._indicatorsElement.children[this._getItemIndex(e)];n&&t(n).addClass(g)}},C._slide=function(e,n){var i,s,r,o=this,a=t(this._element).find(y.ACTIVE_ITEM)[0],l=this._getItemIndex(a),c=n||a&&this._getItemByDirection(e,a),_=this._getItemIndex(c),C=Boolean(this._interval);if(e===h?(i=v,s=E,r=u):(i=m,s=T,r=f),c&&t(c).hasClass(g))this._isSliding=!1;else if(!this._triggerSlideEvent(c,r).isDefaultPrevented()&&a&&c){this._isSliding=!0,C&&this.pause(),this._setActiveIndicatorElement(c);var I=t.Event(d.SLID,{relatedTarget:c,direction:r,from:l,to:_});P.supportsTransitionEnd()&&t(this._element).hasClass(p)?(t(c).addClass(s),P.reflow(c),t(a).addClass(i),t(c).addClass(i),t(a).one(P.TRANSITION_END,function(){t(c).removeClass(i+" "+s).addClass(g),t(a).removeClass(g+" "+s+" "+i),o._isSliding=!1,setTimeout(function(){return t(o._element).trigger(I)},0)}).emulateTransitionEnd(600)):(t(a).removeClass(g),t(c).addClass(g),this._isSliding=!1,t(this._element).trigger(I)),C&&this.cycle()}},o._jQueryInterface=function(e){return this.each(function(){var i=t(this).data(n),s=r({},a,t(this).data());"object"==typeof e&&(s=r({},s,e));var l="string"==typeof e?e:s.slide;if(i||(i=new o(this,s),t(this).data(n,i)),"number"==typeof e)i.to(e);else if("string"==typeof l){if("undefined"==typeof i[l])throw new TypeError('No method named "'+l+'"');i[l]()}else s.interval&&(i.pause(),i.cycle())})},o._dataApiClickHandler=function(e){var i=P.getSelectorFromElement(this);if(i){var s=t(i)[0];if(s&&t(s).hasClass(_)){var a=r({},t(s).data(),t(this).data()),l=this.getAttribute("data-slide-to");l&&(a.interval=!1),o._jQueryInterface.call(t(s),a),l&&t(s).data(n).to(l),e.preventDefault()}}},s(o,null,[{key:"VERSION",get:function(){return"4.0.0"}},{key:"Default",get:function(){return a}}]),o}();return t(document).on(d.CLICK_DATA_API,y.DATA_SLIDE,C._dataApiClickHandler),t(window).on(d.LOAD_DATA_API,function(){t(y.DATA_RIDE).each(function(){var e=t(this);C._jQueryInterface.call(e,e.data())})}),t.fn[e]=C._jQueryInterface,t.fn[e].Constructor=C,t.fn[e].noConflict=function(){return t.fn[e]=o,C._jQueryInterface},C}(e),H=function(t){var e="collapse",n="bs.collapse",i="."+n,o=t.fn[e],a={toggle:!0,parent:""},l={toggle:"boolean",parent:"(string|element)"},h={SHOW:"show"+i,SHOWN:"shown"+i,HIDE:"hide"+i,HIDDEN:"hidden"+i,CLICK_DATA_API:"click"+i+".data-api"},c="show",u="collapse",f="collapsing",d="collapsed",_="width",g="height",p={ACTIVES:".show, .collapsing",DATA_TOGGLE:'[data-toggle="collapse"]'},m=function(){function i(e,n){this._isTransitioning=!1,this._element=e,this._config=this._getConfig(n),this._triggerArray=t.makeArray(t('[data-toggle="collapse"][href="#'+e.id+'"],[data-toggle="collapse"][data-target="#'+e.id+'"]'));for(var i=t(p.DATA_TOGGLE),s=0;s0&&(this._selector=o,this._triggerArray.push(r))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var o=i.prototype;return o.toggle=function(){t(this._element).hasClass(c)?this.hide():this.show()},o.show=function(){var e,s,r=this;if(!this._isTransitioning&&!t(this._element).hasClass(c)&&(this._parent&&0===(e=t.makeArray(t(this._parent).find(p.ACTIVES).filter('[data-parent="'+this._config.parent+'"]'))).length&&(e=null),!(e&&(s=t(e).not(this._selector).data(n))&&s._isTransitioning))){var o=t.Event(h.SHOW);if(t(this._element).trigger(o),!o.isDefaultPrevented()){e&&(i._jQueryInterface.call(t(e).not(this._selector),"hide"),s||t(e).data(n,null));var a=this._getDimension();t(this._element).removeClass(u).addClass(f),this._element.style[a]=0,this._triggerArray.length>0&&t(this._triggerArray).removeClass(d).attr("aria-expanded",!0),this.setTransitioning(!0);var l=function(){t(r._element).removeClass(f).addClass(u).addClass(c),r._element.style[a]="",r.setTransitioning(!1),t(r._element).trigger(h.SHOWN)};if(P.supportsTransitionEnd()){var _="scroll"+(a[0].toUpperCase()+a.slice(1));t(this._element).one(P.TRANSITION_END,l).emulateTransitionEnd(600),this._element.style[a]=this._element[_]+"px"}else l()}}},o.hide=function(){var e=this;if(!this._isTransitioning&&t(this._element).hasClass(c)){var n=t.Event(h.HIDE);if(t(this._element).trigger(n),!n.isDefaultPrevented()){var i=this._getDimension();if(this._element.style[i]=this._element.getBoundingClientRect()[i]+"px",P.reflow(this._element),t(this._element).addClass(f).removeClass(u).removeClass(c),this._triggerArray.length>0)for(var s=0;s0&&t(n).toggleClass(d,!i).attr("aria-expanded",i)}},i._getTargetFromElement=function(e){var n=P.getSelectorFromElement(e);return n?t(n)[0]:null},i._jQueryInterface=function(e){return this.each(function(){var s=t(this),o=s.data(n),l=r({},a,s.data(),"object"==typeof e&&e);if(!o&&l.toggle&&/show|hide/.test(e)&&(l.toggle=!1),o||(o=new i(this,l),s.data(n,o)),"string"==typeof e){if("undefined"==typeof o[e])throw new TypeError('No method named "'+e+'"');o[e]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.0.0"}},{key:"Default",get:function(){return a}}]),i}();return t(document).on(h.CLICK_DATA_API,p.DATA_TOGGLE,function(e){"A"===e.currentTarget.tagName&&e.preventDefault();var i=t(this),s=P.getSelectorFromElement(this);t(s).each(function(){var e=t(this),s=e.data(n)?"toggle":i.data();m._jQueryInterface.call(e,s)})}),t.fn[e]=m._jQueryInterface,t.fn[e].Constructor=m,t.fn[e].noConflict=function(){return t.fn[e]=o,m._jQueryInterface},m}(e),W=function(t){var e="dropdown",i="bs.dropdown",o="."+i,a=".data-api",l=t.fn[e],h=new RegExp("38|40|27"),c={HIDE:"hide"+o,HIDDEN:"hidden"+o,SHOW:"show"+o,SHOWN:"shown"+o,CLICK:"click"+o,CLICK_DATA_API:"click"+o+a,KEYDOWN_DATA_API:"keydown"+o+a,KEYUP_DATA_API:"keyup"+o+a},u="disabled",f="show",d="dropup",_="dropright",g="dropleft",p="dropdown-menu-right",m="dropdown-menu-left",v="position-static",E='[data-toggle="dropdown"]',T=".dropdown form",y=".dropdown-menu",C=".navbar-nav",I=".dropdown-menu .dropdown-item:not(.disabled)",A="top-start",b="top-end",D="bottom-start",S="bottom-end",w="right-start",N="left-start",O={offset:0,flip:!0,boundary:"scrollParent"},k={offset:"(number|string|function)",flip:"boolean",boundary:"(string|element)"},L=function(){function a(t,e){this._element=t,this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar(),this._addEventListeners()}var l=a.prototype;return l.toggle=function(){if(!this._element.disabled&&!t(this._element).hasClass(u)){var e=a._getParentFromElement(this._element),i=t(this._menu).hasClass(f);if(a._clearMenus(),!i){var s={relatedTarget:this._element},r=t.Event(c.SHOW,s);if(t(e).trigger(r),!r.isDefaultPrevented()){if(!this._inNavbar){if("undefined"==typeof n)throw new TypeError("Bootstrap dropdown require Popper.js (https://popper.js.org)");var o=this._element;t(e).hasClass(d)&&(t(this._menu).hasClass(m)||t(this._menu).hasClass(p))&&(o=e),"scrollParent"!==this._config.boundary&&t(e).addClass(v),this._popper=new n(o,this._menu,this._getPopperConfig())}"ontouchstart"in document.documentElement&&0===t(e).closest(C).length&&t("body").children().on("mouseover",null,t.noop),this._element.focus(),this._element.setAttribute("aria-expanded",!0),t(this._menu).toggleClass(f),t(e).toggleClass(f).trigger(t.Event(c.SHOWN,s))}}}},l.dispose=function(){t.removeData(this._element,i),t(this._element).off(o),this._element=null,this._menu=null,null!==this._popper&&(this._popper.destroy(),this._popper=null)},l.update=function(){this._inNavbar=this._detectNavbar(),null!==this._popper&&this._popper.scheduleUpdate()},l._addEventListeners=function(){var e=this;t(this._element).on(c.CLICK,function(t){t.preventDefault(),t.stopPropagation(),e.toggle()})},l._getConfig=function(n){return n=r({},this.constructor.Default,t(this._element).data(),n),P.typeCheckConfig(e,n,this.constructor.DefaultType),n},l._getMenuElement=function(){if(!this._menu){var e=a._getParentFromElement(this._element);this._menu=t(e).find(y)[0]}return this._menu},l._getPlacement=function(){var e=t(this._element).parent(),n=D;return e.hasClass(d)?(n=A,t(this._menu).hasClass(p)&&(n=b)):e.hasClass(_)?n=w:e.hasClass(g)?n=N:t(this._menu).hasClass(p)&&(n=S),n},l._detectNavbar=function(){return t(this._element).closest(".navbar").length>0},l._getPopperConfig=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets)||{}),e}:e.offset=this._config.offset,{placement:this._getPlacement(),modifiers:{offset:e,flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}}},a._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(i);if(n||(n=new a(this,"object"==typeof e?e:null),t(this).data(i,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}})},a._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=t.makeArray(t(E)),s=0;s0&&r--,40===e.which&&rdocument.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},p._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},p._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=t.left+t.right
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent"},f="show",d="out",_={HIDE:"hide"+o,HIDDEN:"hidden"+o,SHOW:"show"+o,SHOWN:"shown"+o,INSERTED:"inserted"+o,CLICK:"click"+o,FOCUSIN:"focusin"+o,FOCUSOUT:"focusout"+o,MOUSEENTER:"mouseenter"+o,MOUSELEAVE:"mouseleave"+o},g="fade",p="show",m=".tooltip-inner",v=".arrow",E="hover",T="focus",y="click",C="manual",I=function(){function a(t,e){if("undefined"==typeof n)throw new TypeError("Bootstrap tooltips require Popper.js (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var I=a.prototype;return I.enable=function(){this._isEnabled=!0},I.disable=function(){this._isEnabled=!1},I.toggleEnabled=function(){this._isEnabled=!this._isEnabled},I.toggle=function(e){if(this._isEnabled)if(e){var n=this.constructor.DATA_KEY,i=t(e.currentTarget).data(n);i||(i=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(n,i)),i._activeTrigger.click=!i._activeTrigger.click,i._isWithActiveTrigger()?i._enter(null,i):i._leave(null,i)}else{if(t(this.getTipElement()).hasClass(p))return void this._leave(null,this);this._enter(null,this)}},I.dispose=function(){clearTimeout(this._timeout),t.removeData(this.element,this.constructor.DATA_KEY),t(this.element).off(this.constructor.EVENT_KEY),t(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&t(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,null!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},I.show=function(){var e=this;if("none"===t(this.element).css("display"))throw new Error("Please use show on visible elements");var i=t.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){t(this.element).trigger(i);var s=t.contains(this.element.ownerDocument.documentElement,this.element);if(i.isDefaultPrevented()||!s)return;var r=this.getTipElement(),o=P.getUID(this.constructor.NAME);r.setAttribute("id",o),this.element.setAttribute("aria-describedby",o),this.setContent(),this.config.animation&&t(r).addClass(g);var l="function"==typeof this.config.placement?this.config.placement.call(this,r,this.element):this.config.placement,h=this._getAttachment(l);this.addAttachmentClass(h);var c=!1===this.config.container?document.body:t(this.config.container);t(r).data(this.constructor.DATA_KEY,this),t.contains(this.element.ownerDocument.documentElement,this.tip)||t(r).appendTo(c),t(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new n(this.element,r,{placement:h,modifiers:{offset:{offset:this.config.offset},flip:{behavior:this.config.fallbackPlacement},arrow:{element:v},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){e._handlePopperPlacementChange(t)}}),t(r).addClass(p),"ontouchstart"in document.documentElement&&t("body").children().on("mouseover",null,t.noop);var u=function(){e.config.animation&&e._fixTransition();var n=e._hoverState;e._hoverState=null,t(e.element).trigger(e.constructor.Event.SHOWN),n===d&&e._leave(null,e)};P.supportsTransitionEnd()&&t(this.tip).hasClass(g)?t(this.tip).one(P.TRANSITION_END,u).emulateTransitionEnd(a._TRANSITION_DURATION):u()}},I.hide=function(e){var n=this,i=this.getTipElement(),s=t.Event(this.constructor.Event.HIDE),r=function(){n._hoverState!==f&&i.parentNode&&i.parentNode.removeChild(i),n._cleanTipClass(),n.element.removeAttribute("aria-describedby"),t(n.element).trigger(n.constructor.Event.HIDDEN),null!==n._popper&&n._popper.destroy(),e&&e()};t(this.element).trigger(s),s.isDefaultPrevented()||(t(i).removeClass(p),"ontouchstart"in document.documentElement&&t("body").children().off("mouseover",null,t.noop),this._activeTrigger[y]=!1,this._activeTrigger[T]=!1,this._activeTrigger[E]=!1,P.supportsTransitionEnd()&&t(this.tip).hasClass(g)?t(i).one(P.TRANSITION_END,r).emulateTransitionEnd(150):r(),this._hoverState="")},I.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},I.isWithContent=function(){return Boolean(this.getTitle())},I.addAttachmentClass=function(e){t(this.getTipElement()).addClass("bs-tooltip-"+e)},I.getTipElement=function(){return this.tip=this.tip||t(this.config.template)[0],this.tip},I.setContent=function(){var e=t(this.getTipElement());this.setElementContent(e.find(m),this.getTitle()),e.removeClass(g+" "+p)},I.setElementContent=function(e,n){var i=this.config.html;"object"==typeof n&&(n.nodeType||n.jquery)?i?t(n).parent().is(e)||e.empty().append(n):e.text(t(n).text()):e[i?"html":"text"](n)},I.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},I._getAttachment=function(t){return c[t.toUpperCase()]},I._setListeners=function(){var e=this;this.config.trigger.split(" ").forEach(function(n){if("click"===n)t(e.element).on(e.constructor.Event.CLICK,e.config.selector,function(t){return e.toggle(t)});else if(n!==C){var i=n===E?e.constructor.Event.MOUSEENTER:e.constructor.Event.FOCUSIN,s=n===E?e.constructor.Event.MOUSELEAVE:e.constructor.Event.FOCUSOUT;t(e.element).on(i,e.config.selector,function(t){return e._enter(t)}).on(s,e.config.selector,function(t){return e._leave(t)})}t(e.element).closest(".modal").on("hide.bs.modal",function(){return e.hide()})}),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},I._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},I._enter=function(e,n){var i=this.constructor.DATA_KEY;(n=n||t(e.currentTarget).data(i))||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(i,n)),e&&(n._activeTrigger["focusin"===e.type?T:E]=!0),t(n.getTipElement()).hasClass(p)||n._hoverState===f?n._hoverState=f:(clearTimeout(n._timeout),n._hoverState=f,n.config.delay&&n.config.delay.show?n._timeout=setTimeout(function(){n._hoverState===f&&n.show()},n.config.delay.show):n.show())},I._leave=function(e,n){var i=this.constructor.DATA_KEY;(n=n||t(e.currentTarget).data(i))||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(i,n)),e&&(n._activeTrigger["focusout"===e.type?T:E]=!1),n._isWithActiveTrigger()||(clearTimeout(n._timeout),n._hoverState=d,n.config.delay&&n.config.delay.hide?n._timeout=setTimeout(function(){n._hoverState===d&&n.hide()},n.config.delay.hide):n.hide())},I._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},I._getConfig=function(n){return"number"==typeof(n=r({},this.constructor.Default,t(this.element).data(),n)).delay&&(n.delay={show:n.delay,hide:n.delay}),"number"==typeof n.title&&(n.title=n.title.toString()),"number"==typeof n.content&&(n.content=n.content.toString()),P.typeCheckConfig(e,n,this.constructor.DefaultType),n},I._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},I._cleanTipClass=function(){var e=t(this.getTipElement()),n=e.attr("class").match(l);null!==n&&n.length>0&&e.removeClass(n.join(""))},I._handlePopperPlacementChange=function(t){this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},I._fixTransition=function(){var e=this.getTipElement(),n=this.config.animation;null===e.getAttribute("x-placement")&&(t(e).removeClass(g),this.config.animation=!1,this.hide(),this.show(),this.config.animation=n)},a._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(i),s="object"==typeof e&&e;if((n||!/dispose|hide/.test(e))&&(n||(n=new a(this,s),t(this).data(i,n)),"string"==typeof e)){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}})},s(a,null,[{key:"VERSION",get:function(){return"4.0.0"}},{key:"Default",get:function(){return u}},{key:"NAME",get:function(){return e}},{key:"DATA_KEY",get:function(){return i}},{key:"Event",get:function(){return _}},{key:"EVENT_KEY",get:function(){return o}},{key:"DefaultType",get:function(){return h}}]),a}();return t.fn[e]=I._jQueryInterface,t.fn[e].Constructor=I,t.fn[e].noConflict=function(){return t.fn[e]=a,I._jQueryInterface},I}(e),x=function(t){var e="popover",n="bs.popover",i="."+n,o=t.fn[e],a=new RegExp("(^|\\s)bs-popover\\S+","g"),l=r({},U.Default,{placement:"right",trigger:"click",content:"",template:''}),h=r({},U.DefaultType,{content:"(string|element|function)"}),c="fade",u="show",f=".popover-header",d=".popover-body",_={HIDE:"hide"+i,HIDDEN:"hidden"+i,SHOW:"show"+i,SHOWN:"shown"+i,INSERTED:"inserted"+i,CLICK:"click"+i,FOCUSIN:"focusin"+i,FOCUSOUT:"focusout"+i,MOUSEENTER:"mouseenter"+i,MOUSELEAVE:"mouseleave"+i},g=function(r){var o,g;function p(){return r.apply(this,arguments)||this}g=r,(o=p).prototype=Object.create(g.prototype),o.prototype.constructor=o,o.__proto__=g;var m=p.prototype;return m.isWithContent=function(){return this.getTitle()||this._getContent()},m.addAttachmentClass=function(e){t(this.getTipElement()).addClass("bs-popover-"+e)},m.getTipElement=function(){return this.tip=this.tip||t(this.config.template)[0],this.tip},m.setContent=function(){var e=t(this.getTipElement());this.setElementContent(e.find(f),this.getTitle());var n=this._getContent();"function"==typeof n&&(n=n.call(this.element)),this.setElementContent(e.find(d),n),e.removeClass(c+" "+u)},m._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},m._cleanTipClass=function(){var e=t(this.getTipElement()),n=e.attr("class").match(a);null!==n&&n.length>0&&e.removeClass(n.join(""))},p._jQueryInterface=function(e){return this.each(function(){var i=t(this).data(n),s="object"==typeof e?e:null;if((i||!/destroy|hide/.test(e))&&(i||(i=new p(this,s),t(this).data(n,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}})},s(p,null,[{key:"VERSION",get:function(){return"4.0.0"}},{key:"Default",get:function(){return l}},{key:"NAME",get:function(){return e}},{key:"DATA_KEY",get:function(){return n}},{key:"Event",get:function(){return _}},{key:"EVENT_KEY",get:function(){return i}},{key:"DefaultType",get:function(){return h}}]),p}(U);return t.fn[e]=g._jQueryInterface,t.fn[e].Constructor=g,t.fn[e].noConflict=function(){return t.fn[e]=o,g._jQueryInterface},g}(e),K=function(t){var e="scrollspy",n="bs.scrollspy",i="."+n,o=t.fn[e],a={offset:10,method:"auto",target:""},l={offset:"number",method:"string",target:"(string|element)"},h={ACTIVATE:"activate"+i,SCROLL:"scroll"+i,LOAD_DATA_API:"load"+i+".data-api"},c="dropdown-item",u="active",f={DATA_SPY:'[data-spy="scroll"]',ACTIVE:".active",NAV_LIST_GROUP:".nav, .list-group",NAV_LINKS:".nav-link",NAV_ITEMS:".nav-item",LIST_ITEMS:".list-group-item",DROPDOWN:".dropdown",DROPDOWN_ITEMS:".dropdown-item",DROPDOWN_TOGGLE:".dropdown-toggle"},d="offset",_="position",g=function(){function o(e,n){var i=this;this._element=e,this._scrollElement="BODY"===e.tagName?window:e,this._config=this._getConfig(n),this._selector=this._config.target+" "+f.NAV_LINKS+","+this._config.target+" "+f.LIST_ITEMS+","+this._config.target+" "+f.DROPDOWN_ITEMS,this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,t(this._scrollElement).on(h.SCROLL,function(t){return i._process(t)}),this.refresh(),this._process()}var g=o.prototype;return g.refresh=function(){var e=this,n=this._scrollElement===this._scrollElement.window?d:_,i="auto"===this._config.method?n:this._config.method,s=i===_?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),t.makeArray(t(this._selector)).map(function(e){var n,r=P.getSelectorFromElement(e);if(r&&(n=t(r)[0]),n){var o=n.getBoundingClientRect();if(o.width||o.height)return[t(n)[i]().top+s,r]}return null}).filter(function(t){return t}).sort(function(t,e){return t[0]-e[0]}).forEach(function(t){e._offsets.push(t[0]),e._targets.push(t[1])})},g.dispose=function(){t.removeData(this._element,n),t(this._scrollElement).off(i),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},g._getConfig=function(n){if("string"!=typeof(n=r({},a,n)).target){var i=t(n.target).attr("id");i||(i=P.getUID(e),t(n.target).attr("id",i)),n.target="#"+i}return P.typeCheckConfig(e,n,l),n},g._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},g._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},g._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},g._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var s=this._offsets.length;s--;){this._activeTarget!==this._targets[s]&&t>=this._offsets[s]&&("undefined"==typeof this._offsets[s+1]||t=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}(e),t.Util=P,t.Alert=L,t.Button=R,t.Carousel=j,t.Collapse=H,t.Dropdown=W,t.Modal=M,t.Popover=x,t.Scrollspy=K,t.Tab=V,t.Tooltip=U,Object.defineProperty(t,"__esModule",{value:!0})}); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/chrome-extension/js/jquery-3.4.1.min.js b/chrome-extension/js/jquery-3.4.1.min.js new file mode 100644 index 0000000..a1c07fd --- /dev/null +++ b/chrome-extension/js/jquery-3.4.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0window.devicePixelRatio||!re),h='bottom'===o?'top':'bottom',g='right'===n?'left':'right',u=K('transform');if(s='bottom'==h?'HTML'===a.nodeName?-a.clientHeight+m.bottom:-l.height+m.bottom:m.top,p='right'==g?'HTML'===a.nodeName?-a.clientWidth+m.right:-l.width+m.right:m.left,d&&u)f[u]='translate3d('+p+'px, '+s+'px, 0)',f[h]=0,f[g]=0,f.willChange='transform';else{var b='bottom'==h?-1:1,w='right'==g?-1:1;f[h]=s*b,f[g]=p*w,f.willChange=h+', '+g}var y={"x-placement":e.placement};return e.attributes=T({},y,e.attributes),e.styles=T({},f,e.styles),e.arrowStyles=T({},e.offsets.arrow,e.arrowStyles),e}function se(e,t,o){var n=U(e,function(e){var o=e.name;return o===t}),i=!!n&&e.some(function(e){return e.name===o&&e.enabled&&e.orderp[c]&&(e.offsets.popper[m]+=d[m]+g-p[c]),e.offsets.popper=C(e.offsets.popper);var u=d[m]+d[l]/2-g/2,b=s(e.instance.popper),w=parseFloat(b['margin'+f]),y=parseFloat(b['border'+f+'Width']),E=u-e.offsets.popper[m]-w-y;return E=Math.max(Math.min(p[l]-g,E),0),e.arrowElement=n,e.offsets.arrow=(o={},S(o,m,Math.round(E)),S(o,h,''),o),e}function ae(e){if('end'===e)return'start';return'start'===e?'end':e}var le=['auto-start','auto','auto-end','top-start','top','top-end','right-start','right','right-end','bottom-end','bottom','bottom-start','left-end','left','left-start'],fe=le.slice(3);function me(e){var t=1f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),x=y||E;(m||b||x)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),x&&(r=ae(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=T({},e.offsets.popper,R(e.instance.popper,e.offsets.reference,e.placement)),e=V(e.instance.modifiers,e,'flip'))}),e}function ge(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Math.floor,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}function ue(e,t,o,n){var i=Math.max,r=e.match(/((?:\-|\+)?\d*\.?\d*)(.*)/),p=+r[1],s=r[2];if(!p)return e;if(0===s.indexOf('%')){var d;switch(s){case'%p':d=o;break;case'%':case'%r':default:d=n;}var a=C(d);return a[t]/100*p}if('vh'===s||'vw'===s){var l;return l='vh'===s?i(document.documentElement.clientHeight,window.innerHeight||0):i(document.documentElement.clientWidth,window.innerWidth||0),l/100*p}return p}function be(e,t,o,n){var i=[0,0],r=-1!==['right','left'].indexOf(n),p=e.split(/(\+|\-)/).map(function(e){return e.trim()}),s=p.indexOf(U(p,function(e){return-1!==e.search(/,|\s/)}));p[s]&&-1===p[s].indexOf(',')&&console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');var d=/\s*,\s*|\s+/,a=-1===s?[p]:[p.slice(0,s).concat([p[s].split(d)[0]]),[p[s].split(d)[1]].concat(p.slice(s+1))];return a=a.map(function(e,n){var i=(1===n?!r:r)?'height':'width',p=!1;return e.reduce(function(e,t){return''===e[e.length-1]&&-1!==['+','-'].indexOf(t)?(e[e.length-1]=t,p=!0,e):p?(e[e.length-1]+=t,p=!1,e):e.concat(t)},[]).map(function(e){return ue(e,i,t,o)})}),a.forEach(function(e,t){e.forEach(function(o,n){$(o)&&(i[t]+=o*('-'===e[n-1]?-1:1))})}),i}function we(e,t){var o,n=t.offset,i=e.placement,r=e.offsets,p=r.popper,s=r.reference,d=i.split('-')[0];return o=$(+n)?[+n,0]:be(n,p,s,d),'left'===d?(p.top+=o[0],p.left-=o[1]):'right'===d?(p.top+=o[0],p.left+=o[1]):'top'===d?(p.left+=o[0],p.top-=o[1]):'bottom'===d&&(p.left+=o[0],p.top+=o[1]),e.popper=p,e}function ye(e,t){var o=t.boundariesElement||c(e.instance.popper);e.instance.reference===o&&(o=c(o));var n=K('transform'),i=e.instance.popper.style,r=i.top,p=i.left,s=i[n];i.top='',i.left='',i[n]='';var d=B(e.instance.popper,e.instance.reference,t.padding,o,e.positionFixed);i.top=r,i.left=p,i[n]=s,t.boundaries=d;var a=t.priority,l=e.offsets.popper,f={primary:function(e){var o=l[e];return l[e]d[e]&&!t.escapeWithReference&&(n=Math.min(l[o],d[e]-('right'===e?l.width:l.height))),S({},o,n)}};return a.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';l=T({},l,f[t](e))}),e.offsets.popper=l,e}function Ee(e){var t=e.placement,o=t.split('-')[0],n=t.split('-')[1];if(n){var i=e.offsets,r=i.reference,p=i.popper,s=-1!==['bottom','top'].indexOf(o),d=s?'left':'top',a=s?'width':'height',l={start:S({},d,r[d]),end:S({},d,r[d]+r[a]-p[a])};e.offsets.popper=T({},p,l[n])}return e}function xe(e){if(!se(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=U(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.right -YoutubeDL-Material Extension Options + + YoutubeDL-Material Extension Options + + + + + + + +

Settings

-
-

Frontend URL

- +
+
+ + +
+ +
+ +
+ +
+ + +
+
+ Settings successfully saved! +
+
-
- -
- -
- -
- -
- - \ No newline at end of file diff --git a/chrome-extension/options.js b/chrome-extension/options.js index 78597b0..c4da699 100644 --- a/chrome-extension/options.js +++ b/chrome-extension/options.js @@ -7,11 +7,10 @@ function save_options() { audio_only: audio_only }, function() { // Update status to let user know options were saved. - var status = document.getElementById('status'); - status.textContent = 'Options saved.'; + $('#collapseExample').collapse('show'); setTimeout(function() { - status.textContent = ''; - }, 750); + $('#collapseExample').collapse('hide'); + }, 2000); }); } From 18371010835fa681b6466293983a0cde4c54c58d Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 18:15:17 -0400 Subject: [PATCH 31/38] Updated manifest --- chrome-extension/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chrome-extension/manifest.json b/chrome-extension/manifest.json index 02adf1e..1ecf992 100644 --- a/chrome-extension/manifest.json +++ b/chrome-extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "YoutubeDL-Material", - "version": "0.2", + "version": "0.3", "description": "The Official Firefox & Chrome Extension of YoutubeDL-Material, an open-source and self-hosted YouTube downloader.", "background": { "scripts": ["background.js"] From 35f8454db35efd1f1f2d6d0e146a4848c8f948e7 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 18:20:25 -0400 Subject: [PATCH 32/38] Fixed bug where auto started downloads would begin if navigated back from the player --- src/app/main/main.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/main/main.component.ts b/src/app/main/main.component.ts index 73ca33e..9103fa1 100644 --- a/src/app/main/main.component.ts +++ b/src/app/main/main.component.ts @@ -477,7 +477,7 @@ export class MainComponent implements OnInit { this.downloadAudioFile(decodeURI(name)); } } else { - localStorage.setItem('player_navigator', this.router.url); + localStorage.setItem('player_navigator', this.router.url.split(';')[0]); if (is_playlist) { this.router.navigate(['/player', {fileNames: name.join('|nvr|'), type: 'audio'}]); } else { @@ -515,7 +515,7 @@ export class MainComponent implements OnInit { this.downloadVideoFile(decodeURI(name)); } } else { - localStorage.setItem('player_navigator', this.router.url); + localStorage.setItem('player_navigator', this.router.url.split(';')[0]); if (is_playlist) { this.router.navigate(['/player', {fileNames: name.join('|nvr|'), type: 'video'}]); } else { From 393267b9195d665e10f45d31a8e26068514ab0c1 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 18:49:19 -0400 Subject: [PATCH 33/38] fixed bug where youtube search API failed to load when enabled through the settings --- src/app/settings/settings.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/settings/settings.component.html b/src/app/settings/settings.component.html index 8c0135d..b4f8b3b 100644 --- a/src/app/settings/settings.component.html +++ b/src/app/settings/settings.component.html @@ -143,11 +143,11 @@
- Use YouTube API + Use YouTube API
From b2730926c82c6294fed0172cf91bd9e225cfbd1c Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 21:38:49 -0400 Subject: [PATCH 34/38] Updated translation details to improve clarity Added upload date property to files in UI Subscription videos can now be filtered by some of their properties (size, upload date, name, duration) Subscription videos are now centered --- backend/app.js | 21 ++++-- .../video-info-dialog.component.html | 14 ++-- src/app/file-card/file-card.component.html | 2 +- src/app/file-card/file-card.component.ts | 5 +- .../subscription-file-card.component.ts | 3 +- .../subscription/subscription.component.html | 66 +++++++++++-------- .../subscription/subscription.component.scss | 8 +++ .../subscription/subscription.component.ts | 50 ++++++++++++++ 8 files changed, 128 insertions(+), 41 deletions(-) diff --git a/backend/app.js b/backend/app.js index 3fdd32c..9fbecb9 100644 --- a/backend/app.js +++ b/backend/app.js @@ -84,7 +84,7 @@ app.use(bodyParser.json()); // objects -function File(id, title, thumbnailURL, isAudio, duration, url = null, uploader = null, size = null, path = null) { +function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date) { this.id = id; this.title = title; this.thumbnailURL = thumbnailURL; @@ -94,6 +94,7 @@ function File(id, title, thumbnailURL, isAudio, duration, url = null, uploader = this.uploader = uploader; this.size = size; this.path = path; + this.upload_date = upload_date; } // actual functions @@ -964,12 +965,15 @@ app.post('/api/getMp3s', function(req, res) { var title = jsonobj.title; var url = jsonobj.webpage_url; var uploader = jsonobj.uploader; + var upload_date = jsonobj.upload_date; + upload_date = `${upload_date.substring(0, 4)}-${upload_date.substring(4, 6)}-${upload_date.substring(6, 8)}`; + var size = stats.size; var thumbnail = jsonobj.thumbnail; var duration = jsonobj.duration; var isaudio = true; - var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file); + var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file, upload_date); mp3s.push(file_obj); } @@ -998,12 +1002,15 @@ app.post('/api/getMp4s', function(req, res) { var title = jsonobj.title; var url = jsonobj.webpage_url; var uploader = jsonobj.uploader; - var size = stats.size; - + var upload_date = jsonobj.upload_date; + upload_date = `${upload_date.substring(0, 4)}-${upload_date.substring(4, 6)}-${upload_date.substring(6, 8)}`; var thumbnail = jsonobj.thumbnail; var duration = jsonobj.duration; + + var size = stats.size; + var isaudio = false; - var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file); + var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file, upload_date); mp4s.push(file_obj); } @@ -1118,10 +1125,12 @@ app.post('/api/getSubscription', async (req, res) => { var duration = jsonobj.duration; var url = jsonobj.webpage_url; var uploader = jsonobj.uploader; + var upload_date = jsonobj.upload_date; + upload_date = `${upload_date.substring(0, 4)}-${upload_date.substring(4, 6)}-${upload_date.substring(6, 8)}`; var size = stats.size; var isaudio = false; - var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file); + var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file, upload_date); parsed_files.push(file_obj); } diff --git a/src/app/dialogs/video-info-dialog/video-info-dialog.component.html b/src/app/dialogs/video-info-dialog/video-info-dialog.component.html index 234b77d..0c0c105 100644 --- a/src/app/dialogs/video-info-dialog/video-info-dialog.component.html +++ b/src/app/dialogs/video-info-dialog/video-info-dialog.component.html @@ -2,25 +2,29 @@
-
Name: 
+
Name: 
{{file.title}}
-
URL: 
+
URL: 
-
Uploader: 
+
Uploader: 
{{file.uploader ? file.uploader : 'N/A'}}
-
File size: 
+
File size: 
{{filesize(file.size)}}
-
Path: 
+
Path: 
{{file.path}}
+
+
Upload Date: 
+
{{file.upload_date}}
+
diff --git a/src/app/file-card/file-card.component.html b/src/app/file-card/file-card.component.html index fd4317d..ef79cf6 100644 --- a/src/app/file-card/file-card.component.html +++ b/src/app/file-card/file-card.component.html @@ -19,7 +19,7 @@ - + diff --git a/src/app/file-card/file-card.component.ts b/src/app/file-card/file-card.component.ts index 1c896c2..16f33ed 100644 --- a/src/app/file-card/file-card.component.ts +++ b/src/app/file-card/file-card.component.ts @@ -61,11 +61,12 @@ export class FileCardComponent implements OnInit { } - openSubscriptionInfoDialog() { + openVideoInfoDialog() { const dialogRef = this.dialog.open(VideoInfoDialogComponent, { data: { file: this.file, - } + }, + minWidth: '50vw' }); } diff --git a/src/app/subscription/subscription-file-card/subscription-file-card.component.ts b/src/app/subscription/subscription-file-card/subscription-file-card.component.ts index 6c9b3b7..093eb94 100644 --- a/src/app/subscription/subscription-file-card/subscription-file-card.component.ts +++ b/src/app/subscription/subscription-file-card/subscription-file-card.component.ts @@ -61,7 +61,8 @@ export class SubscriptionFileCardComponent implements OnInit { const dialogRef = this.dialog.open(VideoInfoDialogComponent, { data: { file: this.file, - } + }, + minWidth: '50vw' }); } diff --git a/src/app/subscription/subscription/subscription.component.html b/src/app/subscription/subscription/subscription.component.html index d94a0a4..86ece5a 100644 --- a/src/app/subscription/subscription/subscription.component.html +++ b/src/app/subscription/subscription/subscription.component.html @@ -1,30 +1,44 @@ -
- -
-

- {{subscription.name}} -

-
- -
- -
-
-
-
-

Videos

-
-
- - - search - -
+
+ +
+

+ {{subscription.name}} +

-
-
-
- + +
+ +
+
+
+
+ + + {{filterOption['value']['label']}} + + +
+
+ +
+
+
+
+
+

Videos

+
+
+ + + search + +
+
+
+
+
+ +
diff --git a/src/app/subscription/subscription/subscription.component.scss b/src/app/subscription/subscription/subscription.component.scss index 10557a0..a9c26bb 100644 --- a/src/app/subscription/subscription/subscription.component.scss +++ b/src/app/subscription/subscription/subscription.component.scss @@ -8,6 +8,13 @@ left: 15px; } +.filter-select-parent { + position: absolute; + top: 0px; + left: 20px; + display: block; +} + .search-bar { transition: all .5s ease; position: relative; @@ -29,6 +36,7 @@ .flex-grid { width: 100%; display: block; + position: relative; } .col { width: 33%; diff --git a/src/app/subscription/subscription/subscription.component.ts b/src/app/subscription/subscription/subscription.component.ts index 0bcf008..f9ff060 100644 --- a/src/app/subscription/subscription/subscription.component.ts +++ b/src/app/subscription/subscription/subscription.component.ts @@ -17,6 +17,30 @@ export class SubscriptionComponent implements OnInit { search_mode = false; search_text = ''; searchIsFocused = false; + descendingMode = true; + filterProperties = { + 'upload_date': { + 'key': 'upload_date', + 'label': 'Upload Date', + 'property': 'upload_date' + }, + 'name': { + 'key': 'name', + 'label': 'Name', + 'property': 'title' + }, + 'file_size': { + 'key': 'file_size', + 'label': 'File Size', + 'property': 'size' + }, + 'duration': { + 'key': 'duration', + 'label': 'Duration', + 'property': 'duration' + } + }; + filterProperty = this.filterProperties['upload_date']; constructor(private postsService: PostsService, private route: ActivatedRoute, private router: Router) { } @@ -27,6 +51,12 @@ export class SubscriptionComponent implements OnInit { this.getSubscription(); this.getConfig(); } + + // set filter property to cached + const cached_filter_property = localStorage.getItem('filter_property'); + if (cached_filter_property && this.filterProperties[cached_filter_property]) { + this.filterProperty = this.filterProperties[cached_filter_property]; + } } goBack() { @@ -42,6 +72,7 @@ export class SubscriptionComponent implements OnInit { } else { this.filtered_files = this.files; } + this.filterByProperty(this.filterProperty['property']); }); } @@ -72,4 +103,23 @@ export class SubscriptionComponent implements OnInit { this.filtered_files = this.files.filter(option => option.id.toLowerCase().includes(filterValue)); } + filterByProperty(prop) { + if (this.descendingMode) { + this.filtered_files = this.filtered_files.sort((a, b) => (a[prop] > b[prop] ? -1 : 1)); + } else { + this.filtered_files = this.filtered_files.sort((a, b) => (a[prop] > b[prop] ? 1 : -1)); + } + } + + filterOptionChanged(value) { + // this.filterProperty = value; + this.filterByProperty(value['property']); + localStorage.setItem('filter_property', value['key']); + } + + toggleModeChange() { + this.descendingMode = !this.descendingMode; + this.filterByProperty(this.filterProperty['property']); + } + } From bdb6a082745c999690338fca26b6b64289e69390 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 22:24:52 -0400 Subject: [PATCH 35/38] Added ability to download subscription videos as zip --- backend/app.js | 37 +++++++++++++------ src/app/posts.services.ts | 7 ++-- .../subscription/subscription.component.html | 1 + .../subscription/subscription.component.scss | 20 ++++++++++ .../subscription/subscription.component.ts | 18 +++++++++ 5 files changed, 69 insertions(+), 14 deletions(-) diff --git a/backend/app.js b/backend/app.js index 9fbecb9..a02a6cd 100644 --- a/backend/app.js +++ b/backend/app.js @@ -358,10 +358,16 @@ function getVideoFormatID(name) } } -async function createPlaylistZipFile(fileNames, type, outputName) { +async function createPlaylistZipFile(fileNames, type, outputName, fullPathProvided = null) { return new Promise(async resolve => { - let zipFolderPath = path.join(__dirname, (type === 'audio') ? audioFolderPath : videoFolderPath); - // let name = fileNames[0].split(' ')[0] + fileNames[1].split(' ')[0]; + let zipFolderPath = null; + + if (!fullPathProvided) { + zipFolderPath = path.join(__dirname, (type === 'audio') ? audioFolderPath : videoFolderPath); + } else { + zipFolderPath = path.join(__dirname, config_api.getConfigItem('ytdl_subscriptions_base_path')); + } + let ext = (type === 'audio') ? '.mp3' : '.mp4'; let output = fs.createWriteStream(path.join(zipFolderPath, outputName + '.zip')); @@ -381,7 +387,8 @@ async function createPlaylistZipFile(fileNames, type, outputName) { for (let i = 0; i < fileNames.length; i++) { let fileName = fileNames[i]; - archive.file(zipFolderPath + fileName + ext, {name: fileName + ext}) + let file_path = !fullPathProvided ? zipFolderPath + fileName + ext : fileName; + archive.file(file_path, {name: fileName + ext}) } await archive.finalize(); @@ -1141,9 +1148,6 @@ app.post('/api/getSubscription', async (req, res) => { } else { res.sendStatus(500); } - - - }); app.post('/api/downloadVideosForSubscription', async (req, res) => { @@ -1278,11 +1282,12 @@ app.post('/api/deleteMp4', async (req, res) => { app.post('/api/downloadFile', async (req, res) => { let fileNames = req.body.fileNames; - let is_playlist = req.body.is_playlist; + let zip_mode = req.body.zip_mode; let type = req.body.type; let outputName = req.body.outputName; + let fullPathProvided = req.body.fullPathProvided; let file = null; - if (!is_playlist) { + if (!zip_mode) { fileNames = decodeURIComponent(fileNames); if (type === 'audio') { file = __dirname + '/' + audioFolderPath + fileNames + '.mp3'; @@ -1293,10 +1298,20 @@ app.post('/api/downloadFile', async (req, res) => { for (let i = 0; i < fileNames.length; i++) { fileNames[i] = decodeURIComponent(fileNames[i]); } - file = await createPlaylistZipFile(fileNames, type, outputName); + file = await createPlaylistZipFile(fileNames, type, outputName, fullPathProvided); } - res.sendFile(file); + res.sendFile(file, function (err) { + if (err) { + next(err); + } else if (fullPathProvided) { + try { + fs.unlinkSync(file); + } catch(e) { + console.log("ERROR: Failed to remove file", file); + } + } + }); }); app.post('/api/deleteFile', async (req, res) => { diff --git a/src/app/posts.services.ts b/src/app/posts.services.ts index 6ea4133..97b63de 100644 --- a/src/app/posts.services.ts +++ b/src/app/posts.services.ts @@ -114,11 +114,12 @@ export class PostsService { return this.http.post(this.path + 'getMp4s', {}); } - downloadFileFromServer(fileName, type, outputName = null) { + downloadFileFromServer(fileName, type, outputName = null, fullPathProvided = null) { return this.http.post(this.path + 'downloadFile', {fileNames: fileName, type: type, - is_playlist: Array.isArray(fileName), - outputName: outputName}, + zip_mode: Array.isArray(fileName), + outputName: outputName, + fullPathProvided: fullPathProvided}, {responseType: 'blob'}); } diff --git a/src/app/subscription/subscription/subscription.component.html b/src/app/subscription/subscription/subscription.component.html index 86ece5a..44ccb41 100644 --- a/src/app/subscription/subscription/subscription.component.html +++ b/src/app/subscription/subscription/subscription.component.html @@ -42,4 +42,5 @@
+
\ No newline at end of file diff --git a/src/app/subscription/subscription/subscription.component.scss b/src/app/subscription/subscription/subscription.component.scss index a9c26bb..7734644 100644 --- a/src/app/subscription/subscription/subscription.component.scss +++ b/src/app/subscription/subscription/subscription.component.scss @@ -38,7 +38,27 @@ display: block; position: relative; } + .col { width: 33%; display: inline-block; +} + +.spinner { + width: 50px; + height: 50px; + bottom: 3px; + left: 3px; + position: absolute; +} + +.save-button { + right: 25px; + position: absolute; + bottom: 25px; +} + +.save-icon { + bottom: 1px; + position: relative; } \ No newline at end of file diff --git a/src/app/subscription/subscription/subscription.component.ts b/src/app/subscription/subscription/subscription.component.ts index f9ff060..496f2d1 100644 --- a/src/app/subscription/subscription/subscription.component.ts +++ b/src/app/subscription/subscription/subscription.component.ts @@ -41,6 +41,7 @@ export class SubscriptionComponent implements OnInit { } }; filterProperty = this.filterProperties['upload_date']; + downloading = false; constructor(private postsService: PostsService, private route: ActivatedRoute, private router: Router) { } @@ -122,4 +123,21 @@ export class SubscriptionComponent implements OnInit { this.filterByProperty(this.filterProperty['property']); } + downloadContent() { + const fileNames = []; + for (let i = 0; i < this.files.length; i++) { + fileNames.push(this.files[i].path); + } + + this.downloading = true; + this.postsService.downloadFileFromServer(fileNames, 'video', this.subscription.name, true).subscribe(res => { + this.downloading = false; + const blob: Blob = res; + saveAs(blob, this.subscription.name + '.zip'); + }, err => { + console.log(err); + this.downloading = false; + }); + } + } From b987e258b5071497fb7d1731069d4cd81e5ab1ed Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Tue, 17 Mar 2020 22:25:21 -0400 Subject: [PATCH 36/38] Updated firefox extension zip --- .../youtubedl-material-firefox-extension.zip | Bin 4487 -> 75374 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/chrome-extension/youtubedl-material-firefox-extension.zip b/chrome-extension/youtubedl-material-firefox-extension.zip index 54d612014896cbd2020c5353c08f04981dc8ca6e..ebf34b89dfea500c4c9ffeff57fe330540257c57 100644 GIT binary patch delta 72886 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 delta 1409 zcmaENhNWG3!+gfge*TS|TpSDnv$Fy|@4t9<`W_iZ&3ZPaH(nq34?aAb=i+wa(&TSD z)HE$$noZri`{b>y#Yvhbmd~y4`_FoRnp;dhZ;30f$PqT1g_~=REnB=UeQD#4=lSb6 z&vLzsKUOSxVDXwCf<`_cJ5p+32&H(X%5rSgg|J4!?p{FS>c4i#xGfL)LQ$ltKWqKzB$(1T=dPhwLF?he~DKi+bq2m(|ko)R++7wHhasNtmqHM^Q87T zdRg+XQdeEMCfVzRDqtE%>jJ&vEto3tcNj3ZueU z{x4Y~C34JOmBYy)`ohc*#;mt}TlaNUPO4Yay!z*4ebg_mhHu*pgjV}lUY;rWsWQZI z#)}tEm}2jz2-`jQR(P}S(QoDeZ)O$|1_lNWhKXxp1MCk48geo+Fx&-V9-wG`K}lwQ zUa?+ANp4Q*L|=bqMS-^WYW4rvpR7|^=05GnjjB~EH&(q^nK=ETs~`u@*?0S=_g^(J zEJ{dtHut$I^Zuy!@8bFVrHvj<7o0Bs$Gj<|X|WsgqX$CE(fHL zW1{Czs8D8?m>VcyRi(FtC7oZ^b;bmtwN}5jh4gDmM9CeTVWj!C@7%1J^Gxqd)zQ4!dP3_{{qs{@8iuY~vzBQHE!w=V2CxcFfec-g<4ke)L`%I z!v;M2_`k`Q6mzNGP34IyyZPAQg~ppgy?JZR7OsoUS<3JB|96i1+TRhzX&#GQE~&q~ zJUx#8-cKRf8LU&?tQD9SZAk0eshs>%Wc_-zsbU8?&$-w4%|5V(`Tq6r2j?e6&xlye zxm6}S?4YfO@+!-$Q_DThb2b0mP&rZ3x+i&V&B@T#W|qU+k+U{l%(~1rX^~BfM!=bX zYYNBL{(kP(eMd2M;niO^?$kIWj!V;M;_1o6XW5>(Pt4l(X*9h zsx!B7Zdi3!c!pt-X8q?0cX;kE*~%N|zTsTL^sxF9oY%idJXe^1&aHIrG8XTP9`a9R zd|hw8WXLTrbuj*U_wCtrf3}%zd-!aO$zdF z+L`XmUBc_aG9lpA-t zn{WqDi}KE+|2^+tmj3+N`S}C?75D2JY(t9Xz1MUs(wsm2p2W0s*Ij3CTz)Zo^OuDW zg;Zb9+ayyEwTr9h^WQnj+@W2Oi%gHGo{*pJq{NsxJwusMfoVG9^e$yaYh^^46A6sk z^-K&5ybLP9$OQofAeP`}n4Y7`DCN3umItr#_p6LBT0ZD;{Hu3Y83Vi-nd}*G Date: Tue, 17 Mar 2020 23:22:26 -0400 Subject: [PATCH 37/38] youtube-dl now auto updates on server restart --- backend/app.js | 50 ++++++++++++++++++++++++++++++++++++++++++++ backend/package.json | 1 + 2 files changed, 51 insertions(+) diff --git a/backend/app.js b/backend/app.js index a02a6cd..dfc0a90 100644 --- a/backend/app.js +++ b/backend/app.js @@ -10,6 +10,8 @@ var bodyParser = require("body-parser"); var archiver = require('archiver'); var mergeFiles = require('merge-files'); const low = require('lowdb') +const downloader = require('youtube-dl/lib/downloader') +const fetch = require('node-fetch'); var URL = require('url').URL; const shortid = require('shortid') const url_api = require('url'); @@ -56,6 +58,9 @@ let debugMode = process.env.YTDL_MODE === 'debug'; if (debugMode) console.log('YTDL-Material in debug mode!'); +// updates & starts youtubedl +startYoutubeDL(); + var validDownloadingAgents = [ 'aria2c', 'avconv', @@ -613,6 +618,51 @@ function writeToBlacklist(type, line) { fs.appendFileSync(blacklistBasePath + 'blacklist.txt', line); } +async function startYoutubeDL() { + // auto update youtube-dl + await autoUpdateYoutubeDL(); +} + +// auto updates the underlying youtube-dl binary, not YoutubeDL-Material +async function autoUpdateYoutubeDL() { + return new Promise(resolve => { + // get current version + let current_app_details_path = 'node_modules/youtube-dl/bin/details'; + let current_app_details_exists = fs.existsSync(current_app_details_path); + if (!current_app_details_exists) { + console.log(`Failed to get youtube-dl binary details at location: ${current_app_details_path}. Cancelling update check.`); + resolve(false); + return; + } + let current_app_details = JSON.parse(fs.readFileSync(current_app_details_path)); + let current_version = current_app_details['version']; + + // got version, now let's check the latest version from the youtube-dl API + let youtubedl_api_path = 'https://api.github.com/repos/ytdl-org/youtube-dl/tags'; + fetch(youtubedl_api_path, {method: 'Get'}) + .then(res => res.json()) + .then((json) => { + // check if the versions are different + const latest_update_version = json[0]['name']; + if (current_version !== latest_update_version) { + let binary_path = 'node_modules/youtube-dl/bin'; + // versions different, download new update + console.log('INFO: Found new update for youtube-dl. Updating binary...'); + downloader(binary_path, function error(err, done) { + 'use strict' + if (err) { + resolve(false); + throw err; + } + console.log(`INFO: Binary successfully updated: ${current_version} -> ${latest_update_version}`); + resolve(true); + }); + } + + }); + }); +} + app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", getOrigin()); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); diff --git a/backend/package.json b/backend/package.json index b67c591..8992bc6 100644 --- a/backend/package.json +++ b/backend/package.json @@ -26,6 +26,7 @@ "express": "^4.17.1", "lowdb": "^1.0.0", "merge-files": "^0.1.2", + "node-fetch": "^2.6.0", "shortid": "^2.2.15", "uuidv4": "^6.0.6", "youtube-dl": "^3.0.2" From 2e71a0bef112f3ccbd89872d891c0785acddbba9 Mon Sep 17 00:00:00 2001 From: Isaac Grynsztein Date: Wed, 18 Mar 2020 00:04:18 -0400 Subject: [PATCH 38/38] fixed bug that caused youtube downloader update to fail when the binary was being used to check for new subscription videos. now it waits for file access with a 10 second timeout --- backend/app.js | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/backend/app.js b/backend/app.js index dfc0a90..76cf30a 100644 --- a/backend/app.js +++ b/backend/app.js @@ -636,18 +636,20 @@ async function autoUpdateYoutubeDL() { } let current_app_details = JSON.parse(fs.readFileSync(current_app_details_path)); let current_version = current_app_details['version']; + let stored_binary_path = current_app_details['path']; // got version, now let's check the latest version from the youtube-dl API let youtubedl_api_path = 'https://api.github.com/repos/ytdl-org/youtube-dl/tags'; fetch(youtubedl_api_path, {method: 'Get'}) - .then(res => res.json()) - .then((json) => { + .then(async res => res.json()) + .then(async (json) => { // check if the versions are different const latest_update_version = json[0]['name']; if (current_version !== latest_update_version) { let binary_path = 'node_modules/youtube-dl/bin'; // versions different, download new update console.log('INFO: Found new update for youtube-dl. Updating binary...'); + await checkExistsWithTimeout(stored_binary_path, 10000); downloader(binary_path, function error(err, done) { 'use strict' if (err) { @@ -663,6 +665,34 @@ async function autoUpdateYoutubeDL() { }); } +async function checkExistsWithTimeout(filePath, timeout) { + return new Promise(function (resolve, reject) { + + var timer = setTimeout(function () { + watcher.close(); + reject(new Error('File did not exists and was not created during the timeout.')); + }, timeout); + + fs.access(filePath, fs.constants.R_OK, function (err) { + if (!err) { + clearTimeout(timer); + watcher.close(); + resolve(); + } + }); + + var dir = path.dirname(filePath); + var basename = path.basename(filePath); + var watcher = fs.watch(dir, function (eventType, filename) { + if (eventType === 'rename' && filename === basename) { + clearTimeout(timer); + watcher.close(); + resolve(); + } + }); + }); +} + app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", getOrigin()); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");