17 Commits

Author SHA1 Message Date
philipp.haefelfinger d80e270db2 updates jquery validation to version 1.19.1 2020-02-07 23:24:30 +01:00
philipp.haefelfinger 7701c94f8e updates jquery to version 3.4.1 2020-02-07 23:08:51 +01:00
philipp.haefelfinger 737ed0327a updates bootstrap to version 4.4.1 2020-02-07 23:04:44 +01:00
philipp.haefelfinger 8d55bfd2ff updates b uild process for new drone version
continuous-integration/drone/push Build is passing
2020-02-06 23:55:30 +01:00
philipp.haefelfinger f92b5a29d3 updates copyright and license info 2020-02-06 23:45:56 +01:00
philipp.haefelfinger 5fcc4afcd1 updates the Dockerfile to build in aspnet core 3.1 2020-02-06 23:38:57 +01:00
philipp.haefelfinger b71807cf16 adds some warnings about the datatypechange in sqlite 2020-02-06 23:13:15 +01:00
philipp.haefelfinger b89ae349ca addes migration for sqlite to make sure the new id field is text 2020-02-06 23:09:24 +01:00
philipp.haefelfinger cef19f9a22 upgrades the main application to .net core 3.1 2020-02-06 22:05:06 +01:00
philipp.haefelfinger 94802dc123 updates project to net standard 2.1 2020-02-06 22:01:33 +01:00
philipp.haefelfinger 7f824ee792 updates gitignore and adds *.blob and TestResults 2020-02-06 21:58:50 +01:00
philipp.haefelfinger a72a8cc8a9 updated EF nuget packages to 2.2.6
continuous-integration/drone/push Build is passing
2019-10-24 22:12:59 +02:00
philipp.haefelfinger 501e81c2c5 added tag 2.0.1 to dockerfile
continuous-integration/drone/push Build is passing
2019-06-04 22:58:33 +02:00
philipp.haefelfinger c8e3c1b9f5 updated readme 2019-06-04 22:48:15 +02:00
philipp.haefelfinger 0b818452b0 Added mass disable / enable 2019-06-04 22:46:26 +02:00
philipp.haefelfinger f190d3b5af added emby as hint 2019-06-04 22:12:05 +02:00
philipp.haefelfinger babd41055f updated packages 2019-06-04 21:46:42 +02:00
43 changed files with 40243 additions and 34924 deletions
+19 -11
View File
@@ -1,12 +1,20 @@
pipeline:
docker:
kind: pipeline
name: default
steps:
- name: docker
image: plugins/docker
repo: phaefelfinger/tv7playlist
tags:
- latest
- 2.0
secrets: [ docker_username, docker_password ]
debug: true
when:
event: push
branch: master
settings:
repo: phaefelfinger/tv7playlist
tags:
- latest
- '3.0'
- '3.0.0'
username:
from_secret: docker_username
password:
from_secret: docker_password
trigger:
branch:
- master
+1 -1
View File
@@ -92,7 +92,6 @@ AppPackages/
[Bb]in
[Oo]bj
sql
TestResults
[Tt]est[Rr]esult*
*.Cache
ClientBin
@@ -107,3 +106,4 @@ _UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
*.blob
+3 -3
View File
@@ -1,4 +1,4 @@
FROM microsoft/dotnet:sdk AS build-env
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /app
# Copy everything else and build
@@ -7,12 +7,12 @@ RUN dotnet restore Tv7Playlist.sln
RUN dotnet publish -c Release -o out Tv7Playlist.sln
# Build runtime image
FROM microsoft/dotnet:aspnetcore-runtime
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
RUN mkdir /data
COPY --from=build-env /app/Tv7Playlist/out .
COPY --from=build /app/out .
ENV ASPNETCORE_URLS=http://+:80
EXPOSE 80
+14 -2
View File
@@ -12,11 +12,23 @@ There are more features than just changing the URL:
- Resorting of the channel list
- Enable or disable a channel
- Override the channel number -> better EPG Detection support in plex
- Override the channel name -> better EPG Detection support in plex
- Enable or disable multiple channels at once
- Override the channel number -> better EPG Detection support in plex / emby
- Override the channel name -> better EPG Detection support in plex / emby
This is licensed under GPLv2. See License file.
## Possible breaking change of .net core 3.1.1 upgrade
Something changed within the entity framework driver for SqLite. A guid is now stored as a text and not blob anymore.
With the wrong datatype, you will get an error if you try to update a record.
The latest version of this application has a migration built in that should convert the blobs to the values as text.
The migrations are applied automatically.
**Backup your database before starting the new version**
A workaround might be clearing your database and rebuilding it by syncing the latest playlist from init7.
## Docker
### Run the application
+3 -3
View File
@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.1" />
</ItemGroup>
<ItemGroup>
@@ -0,0 +1,75 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Tv7Playlist.Data;
namespace Tv7Playlist.Data.Migrations
{
[DbContext(typeof(PlaylistContext))]
[Migration("20200206214445_DotnetCore3_1_upgrade")]
partial class DotnetCore3_1_upgrade
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "3.1.1");
modelBuilder.Entity("Tv7Playlist.Data.PlaylistEntry", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<int>("ChannelNumberExport")
.HasColumnType("INTEGER");
b.Property<int>("ChannelNumberImport")
.HasColumnType("INTEGER");
b.Property<DateTime>("Created")
.HasColumnType("TEXT");
b.Property<string>("EpgMatchName")
.HasColumnType("TEXT");
b.Property<bool>("IsAvailable")
.HasColumnType("INTEGER");
b.Property<bool>("IsEnabled")
.HasColumnType("INTEGER");
b.Property<string>("LogoUrl")
.HasColumnType("TEXT");
b.Property<DateTime>("Modified")
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<int>("Position")
.HasColumnType("INTEGER");
b.Property<string>("UrlOriginal")
.HasColumnType("TEXT");
b.Property<string>("UrlProxy")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("ChannelNumberImport")
.IsUnique();
b.HasIndex("Name");
b.ToTable("PlaylistEntries");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,73 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tv7Playlist.Data.Migrations
{
public partial class DotnetCore3_1_upgrade : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
"PlaylistEntriesTemp",
table => new
{
Id = table.Column<Guid>(),
Position = table.Column<int>(),
ChannelNumberImport = table.Column<int>(),
ChannelNumberExport = table.Column<int>(),
Name = table.Column<string>(nullable: true),
EpgMatchName = table.Column<string>(nullable: true),
UrlProxy = table.Column<string>(nullable: true),
UrlOriginal = table.Column<string>(nullable: true),
LogoUrl = table.Column<string>(nullable: true),
IsAvailable = table.Column<bool>(),
IsEnabled = table.Column<bool>(),
Created = table.Column<DateTime>(),
Modified = table.Column<DateTime>()
});
migrationBuilder.Sql("INSERT INTO PlaylistEntriesTemp SELECT * From PlaylistEntries");
migrationBuilder.DropTable("PlaylistEntries");
migrationBuilder.CreateTable(
"PlaylistEntries",
table => new
{
Id = table.Column<Guid>(),
Position = table.Column<int>(),
ChannelNumberImport = table.Column<int>(),
ChannelNumberExport = table.Column<int>(),
Name = table.Column<string>(nullable: true),
EpgMatchName = table.Column<string>(nullable: true),
UrlProxy = table.Column<string>(nullable: true),
UrlOriginal = table.Column<string>(nullable: true),
LogoUrl = table.Column<string>(nullable: true),
IsAvailable = table.Column<bool>(),
IsEnabled = table.Column<bool>(),
Created = table.Column<DateTime>(),
Modified = table.Column<DateTime>()
},
constraints: table => { table.PrimaryKey("PK_PlaylistEntries", x => x.Id); });
migrationBuilder.Sql("INSERT INTO PlaylistEntries SELECT * From PlaylistEntriesTemp");
migrationBuilder.CreateIndex(
"IX_PlaylistEntries_ChannelNumberImport",
"PlaylistEntries",
"ChannelNumberImport",
unique: true);
migrationBuilder.CreateIndex(
"IX_PlaylistEntries_Name",
"PlaylistEntries",
"Name");
migrationBuilder.DropTable("PlaylistEntriesTemp");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}
@@ -14,36 +14,49 @@ namespace Tv7Playlist.Data.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.1-servicing-10028");
.HasAnnotation("ProductVersion", "3.1.1");
modelBuilder.Entity("Tv7Playlist.Data.PlaylistEntry", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<int>("ChannelNumberExport");
b.Property<int>("ChannelNumberExport")
.HasColumnType("INTEGER");
b.Property<int>("ChannelNumberImport");
b.Property<int>("ChannelNumberImport")
.HasColumnType("INTEGER");
b.Property<DateTime>("Created");
b.Property<DateTime>("Created")
.HasColumnType("TEXT");
b.Property<string>("EpgMatchName");
b.Property<string>("EpgMatchName")
.HasColumnType("TEXT");
b.Property<bool>("IsAvailable");
b.Property<bool>("IsAvailable")
.HasColumnType("INTEGER");
b.Property<bool>("IsEnabled");
b.Property<bool>("IsEnabled")
.HasColumnType("INTEGER");
b.Property<string>("LogoUrl");
b.Property<string>("LogoUrl")
.HasColumnType("TEXT");
b.Property<DateTime>("Modified");
b.Property<DateTime>("Modified")
.HasColumnType("TEXT");
b.Property<string>("Name");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<int>("Position");
b.Property<int>("Position")
.HasColumnType("INTEGER");
b.Property<string>("UrlOriginal");
b.Property<string>("UrlOriginal")
.HasColumnType("TEXT");
b.Property<string>("UrlProxy");
b.Property<string>("UrlProxy")
.HasColumnType("TEXT");
b.HasKey("Id");
+4 -5
View File
@@ -1,15 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<LangVersion>latest</LangVersion>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.1" />
</ItemGroup>
</Project>
+35 -3
View File
@@ -12,9 +12,9 @@ namespace Tv7Playlist.Controllers
{
public class HomeController : Controller
{
private readonly IAppConfig _appConfig;
private readonly PlaylistContext _playlistContext;
private readonly IPlaylistSynchronizer _playlistSynchronizer;
private readonly IAppConfig _appConfig;
public HomeController(PlaylistContext playlistContext, IPlaylistSynchronizer playlistSynchronizer, IAppConfig appConfig)
{
@@ -26,12 +26,29 @@ namespace Tv7Playlist.Controllers
[HttpGet]
public async Task<IActionResult> Index()
{
var playlistEntries = await _playlistContext.PlaylistEntries.AsNoTracking().OrderBy(e => e.Position).ToListAsync();
var playlistEntries = await _playlistContext.PlaylistEntries.AsNoTracking().OrderBy(e => e.Position)
.Select(e => new PlaylistEntryModel(e)).ToListAsync();
var model = new HomeModel(playlistEntries);
return View(model);
}
[HttpPost]
public async Task<IActionResult> DisableSelectedEntries([FromForm] HomeModel model)
{
if (ModelState.IsValid) await UpdateEnabledForItems(model, false);
return Redirect("/");
}
[HttpPost]
public async Task<IActionResult> EnableSelectedEntries([FromForm] HomeModel model)
{
if (ModelState.IsValid) await UpdateEnabledForItems(model, true);
return Redirect("/");
}
[HttpGet]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
@@ -54,8 +71,23 @@ namespace Tv7Playlist.Controllers
public async Task<IActionResult> Synchronize(bool ok)
{
await _playlistSynchronizer.SynchronizeAsync();
return RedirectToAction("Index", "Home");
}
private async Task UpdateEnabledForItems(HomeModel model, bool isEnabled)
{
if (model == null) throw new ArgumentNullException(nameof(model));
var idsToUpdate = model.PlaylistEntries.Where(e => e.Selected).Select(e => e.Id);
foreach (var id in idsToUpdate)
{
var entry = await _playlistContext.PlaylistEntries.FindAsync(id);
if (entry == null) continue;
entry.IsEnabled = isEnabled;
}
await _playlistContext.SaveChangesAsync();
}
}
}
+6 -3
View File
@@ -1,16 +1,19 @@
using System;
using System.Collections.Generic;
using Tv7Playlist.Data;
namespace Tv7Playlist.Models
{
public class HomeModel
{
public HomeModel(List<PlaylistEntry> playlistEntries)
public HomeModel()
{
}
public HomeModel(List<PlaylistEntryModel> playlistEntries)
{
PlaylistEntries = playlistEntries ?? throw new ArgumentNullException(nameof(playlistEntries));
}
public List<PlaylistEntry> PlaylistEntries { get; }
public List<PlaylistEntryModel> PlaylistEntries { get; set; }
}
}
+24
View File
@@ -0,0 +1,24 @@
using System;
using Tv7Playlist.Data;
namespace Tv7Playlist.Models
{
public class PlaylistEntryModel
{
public PlaylistEntryModel()
{
}
public PlaylistEntryModel(PlaylistEntry entry)
{
Entry = entry ?? throw new ArgumentNullException(nameof(entry));
Id = entry.Id;
}
public Guid Id { get; set; }
public PlaylistEntry Entry { get; set; }
public bool Selected { get; set; }
}
}
+8 -7
View File
@@ -2,10 +2,10 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Tv7Playlist.Core;
using Tv7Playlist.Core.Parsers;
@@ -43,11 +43,11 @@ namespace Tv7Playlist
ConfigureParser(services, appConfig);
ConfigureDatabase(services, appConfig);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
@@ -67,11 +67,12 @@ namespace Tv7Playlist
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
app.UseRouting();
app.UseEndpoints(endpoints =>
{
routes.MapRoute(
"default",
"{controller=Home}/{action=Index}/{id?}");
endpoints.MapDefaultControllerRoute();
endpoints.MapControllers();
endpoints.MapRazorPages();
});
}
+4 -5
View File
@@ -1,16 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.1" />
</ItemGroup>
+68 -52
View File
@@ -3,56 +3,72 @@
ViewData["Title"] = "TV7 Playlist";
}
<div class="row">
<div class="col col-12">
<table class="table table-hover table-striped">
<tr>
<th></th>
<th>Number Import</th>
<th>Number Export</th>
<th>Position</th>
<th>Name</th>
<th>EPG Name</th>
<th>Enabled</th>
<th>Available</th>
<th>URL Proxy</th>
<th>URL Original</th>
<th>Created</th>
<th>Modified</th>
</tr>
@{
foreach (var channel in Model.PlaylistEntries)
{
<tr>
<td>
<a class="btn btn-secondary" asp-area="" asp-controller="PlaylistEntry" asp-action="Edit" asp-route-id="@channel.Id">Edit</a>
<a class="btn btn-danger" asp-area="" asp-controller="PlaylistEntry" asp-action="Delete" asp-route-id="@channel.Id">Delete</a>
@{
if (channel.IsEnabled)
{
<a class="btn btn-warning" asp-area="" asp-controller="PlaylistEntry" asp-action="ToggleEnabled" asp-route-id="@channel.Id">Disable</a>
}
else
{
<a class="btn btn-info" asp-area="" asp-controller="PlaylistEntry" asp-action="ToggleEnabled" asp-route-id="@channel.Id">Enable</a>
}
}
</td>
<td>@channel.ChannelNumberImport</td>
<td>@channel.ChannelNumberExport</td>
<td>@channel.Position</td>
<td>@channel.Name</td>
<td>@channel.EpgMatchName</td>
<td class="text-center">@Html.Raw(channel.IsEnabled ? "<span class=\"text-primary\">Enabled</span>" : "<span class=\"text-danger\">Disabled</span>")</td>
<td class="text-center">@Html.Raw(channel.IsAvailable ? "<span class=\"text-primary\">yes</span>" : "<span class=\"text-danger\">no</span>")</td>
<td>@channel.UrlProxy</td>
<td>@channel.UrlOriginal</td>
<td>@channel.Created.ToString("g")</td>
<td>@channel.Modified.ToString("g")</td>
</tr>
}
}
</table>
<form method="post">
<div class="row">
<div class="col col-4">
<button class="btn btn-warning" asp-action="DisableSelectedEntries" asp-controller="Home">Disable selected</button>
<button class="btn btn-info" asp-action="EnableSelectedEntries" asp-controller="Home">Enable selected</button>
</div>
</div>
</div>
<div class="row">
<div class="col col-12">
<table class="table table-hover table-striped">
<tr>
<th>Selected</th>
<th>Single Action</th>
<th>Number Import</th>
<th>Number Export</th>
<th>Position</th>
<th>Name</th>
<th>EPG Name</th>
<th>Enabled</th>
<th>Available</th>
<th>URL Proxy</th>
<th>URL Original</th>
<th>Created</th>
<th>Modified</th>
</tr>
@{
for (var i = 0; i < Model.PlaylistEntries.Count; i++)
{
@Html.HiddenFor(m => m.PlaylistEntries[i].Id)
<tr>
<td>
<input asp-for="PlaylistEntries[i].Selected" type="checkbox" />
</td>
<td>
<a class="btn btn-secondary" asp-area="" asp-controller="PlaylistEntry" asp-action="Edit" asp-route-id="@Model.PlaylistEntries[i].Id">Edit</a>
<a class="btn btn-danger" asp-area="" asp-controller="PlaylistEntry" asp-action="Delete" asp-route-id="@Model.PlaylistEntries[i].Id">Delete</a>
@{
if (Model.PlaylistEntries[i].Entry.IsEnabled)
{
<a class="btn btn-warning" asp-area="" asp-controller="PlaylistEntry" asp-action="ToggleEnabled" asp-route-id="@Model.PlaylistEntries[i].Id">Disable</a>
}
else
{
<a class="btn btn-info" asp-area="" asp-controller="PlaylistEntry" asp-action="ToggleEnabled" asp-route-id="@Model.PlaylistEntries[i].Id">Enable</a>
}
}
</td>
<td>@Model.PlaylistEntries[i].Entry.ChannelNumberImport</td>
<td>@Model.PlaylistEntries[i].Entry.ChannelNumberExport</td>
<td>@Model.PlaylistEntries[i].Entry.Position</td>
<td>@Model.PlaylistEntries[i].Entry.Name</td>
<td>@Model.PlaylistEntries[i].Entry.EpgMatchName</td>
<td class="text-center">@Html.Raw(Model.PlaylistEntries[i].Entry.IsEnabled ? "<span class=\"text-primary\">Enabled</span>" : "<span class=\"text-danger\">Disabled</span>")</td>
<td class="text-center">@Html.Raw(Model.PlaylistEntries[i].Entry.IsAvailable ? "<span class=\"text-primary\">yes</span>" : "<span class=\"text-danger\">no</span>")</td>
<td>@Model.PlaylistEntries[i].Entry.UrlProxy</td>
<td>@Model.PlaylistEntries[i].Entry.UrlOriginal</td>
<td>@Model.PlaylistEntries[i].Entry.Created.ToString("g")</td>
<td>@Model.PlaylistEntries[i].Entry.Modified.ToString("g")</td>
</tr>
}
}
</table>
</div>
</div>
</form>
+1 -1
View File
@@ -51,7 +51,7 @@
<footer class="border-top footer text-muted">
<div class="container">
&copy; 2018 - Philipp H&auml;felfinger - Tv7Playlist
&copy; 2018-2020 - Philipp H&auml;felfinger - Licensed under GPLv2 - Tv7Playlist
</div>
</footer>
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+326 -330
View File
@@ -1,331 +1,327 @@
/*!
* Bootstrap Reboot v4.1.3 (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)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
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: rgba(0, 0, 0, 0);
}
@-ms-viewport {
width: device-width;
}
article, aside, 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", "Noto Color Emoji";
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: 0.5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-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;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
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]):hover, a:not([href]):not([tabindex]):focus {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", 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 {
overflow: hidden;
vertical-align: middle;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #6c757d;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
}
label {
display: inline-block;
margin-bottom: 0.5rem;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-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;
}
/*!
* Bootstrap Reboot v4.4.1 (https://getbootstrap.com/)
* Copyright 2011-2019 The Bootstrap Authors
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
text-align: left;
background-color: #fff;
}
[tabindex="-1"]:focus:not(:focus-visible) {
outline: 0 !important;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 0.5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: .5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
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;
}
a:hover {
color: #0056b3;
text-decoration: underline;
}
a:not([href]) {
color: inherit;
text-decoration: none;
}
a:not([href]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
svg {
overflow: hidden;
vertical-align: middle;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #6c757d;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
}
label {
display: inline-block;
margin-bottom: 0.5rem;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
select {
word-wrap: normal;
}
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button:not(:disabled),
[type="button"]:not(:disabled),
[type="reset"]:not(:disabled),
[type="submit"]:not(:disabled) {
cursor: pointer;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-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-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;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */
File diff suppressed because one or more lines are too long
@@ -1,8 +1,8 @@
/*!
* Bootstrap Reboot v4.1.3 (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)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::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,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","Noto Color Emoji";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:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",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{overflow:hidden;vertical-align:middle}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}
/*!
* Bootstrap Reboot v4.4.1 (https://getbootstrap.com/)
* Copyright 2011-2019 The Bootstrap Authors
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){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;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}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}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}a:hover{color:#0056b3;text-decoration:underline}a:not([href]){color:inherit;text-decoration:none}a:not([href]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}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}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[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-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}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+10598 -10364
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long