From 5c2a901f75e9f6723b741b51b98ed70404694be6 Mon Sep 17 00:00:00 2001 From: Jonas Dellinger Date: Fri, 24 Aug 2018 14:10:13 +0200 Subject: [PATCH] Updated to .NET Core and reimplemented auth strategies --- SpotifyAPI.Example/App.config | 6 - SpotifyAPI.Example/ExampleForm.Designer.cs | 114 --- SpotifyAPI.Example/ExampleForm.cs | 12 - SpotifyAPI.Example/ExampleForm.resx | 120 --- SpotifyAPI.Example/LocalControl.Designer.cs | 686 ------------------ SpotifyAPI.Example/LocalControl.cs | 251 ------- SpotifyAPI.Example/LocalControl.resx | 120 --- SpotifyAPI.Example/Program.cs | 19 - SpotifyAPI.Example/Properties/AssemblyInfo.cs | 35 - .../Properties/Resources.Designer.cs | 71 -- SpotifyAPI.Example/Properties/Resources.resx | 117 --- .../Properties/Settings.Designer.cs | 30 - .../Properties/Settings.settings | 7 - SpotifyAPI.Example/SpotifyAPI.Example.csproj | 112 --- SpotifyAPI.Example/WebControl.Designer.cs | 420 ----------- SpotifyAPI.Example/WebControl.cs | 140 ---- SpotifyAPI.Example/WebControl.resx | 120 --- SpotifyAPI.Tests/Properties/AssemblyInfo.cs | 35 - SpotifyAPI.Tests/SpotifyAPI.Tests.csproj | 86 --- SpotifyAPI.Tests/SpotifyUriTest.cs | 54 -- SpotifyAPI.Tests/packages.config | 7 - SpotifyAPI.Web.Auth/AuthUtil.cs | 29 + SpotifyAPI.Web.Auth/AuthorizationCodeAuth.cs | 115 +++ SpotifyAPI.Web.Auth/CredentialsAuth.cs | 43 ++ SpotifyAPI.Web.Auth/ImplictGrantAuth.cs | 62 ++ .../AuthorizationCodeAuth/css/bulma.min.css | 1 + .../AuthorizationCodeAuth/images/1.png | Bin 0 -> 38997 bytes .../AuthorizationCodeAuth/images/2.png | Bin 0 -> 16049 bytes .../AuthorizationCodeAuth/start.html | 77 ++ .../Resources/ImplicitGrantAuth/index.html | 45 ++ .../SpotifyAPI.Web.Auth.csproj | 23 + SpotifyAPI.Web.Auth/SpotifyAuthServer.cs | 88 +++ SpotifyAPI.Web.Example/Program.cs | 74 ++ .../SpotifyAPI.Web.Example.csproj | 14 + .../SpotifyAPI.Web.Example.csproj.DotSettings | 2 + .../ProxyConfigTest.cs | 2 +- .../SpotifyAPI.Web.Tests.csproj | 21 + .../SpotifyWebAPITest.cs | 15 +- .../UtilTest.cs | 3 +- .../fixtures/private-user.json | 0 .../fixtures/public-user.json | 0 .../Web => SpotifyAPI.Web}/Enums/AlbumType.cs | 0 .../Enums/FollowType.cs | 0 .../Enums/RepeatState.cs | 0 .../Web => SpotifyAPI.Web}/Enums/Scope.cs | 0 .../Enums/SearchType.cs | 0 .../Enums/TimeRangeType.cs | 0 {SpotifyAPI/Web => SpotifyAPI.Web}/IClient.cs | 1 - .../Models/AnalysisMeta.cs | 0 .../Models/AnalysisSection.cs | 0 .../Models/AnalysisSegment.cs | 0 .../Models/AnalysisTimeSlice.cs | 0 .../Models/AnalysisTrack.cs | 0 .../Models/ArrayResponse.cs | 0 .../Models/AudioAnalysis.cs | 0 .../Models/AudioFeatures.cs | 0 .../Models/AvailabeDevices.cs | 0 .../Models/BasicModel.cs | 0 .../Web => SpotifyAPI.Web}/Models/Category.cs | 0 .../Models/CategoryList.cs | 0 .../Models/CategoryPlaylist.cs | 0 .../Models/CursorPaging.cs | 0 .../Web => SpotifyAPI.Web}/Models/Device.cs | 0 .../Models/FeaturedPlaylists.cs | 0 .../Models/FollowedArtists.cs | 0 .../Models/FullAlbum.cs | 0 .../Models/FullArtist.cs | 0 .../Models/FullPlaylist.cs | 0 .../Models/FullTrack.cs | 0 .../Models/GeneralModels.cs | 0 .../Models/NewAlbumReleases.cs | 0 .../Web => SpotifyAPI.Web}/Models/Paging.cs | 0 .../Models/PlayHistory.cs | 0 .../Models/PlaybackContext.cs | 0 .../Models/PrivateProfile.cs | 0 .../Models/PublicProfile.cs | 0 .../Models/RecommendationSeed .cs | 0 .../Models/RecommendationSeedGenres.cs | 0 .../Models/Recommendations.cs | 0 .../Models/ResponseInfo.cs | 0 .../Models/SearchItem.cs | 0 .../Models/SeveralAlbums.cs | 0 .../Models/SeveralArtists.cs | 0 .../Models/SeveralAudioFeatures.cs | 0 .../Models/SeveralTracks.cs | 0 .../Models/SimpleAlbum.cs | 0 .../Models/SimpleArtist.cs | 0 .../Models/SimplePlaylist.cs | 0 .../Models/SimpleTrack.cs | 0 .../Web => SpotifyAPI.Web}/Models/Snapshot.cs | 0 .../Web => SpotifyAPI.Web}/Models/Token.cs | 9 +- .../Models/TuneableTrack.cs | 0 {SpotifyAPI => SpotifyAPI.Web}/ProxyConfig.cs | 0 SpotifyAPI.Web/SpotifyAPI.Web.csproj | 11 + .../Web => SpotifyAPI.Web}/SpotifyWebAPI.cs | 5 - .../SpotifyWebBuilder.cs | 0 .../SpotifyWebClient.cs | 2 - {SpotifyAPI/Web => SpotifyAPI.Web}/Util.cs | 0 SpotifyAPI.sln | 43 +- SpotifyAPI/Local/Enums/AlbumArtSize.cs | 9 - SpotifyAPI/Local/Enums/UriType.cs | 12 - SpotifyAPI/Local/ExtendedWebClient.cs | 29 - SpotifyAPI/Local/LocalEvents.cs | 39 - SpotifyAPI/Local/Models/CFID.cs | 25 - SpotifyAPI/Local/Models/OpenGraphState.cs | 14 - SpotifyAPI/Local/Models/SpotifyResource.cs | 22 - SpotifyAPI/Local/Models/SpotifyUri.cs | 60 -- SpotifyAPI/Local/Models/StatusResponse.cs | 52 -- SpotifyAPI/Local/Models/Track.cs | 181 ----- .../Local/Models/TrackResourceLocation.cs | 11 - SpotifyAPI/Local/RemoteHandler.cs | 194 ----- SpotifyAPI/Local/SpotifyLocalAPI.cs | 368 ---------- SpotifyAPI/Local/SpotifyLocalAPIConfig.cs | 16 - SpotifyAPI/Local/VolumeMixerControl.cs | 302 -------- SpotifyAPI/Properties/AssemblyInfo.cs | 35 - SpotifyAPI/SpotifyAPI.csproj | 151 ---- SpotifyAPI/SpotifyAPI.nuspec | 25 - SpotifyAPI/Web/Auth/AutorizationCodeAuth.cs | 160 ---- SpotifyAPI/Web/Auth/ClientCredentialsAuth.cs | 85 --- SpotifyAPI/Web/Auth/ImplicitGrantAuth.cs | 77 -- SpotifyAPI/Web/Auth/WebAPIFactory.cs | 107 --- SpotifyAPI/Web/SimpleHttpServer.cs | 370 ---------- SpotifyAPI/app.config | 3 - SpotifyAPI/packages.config | 4 - SpotifyAPI/publish.cmd | 12 - 125 files changed, 647 insertions(+), 4963 deletions(-) delete mode 100644 SpotifyAPI.Example/App.config delete mode 100644 SpotifyAPI.Example/ExampleForm.Designer.cs delete mode 100644 SpotifyAPI.Example/ExampleForm.cs delete mode 100644 SpotifyAPI.Example/ExampleForm.resx delete mode 100644 SpotifyAPI.Example/LocalControl.Designer.cs delete mode 100644 SpotifyAPI.Example/LocalControl.cs delete mode 100644 SpotifyAPI.Example/LocalControl.resx delete mode 100644 SpotifyAPI.Example/Program.cs delete mode 100644 SpotifyAPI.Example/Properties/AssemblyInfo.cs delete mode 100644 SpotifyAPI.Example/Properties/Resources.Designer.cs delete mode 100644 SpotifyAPI.Example/Properties/Resources.resx delete mode 100644 SpotifyAPI.Example/Properties/Settings.Designer.cs delete mode 100644 SpotifyAPI.Example/Properties/Settings.settings delete mode 100644 SpotifyAPI.Example/SpotifyAPI.Example.csproj delete mode 100644 SpotifyAPI.Example/WebControl.Designer.cs delete mode 100644 SpotifyAPI.Example/WebControl.cs delete mode 100644 SpotifyAPI.Example/WebControl.resx delete mode 100644 SpotifyAPI.Tests/Properties/AssemblyInfo.cs delete mode 100644 SpotifyAPI.Tests/SpotifyAPI.Tests.csproj delete mode 100644 SpotifyAPI.Tests/SpotifyUriTest.cs delete mode 100644 SpotifyAPI.Tests/packages.config create mode 100644 SpotifyAPI.Web.Auth/AuthUtil.cs create mode 100644 SpotifyAPI.Web.Auth/AuthorizationCodeAuth.cs create mode 100644 SpotifyAPI.Web.Auth/CredentialsAuth.cs create mode 100644 SpotifyAPI.Web.Auth/ImplictGrantAuth.cs create mode 100644 SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/css/bulma.min.css create mode 100644 SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/images/1.png create mode 100644 SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/images/2.png create mode 100644 SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/start.html create mode 100644 SpotifyAPI.Web.Auth/Resources/ImplicitGrantAuth/index.html create mode 100644 SpotifyAPI.Web.Auth/SpotifyAPI.Web.Auth.csproj create mode 100644 SpotifyAPI.Web.Auth/SpotifyAuthServer.cs create mode 100644 SpotifyAPI.Web.Example/Program.cs create mode 100644 SpotifyAPI.Web.Example/SpotifyAPI.Web.Example.csproj create mode 100644 SpotifyAPI.Web.Example/SpotifyAPI.Web.Example.csproj.DotSettings rename {SpotifyAPI.Tests => SpotifyAPI.Web.Tests}/ProxyConfigTest.cs (99%) create mode 100644 SpotifyAPI.Web.Tests/SpotifyAPI.Web.Tests.csproj rename {SpotifyAPI.Tests => SpotifyAPI.Web.Tests}/SpotifyWebAPITest.cs (95%) rename {SpotifyAPI.Tests => SpotifyAPI.Web.Tests}/UtilTest.cs (88%) rename {SpotifyAPI.Tests => SpotifyAPI.Web.Tests}/fixtures/private-user.json (100%) rename {SpotifyAPI.Tests => SpotifyAPI.Web.Tests}/fixtures/public-user.json (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Enums/AlbumType.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Enums/FollowType.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Enums/RepeatState.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Enums/Scope.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Enums/SearchType.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Enums/TimeRangeType.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/IClient.cs (99%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/AnalysisMeta.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/AnalysisSection.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/AnalysisSegment.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/AnalysisTimeSlice.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/AnalysisTrack.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/ArrayResponse.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/AudioAnalysis.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/AudioFeatures.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/AvailabeDevices.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/BasicModel.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/Category.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/CategoryList.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/CategoryPlaylist.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/CursorPaging.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/Device.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/FeaturedPlaylists.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/FollowedArtists.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/FullAlbum.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/FullArtist.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/FullPlaylist.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/FullTrack.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/GeneralModels.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/NewAlbumReleases.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/Paging.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/PlayHistory.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/PlaybackContext.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/PrivateProfile.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/PublicProfile.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/RecommendationSeed .cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/RecommendationSeedGenres.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/Recommendations.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/ResponseInfo.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/SearchItem.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/SeveralAlbums.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/SeveralArtists.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/SeveralAudioFeatures.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/SeveralTracks.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/SimpleAlbum.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/SimpleArtist.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/SimplePlaylist.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/SimpleTrack.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/Snapshot.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/Token.cs (85%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Models/TuneableTrack.cs (100%) rename {SpotifyAPI => SpotifyAPI.Web}/ProxyConfig.cs (100%) create mode 100644 SpotifyAPI.Web/SpotifyAPI.Web.csproj rename {SpotifyAPI/Web => SpotifyAPI.Web}/SpotifyWebAPI.cs (99%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/SpotifyWebBuilder.cs (100%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/SpotifyWebClient.cs (99%) rename {SpotifyAPI/Web => SpotifyAPI.Web}/Util.cs (100%) delete mode 100644 SpotifyAPI/Local/Enums/AlbumArtSize.cs delete mode 100644 SpotifyAPI/Local/Enums/UriType.cs delete mode 100644 SpotifyAPI/Local/ExtendedWebClient.cs delete mode 100644 SpotifyAPI/Local/LocalEvents.cs delete mode 100644 SpotifyAPI/Local/Models/CFID.cs delete mode 100644 SpotifyAPI/Local/Models/OpenGraphState.cs delete mode 100644 SpotifyAPI/Local/Models/SpotifyResource.cs delete mode 100644 SpotifyAPI/Local/Models/SpotifyUri.cs delete mode 100644 SpotifyAPI/Local/Models/StatusResponse.cs delete mode 100755 SpotifyAPI/Local/Models/Track.cs delete mode 100644 SpotifyAPI/Local/Models/TrackResourceLocation.cs delete mode 100644 SpotifyAPI/Local/RemoteHandler.cs delete mode 100644 SpotifyAPI/Local/SpotifyLocalAPI.cs delete mode 100644 SpotifyAPI/Local/SpotifyLocalAPIConfig.cs delete mode 100644 SpotifyAPI/Local/VolumeMixerControl.cs delete mode 100644 SpotifyAPI/Properties/AssemblyInfo.cs delete mode 100644 SpotifyAPI/SpotifyAPI.csproj delete mode 100644 SpotifyAPI/SpotifyAPI.nuspec delete mode 100644 SpotifyAPI/Web/Auth/AutorizationCodeAuth.cs delete mode 100644 SpotifyAPI/Web/Auth/ClientCredentialsAuth.cs delete mode 100644 SpotifyAPI/Web/Auth/ImplicitGrantAuth.cs delete mode 100644 SpotifyAPI/Web/Auth/WebAPIFactory.cs delete mode 100644 SpotifyAPI/Web/SimpleHttpServer.cs delete mode 100644 SpotifyAPI/app.config delete mode 100644 SpotifyAPI/packages.config delete mode 100644 SpotifyAPI/publish.cmd diff --git a/SpotifyAPI.Example/App.config b/SpotifyAPI.Example/App.config deleted file mode 100644 index 1f6eeef1..00000000 --- a/SpotifyAPI.Example/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/SpotifyAPI.Example/ExampleForm.Designer.cs b/SpotifyAPI.Example/ExampleForm.Designer.cs deleted file mode 100644 index 2cf7ab2f..00000000 --- a/SpotifyAPI.Example/ExampleForm.Designer.cs +++ /dev/null @@ -1,114 +0,0 @@ -namespace SpotifyAPI.Example -{ - partial class ExampleForm - { - /// - /// Erforderliche Designervariable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Verwendete Ressourcen bereinigen. - /// - /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Vom Windows Form-Designer generierter Code - - /// - /// Erforderliche Methode für die Designerunterstützung. - /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. - /// - private void InitializeComponent() - { - this.tabControl1 = new System.Windows.Forms.TabControl(); - this.tabPage1 = new System.Windows.Forms.TabPage(); - this.localControl1 = new SpotifyAPI.Example.LocalControl(); - this.tabPage2 = new System.Windows.Forms.TabPage(); - this.webControl2 = new SpotifyAPI.Example.WebControl(); - this.tabControl1.SuspendLayout(); - this.tabPage1.SuspendLayout(); - this.tabPage2.SuspendLayout(); - this.SuspendLayout(); - // - // tabControl1 - // - this.tabControl1.Controls.Add(this.tabPage1); - this.tabControl1.Controls.Add(this.tabPage2); - this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; - this.tabControl1.Location = new System.Drawing.Point(0, 0); - this.tabControl1.Name = "tabControl1"; - this.tabControl1.SelectedIndex = 0; - this.tabControl1.Size = new System.Drawing.Size(984, 702); - this.tabControl1.TabIndex = 0; - // - // tabPage1 - // - this.tabPage1.Controls.Add(this.localControl1); - this.tabPage1.Location = new System.Drawing.Point(4, 22); - this.tabPage1.Name = "tabPage1"; - this.tabPage1.Padding = new System.Windows.Forms.Padding(3); - this.tabPage1.Size = new System.Drawing.Size(976, 676); - this.tabPage1.TabIndex = 0; - this.tabPage1.Text = "Local-API"; - this.tabPage1.UseVisualStyleBackColor = true; - // - // localControl1 - // - this.localControl1.Dock = System.Windows.Forms.DockStyle.Fill; - this.localControl1.Location = new System.Drawing.Point(3, 3); - this.localControl1.Name = "localControl1"; - this.localControl1.Size = new System.Drawing.Size(970, 670); - this.localControl1.TabIndex = 0; - // - // tabPage2 - // - this.tabPage2.Controls.Add(this.webControl2); - this.tabPage2.Location = new System.Drawing.Point(4, 22); - this.tabPage2.Name = "tabPage2"; - this.tabPage2.Padding = new System.Windows.Forms.Padding(3); - this.tabPage2.Size = new System.Drawing.Size(976, 676); - this.tabPage2.TabIndex = 1; - this.tabPage2.Text = "Web-API"; - this.tabPage2.UseVisualStyleBackColor = true; - // - // webControl2 - // - this.webControl2.Dock = System.Windows.Forms.DockStyle.Fill; - this.webControl2.Location = new System.Drawing.Point(3, 3); - this.webControl2.Name = "webControl2"; - this.webControl2.Size = new System.Drawing.Size(970, 670); - this.webControl2.TabIndex = 0; - // - // ExampleForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(984, 702); - this.Controls.Add(this.tabControl1); - this.Name = "ExampleForm"; - this.Text = "SpoitfyAPI .NET Example"; - this.tabControl1.ResumeLayout(false); - this.tabPage1.ResumeLayout(false); - this.tabPage2.ResumeLayout(false); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.TabControl tabControl1; - private System.Windows.Forms.TabPage tabPage1; - private System.Windows.Forms.TabPage tabPage2; - private LocalControl localControl1; - private WebControl webControl2; - } -} - diff --git a/SpotifyAPI.Example/ExampleForm.cs b/SpotifyAPI.Example/ExampleForm.cs deleted file mode 100644 index d311c0ef..00000000 --- a/SpotifyAPI.Example/ExampleForm.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Windows.Forms; - -namespace SpotifyAPI.Example -{ - public partial class ExampleForm : Form - { - public ExampleForm() - { - InitializeComponent(); - } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Example/ExampleForm.resx b/SpotifyAPI.Example/ExampleForm.resx deleted file mode 100644 index 1af7de15..00000000 --- a/SpotifyAPI.Example/ExampleForm.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/SpotifyAPI.Example/LocalControl.Designer.cs b/SpotifyAPI.Example/LocalControl.Designer.cs deleted file mode 100644 index 0a058cb8..00000000 --- a/SpotifyAPI.Example/LocalControl.Designer.cs +++ /dev/null @@ -1,686 +0,0 @@ -namespace SpotifyAPI.Example -{ - partial class LocalControl - { - /// - /// Erforderliche Designervariable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Verwendete Ressourcen bereinigen. - /// - /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Vom Komponenten-Designer generierter Code - - /// - /// Erforderliche Methode für die Designerunterstützung. - /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. - /// - private void InitializeComponent() - { - this.bigAlbumPicture = new System.Windows.Forms.PictureBox(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.volumeMixerLabel = new System.Windows.Forms.Label(); - this.label9 = new System.Windows.Forms.Label(); - this.volumeUpBtn = new System.Windows.Forms.Button(); - this.volumeDownBtn = new System.Windows.Forms.Button(); - this.repeatShuffleLabel = new System.Windows.Forms.Label(); - this.label6 = new System.Windows.Forms.Label(); - this.versionLabel = new System.Windows.Forms.Label(); - this.label11 = new System.Windows.Forms.Label(); - this.clientVersionLabel = new System.Windows.Forms.Label(); - this.label7 = new System.Windows.Forms.Label(); - this.skipBtn = new System.Windows.Forms.Button(); - this.prevBtn = new System.Windows.Forms.Button(); - this.pauseBtn = new System.Windows.Forms.Button(); - this.playBtn = new System.Windows.Forms.Button(); - this.label1 = new System.Windows.Forms.Label(); - this.contextTextBox = new System.Windows.Forms.TextBox(); - this.playUrlBtn = new System.Windows.Forms.Button(); - this.playTextBox = new System.Windows.Forms.TextBox(); - this.label2 = new System.Windows.Forms.Label(); - this.isPlayingLabel = new System.Windows.Forms.Label(); - this.volumeLabel = new System.Windows.Forms.Label(); - this.label10 = new System.Windows.Forms.Label(); - this.label8 = new System.Windows.Forms.Label(); - this.connectBtn = new System.Windows.Forms.Button(); - this.trackInfoBox = new System.Windows.Forms.GroupBox(); - this.advertLabel = new System.Windows.Forms.Label(); - this.timeLabel = new System.Windows.Forms.Label(); - this.timeProgressBar = new System.Windows.Forms.ProgressBar(); - this.label5 = new System.Windows.Forms.Label(); - this.smallAlbumPicture = new System.Windows.Forms.PictureBox(); - this.label4 = new System.Windows.Forms.Label(); - this.artistLinkLabel = new System.Windows.Forms.LinkLabel(); - this.titleLinkLabel = new System.Windows.Forms.LinkLabel(); - this.label3 = new System.Windows.Forms.Label(); - this.albumLinkLabel = new System.Windows.Forms.LinkLabel(); - this.proxyGroupBox = new System.Windows.Forms.GroupBox(); - this.proxyPortUpDown = new System.Windows.Forms.NumericUpDown(); - this.proxyPasswordTextBox = new System.Windows.Forms.TextBox(); - this.label15 = new System.Windows.Forms.Label(); - this.proxyUsernameTextBox = new System.Windows.Forms.TextBox(); - this.label14 = new System.Windows.Forms.Label(); - this.label13 = new System.Windows.Forms.Label(); - this.proxyHostTextBox = new System.Windows.Forms.TextBox(); - this.label12 = new System.Windows.Forms.Label(); - this.applyProxyBtn = new System.Windows.Forms.Button(); - ((System.ComponentModel.ISupportInitialize)(this.bigAlbumPicture)).BeginInit(); - this.groupBox1.SuspendLayout(); - this.trackInfoBox.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.smallAlbumPicture)).BeginInit(); - this.proxyGroupBox.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.proxyPortUpDown)).BeginInit(); - this.SuspendLayout(); - // - // bigAlbumPicture - // - this.bigAlbumPicture.Location = new System.Drawing.Point(407, 93); - this.bigAlbumPicture.Name = "bigAlbumPicture"; - this.bigAlbumPicture.Size = new System.Drawing.Size(560, 560); - this.bigAlbumPicture.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; - this.bigAlbumPicture.TabIndex = 2; - this.bigAlbumPicture.TabStop = false; - // - // groupBox1 - // - this.groupBox1.Controls.Add(this.volumeMixerLabel); - this.groupBox1.Controls.Add(this.label9); - this.groupBox1.Controls.Add(this.volumeUpBtn); - this.groupBox1.Controls.Add(this.volumeDownBtn); - this.groupBox1.Controls.Add(this.repeatShuffleLabel); - this.groupBox1.Controls.Add(this.label6); - this.groupBox1.Controls.Add(this.versionLabel); - this.groupBox1.Controls.Add(this.label11); - this.groupBox1.Controls.Add(this.clientVersionLabel); - this.groupBox1.Controls.Add(this.label7); - this.groupBox1.Controls.Add(this.skipBtn); - this.groupBox1.Controls.Add(this.prevBtn); - this.groupBox1.Controls.Add(this.pauseBtn); - this.groupBox1.Controls.Add(this.playBtn); - this.groupBox1.Controls.Add(this.label1); - this.groupBox1.Controls.Add(this.contextTextBox); - this.groupBox1.Controls.Add(this.playUrlBtn); - this.groupBox1.Controls.Add(this.playTextBox); - this.groupBox1.Controls.Add(this.label2); - this.groupBox1.Controls.Add(this.isPlayingLabel); - this.groupBox1.Controls.Add(this.volumeLabel); - this.groupBox1.Controls.Add(this.label10); - this.groupBox1.Controls.Add(this.label8); - this.groupBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.groupBox1.Location = new System.Drawing.Point(3, 55); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(398, 286); - this.groupBox1.TabIndex = 3; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "Spotify Info"; - // - // volumeMixerLabel - // - this.volumeMixerLabel.AutoSize = true; - this.volumeMixerLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.volumeMixerLabel.Location = new System.Drawing.Point(168, 117); - this.volumeMixerLabel.Name = "volumeMixerLabel"; - this.volumeMixerLabel.Size = new System.Drawing.Size(13, 17); - this.volumeMixerLabel.TabIndex = 35; - this.volumeMixerLabel.Text = "-"; - // - // label9 - // - this.label9.AutoSize = true; - this.label9.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label9.Location = new System.Drawing.Point(7, 117); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(155, 17); - this.label9.TabIndex = 34; - this.label9.Text = "Volume Mixer\'s volume:"; - // - // volumeUpBtn - // - this.volumeUpBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.volumeUpBtn.Location = new System.Drawing.Point(300, 114); - this.volumeUpBtn.Margin = new System.Windows.Forms.Padding(0); - this.volumeUpBtn.Name = "volumeUpBtn"; - this.volumeUpBtn.Size = new System.Drawing.Size(92, 24); - this.volumeUpBtn.TabIndex = 33; - this.volumeUpBtn.Text = "Volume+"; - this.volumeUpBtn.UseVisualStyleBackColor = true; - this.volumeUpBtn.Click += new System.EventHandler(this.volumeUpBtn_Click); - // - // volumeDownBtn - // - this.volumeDownBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.volumeDownBtn.Location = new System.Drawing.Point(300, 138); - this.volumeDownBtn.Margin = new System.Windows.Forms.Padding(0); - this.volumeDownBtn.Name = "volumeDownBtn"; - this.volumeDownBtn.Size = new System.Drawing.Size(92, 24); - this.volumeDownBtn.TabIndex = 32; - this.volumeDownBtn.Text = "Volume-"; - this.volumeDownBtn.UseVisualStyleBackColor = true; - this.volumeDownBtn.Click += new System.EventHandler(this.volumeDownBtn_Click); - // - // repeatShuffleLabel - // - this.repeatShuffleLabel.AutoSize = true; - this.repeatShuffleLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.repeatShuffleLabel.Location = new System.Drawing.Point(146, 88); - this.repeatShuffleLabel.Name = "repeatShuffleLabel"; - this.repeatShuffleLabel.Size = new System.Drawing.Size(13, 17); - this.repeatShuffleLabel.TabIndex = 30; - this.repeatShuffleLabel.Text = "-"; - // - // label6 - // - this.label6.AutoSize = true; - this.label6.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label6.Location = new System.Drawing.Point(6, 88); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(134, 17); - this.label6.TabIndex = 29; - this.label6.Text = "Repeat and Shuffle:"; - // - // versionLabel - // - this.versionLabel.AutoSize = true; - this.versionLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.versionLabel.Location = new System.Drawing.Point(72, 37); - this.versionLabel.Name = "versionLabel"; - this.versionLabel.Size = new System.Drawing.Size(13, 17); - this.versionLabel.TabIndex = 28; - this.versionLabel.Text = "-"; - // - // label11 - // - this.label11.AutoSize = true; - this.label11.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label11.Location = new System.Drawing.Point(6, 37); - this.label11.Name = "label11"; - this.label11.Size = new System.Drawing.Size(60, 17); - this.label11.TabIndex = 27; - this.label11.Text = "Version:"; - // - // clientVersionLabel - // - this.clientVersionLabel.AutoSize = true; - this.clientVersionLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.clientVersionLabel.Location = new System.Drawing.Point(108, 20); - this.clientVersionLabel.Name = "clientVersionLabel"; - this.clientVersionLabel.Size = new System.Drawing.Size(13, 17); - this.clientVersionLabel.TabIndex = 26; - this.clientVersionLabel.Text = "-"; - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label7.Location = new System.Drawing.Point(6, 20); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(96, 17); - this.label7.TabIndex = 25; - this.label7.Text = "Client-Version"; - // - // skipBtn - // - this.skipBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.skipBtn.Location = new System.Drawing.Point(300, 252); - this.skipBtn.Name = "skipBtn"; - this.skipBtn.Size = new System.Drawing.Size(92, 23); - this.skipBtn.TabIndex = 24; - this.skipBtn.Text = "Skip"; - this.skipBtn.UseVisualStyleBackColor = true; - this.skipBtn.Click += new System.EventHandler(this.skipBtn_Click); - // - // prevBtn - // - this.prevBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.prevBtn.Location = new System.Drawing.Point(202, 252); - this.prevBtn.Name = "prevBtn"; - this.prevBtn.Size = new System.Drawing.Size(92, 23); - this.prevBtn.TabIndex = 23; - this.prevBtn.Text = "Previous"; - this.prevBtn.UseVisualStyleBackColor = true; - this.prevBtn.Click += new System.EventHandler(this.prevBtn_Click); - // - // pauseBtn - // - this.pauseBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.pauseBtn.Location = new System.Drawing.Point(104, 252); - this.pauseBtn.Name = "pauseBtn"; - this.pauseBtn.Size = new System.Drawing.Size(92, 23); - this.pauseBtn.TabIndex = 22; - this.pauseBtn.Text = "Pause"; - this.pauseBtn.UseVisualStyleBackColor = true; - this.pauseBtn.Click += new System.EventHandler(this.pauseBtn_Click); - // - // playBtn - // - this.playBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.playBtn.Location = new System.Drawing.Point(6, 252); - this.playBtn.Name = "playBtn"; - this.playBtn.Size = new System.Drawing.Size(92, 23); - this.playBtn.TabIndex = 21; - this.playBtn.Text = "Play"; - this.playBtn.UseVisualStyleBackColor = true; - this.playBtn.Click += new System.EventHandler(this.playBtn_Click); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label1.Location = new System.Drawing.Point(6, 206); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(110, 17); - this.label1.TabIndex = 20; - this.label1.Text = "Playing-Context:"; - // - // contextTextBox - // - this.contextTextBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.contextTextBox.Location = new System.Drawing.Point(9, 226); - this.contextTextBox.Name = "contextTextBox"; - this.contextTextBox.Size = new System.Drawing.Size(285, 20); - this.contextTextBox.TabIndex = 19; - // - // playUrlBtn - // - this.playUrlBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.playUrlBtn.Location = new System.Drawing.Point(300, 165); - this.playUrlBtn.Name = "playUrlBtn"; - this.playUrlBtn.Size = new System.Drawing.Size(92, 81); - this.playUrlBtn.TabIndex = 18; - this.playUrlBtn.Text = "PlayURL"; - this.playUrlBtn.UseVisualStyleBackColor = true; - this.playUrlBtn.Click += new System.EventHandler(this.playUrlBtn_Click); - // - // playTextBox - // - this.playTextBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.playTextBox.Location = new System.Drawing.Point(6, 185); - this.playTextBox.Name = "playTextBox"; - this.playTextBox.Size = new System.Drawing.Size(288, 20); - this.playTextBox.TabIndex = 17; - this.playTextBox.Text = "https://open.spotify.com/track/4myBMnNWZlgvVelYeTu55w"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label2.Location = new System.Drawing.Point(6, 165); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(131, 17); - this.label2.TabIndex = 16; - this.label2.Text = "Spotify URI or URL:"; - // - // isPlayingLabel - // - this.isPlayingLabel.AutoSize = true; - this.isPlayingLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.isPlayingLabel.Location = new System.Drawing.Point(84, 71); - this.isPlayingLabel.Name = "isPlayingLabel"; - this.isPlayingLabel.Size = new System.Drawing.Size(13, 17); - this.isPlayingLabel.TabIndex = 14; - this.isPlayingLabel.Text = "-"; - // - // volumeLabel - // - this.volumeLabel.AutoSize = true; - this.volumeLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.volumeLabel.Location = new System.Drawing.Point(71, 54); - this.volumeLabel.Name = "volumeLabel"; - this.volumeLabel.Size = new System.Drawing.Size(13, 17); - this.volumeLabel.TabIndex = 13; - this.volumeLabel.Text = "-"; - // - // label10 - // - this.label10.AutoSize = true; - this.label10.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label10.Location = new System.Drawing.Point(6, 54); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(59, 17); - this.label10.TabIndex = 11; - this.label10.Text = "Volume:"; - // - // label8 - // - this.label8.AutoSize = true; - this.label8.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label8.Location = new System.Drawing.Point(6, 71); - this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(72, 17); - this.label8.TabIndex = 10; - this.label8.Text = "Is Playing:"; - // - // connectBtn - // - this.connectBtn.Location = new System.Drawing.Point(3, 13); - this.connectBtn.Name = "connectBtn"; - this.connectBtn.Size = new System.Drawing.Size(398, 36); - this.connectBtn.TabIndex = 4; - this.connectBtn.Text = "Connect to Spotify"; - this.connectBtn.UseVisualStyleBackColor = true; - this.connectBtn.Click += new System.EventHandler(this.connectBtn_Click); - // - // trackInfoBox - // - this.trackInfoBox.Controls.Add(this.advertLabel); - this.trackInfoBox.Controls.Add(this.timeLabel); - this.trackInfoBox.Controls.Add(this.timeProgressBar); - this.trackInfoBox.Controls.Add(this.label5); - this.trackInfoBox.Controls.Add(this.smallAlbumPicture); - this.trackInfoBox.Controls.Add(this.label4); - this.trackInfoBox.Controls.Add(this.artistLinkLabel); - this.trackInfoBox.Controls.Add(this.titleLinkLabel); - this.trackInfoBox.Controls.Add(this.label3); - this.trackInfoBox.Controls.Add(this.albumLinkLabel); - this.trackInfoBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.trackInfoBox.Location = new System.Drawing.Point(3, 347); - this.trackInfoBox.Name = "trackInfoBox"; - this.trackInfoBox.Size = new System.Drawing.Size(398, 306); - this.trackInfoBox.TabIndex = 4; - this.trackInfoBox.TabStop = false; - this.trackInfoBox.Text = "Track Info"; - // - // advertLabel - // - this.advertLabel.AutoSize = true; - this.advertLabel.Location = new System.Drawing.Point(6, 67); - this.advertLabel.Name = "advertLabel"; - this.advertLabel.Size = new System.Drawing.Size(0, 17); - this.advertLabel.TabIndex = 31; - // - // timeLabel - // - this.timeLabel.AutoSize = true; - this.timeLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.timeLabel.Location = new System.Drawing.Point(7, 281); - this.timeLabel.Name = "timeLabel"; - this.timeLabel.Size = new System.Drawing.Size(13, 17); - this.timeLabel.TabIndex = 29; - this.timeLabel.Text = "-"; - // - // timeProgressBar - // - this.timeProgressBar.Location = new System.Drawing.Point(6, 255); - this.timeProgressBar.Name = "timeProgressBar"; - this.timeProgressBar.Size = new System.Drawing.Size(386, 23); - this.timeProgressBar.TabIndex = 28; - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label5.Location = new System.Drawing.Point(10, 227); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(51, 17); - this.label5.TabIndex = 27; - this.label5.Text = "Album:"; - // - // smallAlbumPicture - // - this.smallAlbumPicture.Location = new System.Drawing.Point(123, 22); - this.smallAlbumPicture.Name = "smallAlbumPicture"; - this.smallAlbumPicture.Size = new System.Drawing.Size(150, 150); - this.smallAlbumPicture.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; - this.smallAlbumPicture.TabIndex = 5; - this.smallAlbumPicture.TabStop = false; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label4.Location = new System.Drawing.Point(17, 204); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(44, 17); - this.label4.TabIndex = 26; - this.label4.Text = "Artist:"; - // - // artistLinkLabel - // - this.artistLinkLabel.AutoSize = true; - this.artistLinkLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.artistLinkLabel.Location = new System.Drawing.Point(67, 204); - this.artistLinkLabel.Name = "artistLinkLabel"; - this.artistLinkLabel.Size = new System.Drawing.Size(13, 17); - this.artistLinkLabel.TabIndex = 6; - this.artistLinkLabel.TabStop = true; - this.artistLinkLabel.Text = "-"; - this.artistLinkLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - // - // titleLinkLabel - // - this.titleLinkLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.titleLinkLabel.AutoSize = true; - this.titleLinkLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.titleLinkLabel.Location = new System.Drawing.Point(67, 182); - this.titleLinkLabel.Name = "titleLinkLabel"; - this.titleLinkLabel.Size = new System.Drawing.Size(13, 17); - this.titleLinkLabel.TabIndex = 5; - this.titleLinkLabel.TabStop = true; - this.titleLinkLabel.Text = "-"; - this.titleLinkLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label3.Location = new System.Drawing.Point(22, 182); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(39, 17); - this.label3.TabIndex = 25; - this.label3.Text = "Title:"; - // - // albumLinkLabel - // - this.albumLinkLabel.AutoSize = true; - this.albumLinkLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.albumLinkLabel.Location = new System.Drawing.Point(67, 227); - this.albumLinkLabel.Name = "albumLinkLabel"; - this.albumLinkLabel.Size = new System.Drawing.Size(13, 17); - this.albumLinkLabel.TabIndex = 7; - this.albumLinkLabel.TabStop = true; - this.albumLinkLabel.Text = "-"; - this.albumLinkLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - // - // proxyGroupBox - // - this.proxyGroupBox.Controls.Add(this.proxyPortUpDown); - this.proxyGroupBox.Controls.Add(this.proxyPasswordTextBox); - this.proxyGroupBox.Controls.Add(this.label15); - this.proxyGroupBox.Controls.Add(this.proxyUsernameTextBox); - this.proxyGroupBox.Controls.Add(this.label14); - this.proxyGroupBox.Controls.Add(this.label13); - this.proxyGroupBox.Controls.Add(this.proxyHostTextBox); - this.proxyGroupBox.Controls.Add(this.label12); - this.proxyGroupBox.Controls.Add(this.applyProxyBtn); - this.proxyGroupBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 11F); - this.proxyGroupBox.Location = new System.Drawing.Point(407, 10); - this.proxyGroupBox.Name = "proxyGroupBox"; - this.proxyGroupBox.Size = new System.Drawing.Size(560, 77); - this.proxyGroupBox.TabIndex = 5; - this.proxyGroupBox.TabStop = false; - this.proxyGroupBox.Text = "Proxy Config"; - // - // proxyPortUpDown - // - this.proxyPortUpDown.Location = new System.Drawing.Point(324, 18); - this.proxyPortUpDown.Maximum = new decimal(new int[] { - 65535, - 0, - 0, - 0}); - this.proxyPortUpDown.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.proxyPortUpDown.Name = "proxyPortUpDown"; - this.proxyPortUpDown.Size = new System.Drawing.Size(157, 24); - this.proxyPortUpDown.TabIndex = 6; - this.proxyPortUpDown.Value = new decimal(new int[] { - 80, - 0, - 0, - 0}); - // - // proxyPasswordTextBox - // - this.proxyPasswordTextBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.proxyPasswordTextBox.Location = new System.Drawing.Point(359, 47); - this.proxyPasswordTextBox.Name = "proxyPasswordTextBox"; - this.proxyPasswordTextBox.Size = new System.Drawing.Size(122, 20); - this.proxyPasswordTextBox.TabIndex = 42; - // - // label15 - // - this.label15.AutoSize = true; - this.label15.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label15.Location = new System.Drawing.Point(280, 48); - this.label15.Name = "label15"; - this.label15.Size = new System.Drawing.Size(73, 17); - this.label15.TabIndex = 41; - this.label15.Text = "Password:"; - // - // proxyUsernameTextBox - // - this.proxyUsernameTextBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.proxyUsernameTextBox.Location = new System.Drawing.Point(89, 47); - this.proxyUsernameTextBox.Name = "proxyUsernameTextBox"; - this.proxyUsernameTextBox.Size = new System.Drawing.Size(185, 20); - this.proxyUsernameTextBox.TabIndex = 40; - // - // label14 - // - this.label14.AutoSize = true; - this.label14.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label14.Location = new System.Drawing.Point(6, 48); - this.label14.Name = "label14"; - this.label14.Size = new System.Drawing.Size(77, 17); - this.label14.TabIndex = 39; - this.label14.Text = "Username:"; - // - // label13 - // - this.label13.AutoSize = true; - this.label13.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label13.Location = new System.Drawing.Point(280, 22); - this.label13.Name = "label13"; - this.label13.Size = new System.Drawing.Size(38, 17); - this.label13.TabIndex = 37; - this.label13.Text = "Port:"; - // - // proxyHostTextBox - // - this.proxyHostTextBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.proxyHostTextBox.Location = new System.Drawing.Point(49, 21); - this.proxyHostTextBox.Name = "proxyHostTextBox"; - this.proxyHostTextBox.Size = new System.Drawing.Size(225, 20); - this.proxyHostTextBox.TabIndex = 36; - // - // label12 - // - this.label12.AutoSize = true; - this.label12.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label12.Location = new System.Drawing.Point(6, 22); - this.label12.Name = "label12"; - this.label12.Size = new System.Drawing.Size(41, 17); - this.label12.TabIndex = 36; - this.label12.Text = "Host:"; - // - // applyProxyBtn - // - this.applyProxyBtn.Location = new System.Drawing.Point(487, 15); - this.applyProxyBtn.Name = "applyProxyBtn"; - this.applyProxyBtn.Size = new System.Drawing.Size(67, 56); - this.applyProxyBtn.TabIndex = 0; - this.applyProxyBtn.Text = "Apply"; - this.applyProxyBtn.UseVisualStyleBackColor = true; - this.applyProxyBtn.Click += new System.EventHandler(this.applyProxyBtn_Click); - // - // LocalControl - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.proxyGroupBox); - this.Controls.Add(this.trackInfoBox); - this.Controls.Add(this.connectBtn); - this.Controls.Add(this.groupBox1); - this.Controls.Add(this.bigAlbumPicture); - this.Name = "LocalControl"; - this.Size = new System.Drawing.Size(970, 670); - ((System.ComponentModel.ISupportInitialize)(this.bigAlbumPicture)).EndInit(); - this.groupBox1.ResumeLayout(false); - this.groupBox1.PerformLayout(); - this.trackInfoBox.ResumeLayout(false); - this.trackInfoBox.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.smallAlbumPicture)).EndInit(); - this.proxyGroupBox.ResumeLayout(false); - this.proxyGroupBox.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.proxyPortUpDown)).EndInit(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.PictureBox bigAlbumPicture; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.Button connectBtn; - private System.Windows.Forms.GroupBox trackInfoBox; - private System.Windows.Forms.PictureBox smallAlbumPicture; - private System.Windows.Forms.Label label10; - private System.Windows.Forms.Label label8; - private System.Windows.Forms.Label volumeLabel; - private System.Windows.Forms.Label isPlayingLabel; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.TextBox playTextBox; - private System.Windows.Forms.Button playUrlBtn; - private System.Windows.Forms.TextBox contextTextBox; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Button playBtn; - private System.Windows.Forms.Button skipBtn; - private System.Windows.Forms.Button prevBtn; - private System.Windows.Forms.Button pauseBtn; - private System.Windows.Forms.LinkLabel artistLinkLabel; - private System.Windows.Forms.LinkLabel titleLinkLabel; - private System.Windows.Forms.LinkLabel albumLinkLabel; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.Label timeLabel; - private System.Windows.Forms.ProgressBar timeProgressBar; - private System.Windows.Forms.Label clientVersionLabel; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.Label versionLabel; - private System.Windows.Forms.Label label11; - private System.Windows.Forms.Label label6; - private System.Windows.Forms.Label repeatShuffleLabel; - private System.Windows.Forms.Label advertLabel; - private System.Windows.Forms.Button volumeUpBtn; - private System.Windows.Forms.Button volumeDownBtn; - private System.Windows.Forms.Label volumeMixerLabel; - private System.Windows.Forms.Label label9; - private System.Windows.Forms.GroupBox proxyGroupBox; - private System.Windows.Forms.TextBox proxyPasswordTextBox; - private System.Windows.Forms.Label label15; - private System.Windows.Forms.TextBox proxyUsernameTextBox; - private System.Windows.Forms.Label label14; - private System.Windows.Forms.Label label13; - private System.Windows.Forms.TextBox proxyHostTextBox; - private System.Windows.Forms.Label label12; - private System.Windows.Forms.Button applyProxyBtn; - private System.Windows.Forms.NumericUpDown proxyPortUpDown; - } -} diff --git a/SpotifyAPI.Example/LocalControl.cs b/SpotifyAPI.Example/LocalControl.cs deleted file mode 100644 index 31ed6af6..00000000 --- a/SpotifyAPI.Example/LocalControl.cs +++ /dev/null @@ -1,251 +0,0 @@ -using SpotifyAPI.Local; -using SpotifyAPI.Local.Enums; -using SpotifyAPI.Local.Models; -using System; -using System.Diagnostics; -using System.Globalization; -using System.Windows.Forms; - -namespace SpotifyAPI.Example -{ - public partial class LocalControl : UserControl - { - private readonly SpotifyLocalAPIConfig _config; - private SpotifyLocalAPI _spotify; - private Track _currentTrack; - - public LocalControl() - { - InitializeComponent(); - - _config = new SpotifyLocalAPIConfig - { - ProxyConfig = new ProxyConfig() - }; - - _spotify = new SpotifyLocalAPI(_config); - _spotify.OnPlayStateChange += _spotify_OnPlayStateChange; - _spotify.OnTrackChange += _spotify_OnTrackChange; - _spotify.OnTrackTimeChange += _spotify_OnTrackTimeChange; - _spotify.OnVolumeChange += _spotify_OnVolumeChange; - //_spotify.SynchronizingObject = this; - - artistLinkLabel.Click += (sender, args) => Process.Start(artistLinkLabel.Tag.ToString()); - albumLinkLabel.Click += (sender, args) => Process.Start(albumLinkLabel.Tag.ToString()); - titleLinkLabel.Click += (sender, args) => Process.Start(titleLinkLabel.Tag.ToString()); - } - - public void Connect() - { - if (!SpotifyLocalAPI.IsSpotifyRunning()) - { - MessageBox.Show(@"Spotify isn't running!"); - return; - } - if (!SpotifyLocalAPI.IsSpotifyWebHelperRunning()) - { - MessageBox.Show(@"SpotifyWebHelper isn't running!"); - return; - } - - bool successful = _spotify.Connect(); - if (successful) - { - connectBtn.Text = @"Connection to Spotify successful"; - connectBtn.Enabled = false; - UpdateInfos(); - _spotify.ListenForEvents = true; - } - else - { - DialogResult res = MessageBox.Show(@"Couldn't connect to the spotify client. Retry?", @"Spotify", MessageBoxButtons.YesNo); - if (res == DialogResult.Yes) - Connect(); - } - } - - public void UpdateInfos() - { - StatusResponse status = _spotify.GetStatus(); - if (status == null) - return; - - //Basic Spotify Infos - UpdatePlayingStatus(status.Playing); - clientVersionLabel.Text = status.ClientVersion; - versionLabel.Text = status.Version.ToString(); - repeatShuffleLabel.Text = status.Repeat + @" and " + status.Shuffle; - - if (status.Track != null) //Update track infos - UpdateTrack(status.Track); - - RefreshVolumeMixerVolume(); - } - - public async void UpdateTrack(Track track) - { - _currentTrack = track; - - advertLabel.Text = track.IsAd() ? "ADVERT" : ""; - timeProgressBar.Maximum = track.Length; - - if (track.IsAd()) - return; //Don't process further, maybe null values - - titleLinkLabel.Text = track.TrackResource?.Name; - titleLinkLabel.Tag = track.TrackResource?.Uri; - - artistLinkLabel.Text = track.ArtistResource?.Name; - artistLinkLabel.Tag = track.ArtistResource?.Uri; - - albumLinkLabel.Text = track.AlbumResource?.Name; - albumLinkLabel.Tag = track.AlbumResource?.Uri; - - SpotifyUri uri = track.TrackResource?.ParseUri(); - - trackInfoBox.Text = $@"Track Info - {uri?.Id}"; - - bigAlbumPicture.Image = track.AlbumResource != null ? await track.GetAlbumArtAsync(AlbumArtSize.Size640, _config.ProxyConfig) : null; - smallAlbumPicture.Image = track.AlbumResource != null ? await track.GetAlbumArtAsync(AlbumArtSize.Size160, _config.ProxyConfig) : null; - } - - public void UpdatePlayingStatus(bool playing) - { - isPlayingLabel.Text = playing.ToString(); - } - - public void RefreshVolumeMixerVolume() - { - volumeMixerLabel.Text = _spotify.GetSpotifyVolume().ToString(CultureInfo.InvariantCulture); - } - - private void applyProxyBtn_Click(object sender, EventArgs e) - { - _config.ProxyConfig.Host = proxyHostTextBox.Text; - _config.ProxyConfig.Port = (int)proxyPortUpDown.Value; - _config.ProxyConfig.Username = proxyUsernameTextBox.Text; - _config.ProxyConfig.Password = proxyPasswordTextBox.Text; - - bool connected = _spotify.ListenForEvents; - if (connected) - { - // Reconnect using new proxy - _spotify.ListenForEvents = false; - _spotify.OnPlayStateChange -= _spotify_OnPlayStateChange; - _spotify.OnTrackChange -= _spotify_OnTrackChange; - _spotify.OnTrackTimeChange -= _spotify_OnTrackTimeChange; - _spotify.OnVolumeChange -= _spotify_OnVolumeChange; - - _spotify.Dispose(); - - _spotify = new SpotifyLocalAPI(_config); - _spotify.OnPlayStateChange += _spotify_OnPlayStateChange; - _spotify.OnTrackChange += _spotify_OnTrackChange; - _spotify.OnTrackTimeChange += _spotify_OnTrackTimeChange; - _spotify.OnVolumeChange += _spotify_OnVolumeChange; - - connectBtn.Text = @"Reconnecting..."; - Connect(); - } - } - - private void _spotify_OnVolumeChange(object sender, VolumeChangeEventArgs e) - { - if (InvokeRequired) - { - Invoke(new Action(() => _spotify_OnVolumeChange(sender, e))); - return; - } - volumeLabel.Text = (e.NewVolume * 100).ToString(CultureInfo.InvariantCulture); - } - - private void _spotify_OnTrackTimeChange(object sender, TrackTimeChangeEventArgs e) - { - if (InvokeRequired) - { - Invoke(new Action(() => _spotify_OnTrackTimeChange(sender, e))); - return; - } - timeLabel.Text = $@"{FormatTime(e.TrackTime)}/{FormatTime(_currentTrack.Length)}"; - if(e.TrackTime < _currentTrack.Length) - timeProgressBar.Value = (int)e.TrackTime; - } - - private void _spotify_OnTrackChange(object sender, TrackChangeEventArgs e) - { - if (InvokeRequired) - { - Invoke(new Action(() => _spotify_OnTrackChange(sender, e))); - return; - } - UpdateTrack(e.NewTrack); - } - - private void _spotify_OnPlayStateChange(object sender, PlayStateEventArgs e) - { - if (InvokeRequired) - { - Invoke(new Action(() => _spotify_OnPlayStateChange(sender, e))); - return; - } - UpdatePlayingStatus(e.Playing); - } - - private void connectBtn_Click(object sender, EventArgs e) - { - Connect(); - } - - private async void playUrlBtn_Click(object sender, EventArgs e) - { - await _spotify.PlayURL(playTextBox.Text, contextTextBox.Text); - } - - private async void playBtn_Click(object sender, EventArgs e) - { - await _spotify.Play(); - } - - private async void pauseBtn_Click(object sender, EventArgs e) - { - await _spotify.Pause(); - } - - private void prevBtn_Click(object sender, EventArgs e) - { - _spotify.Previous(); - } - - private void skipBtn_Click(object sender, EventArgs e) - { - _spotify.Skip(); - } - - private void volumeUpBtn_Click(object sender, EventArgs e) - { - float currentVolume = _spotify.GetSpotifyVolume(); - float newVolume = currentVolume + 2.0f; - _spotify.SetSpotifyVolume(newVolume >= 100.0f ? 100.0f : newVolume); - - RefreshVolumeMixerVolume(); - } - - private void volumeDownBtn_Click(object sender, EventArgs e) - { - float currentVolume = _spotify.GetSpotifyVolume(); - float newVolume = currentVolume - 2.0f; - _spotify.SetSpotifyVolume(newVolume <= 0.0f ? 0.0f : newVolume); - - RefreshVolumeMixerVolume(); - } - - private static String FormatTime(double sec) - { - TimeSpan span = TimeSpan.FromSeconds(sec); - String secs = span.Seconds.ToString(), mins = span.Minutes.ToString(); - if (secs.Length < 2) - secs = "0" + secs; - return mins + ":" + secs; - } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Example/LocalControl.resx b/SpotifyAPI.Example/LocalControl.resx deleted file mode 100644 index 1af7de15..00000000 --- a/SpotifyAPI.Example/LocalControl.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/SpotifyAPI.Example/Program.cs b/SpotifyAPI.Example/Program.cs deleted file mode 100644 index bdfac8ea..00000000 --- a/SpotifyAPI.Example/Program.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Windows.Forms; - -namespace SpotifyAPI.Example -{ - internal static class Program - { - /// - /// Der Haupteinstiegspunkt für die Anwendung. - /// - [STAThread] - private static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new ExampleForm()); - } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Example/Properties/AssemblyInfo.cs b/SpotifyAPI.Example/Properties/AssemblyInfo.cs deleted file mode 100644 index 2dad8ee7..00000000 --- a/SpotifyAPI.Example/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// Allgemeine Informationen über eine Assembly werden über die folgenden -// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, -// die mit einer Assembly verknüpft sind. -[assembly: AssemblyTitle("SpotifyAPI.Example")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SpotifyAPI.Example")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar -// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von -// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. -[assembly: ComVisible(false)] - -// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird -[assembly: Guid("22aa2afd-11be-4d66-b7d8-c337877ce14b")] - -// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: -// -// Hauptversion -// Nebenversion -// Buildnummer -// Revision -// -// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern -// übernehmen, indem Sie "*" eingeben: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/SpotifyAPI.Example/Properties/Resources.Designer.cs b/SpotifyAPI.Example/Properties/Resources.Designer.cs deleted file mode 100644 index 92913fed..00000000 --- a/SpotifyAPI.Example/Properties/Resources.Designer.cs +++ /dev/null @@ -1,71 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.34209 -// -// Änderungen an dieser Datei können fehlerhaftes Verhalten verursachen und gehen verloren, wenn -// der Code neu generiert wird. -// -//------------------------------------------------------------------------------ - -namespace SpotifyAPI.Example.Properties -{ - - - /// - /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. - /// - // Diese Klasse wurde von der StronglyTypedResourceBuilder-Klasse - // über ein Tool wie ResGen oder Visual Studio automatisch generiert. - // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen - // mit der Option /str erneut aus, oder erstellen Sie Ihr VS-Projekt neu. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { - } - - /// - /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SpotifyAPI.Example.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle - /// Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - } -} diff --git a/SpotifyAPI.Example/Properties/Resources.resx b/SpotifyAPI.Example/Properties/Resources.resx deleted file mode 100644 index af7dbebb..00000000 --- a/SpotifyAPI.Example/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/SpotifyAPI.Example/Properties/Settings.Designer.cs b/SpotifyAPI.Example/Properties/Settings.Designer.cs deleted file mode 100644 index 3444495f..00000000 --- a/SpotifyAPI.Example/Properties/Settings.Designer.cs +++ /dev/null @@ -1,30 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.34209 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace SpotifyAPI.Example.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - } -} diff --git a/SpotifyAPI.Example/Properties/Settings.settings b/SpotifyAPI.Example/Properties/Settings.settings deleted file mode 100644 index 39645652..00000000 --- a/SpotifyAPI.Example/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/SpotifyAPI.Example/SpotifyAPI.Example.csproj b/SpotifyAPI.Example/SpotifyAPI.Example.csproj deleted file mode 100644 index c8d5e78a..00000000 --- a/SpotifyAPI.Example/SpotifyAPI.Example.csproj +++ /dev/null @@ -1,112 +0,0 @@ - - - - - Debug - AnyCPU - {C8968A03-497E-4BAB-B492-5651AE7E0C06} - WinExe - Properties - SpotifyAPI.Example - SpotifyAPI.Example - v4.5 - 512 - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - Form - - - ExampleForm.cs - - - UserControl - - - LocalControl.cs - - - - - UserControl - - - WebControl.cs - - - ExampleForm.cs - - - LocalControl.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - - - WebControl.cs - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - - {ebbe35e2-7b91-4d7d-b8fc-3a0472f5119d} - SpotifyAPI - - - - - \ No newline at end of file diff --git a/SpotifyAPI.Example/WebControl.Designer.cs b/SpotifyAPI.Example/WebControl.Designer.cs deleted file mode 100644 index 4bbb6ba2..00000000 --- a/SpotifyAPI.Example/WebControl.Designer.cs +++ /dev/null @@ -1,420 +0,0 @@ -namespace SpotifyAPI.Example -{ - partial class WebControl - { - /// - /// Erforderliche Designervariable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Verwendete Ressourcen bereinigen. - /// - /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Vom Komponenten-Designer generierter Code - - /// - /// Erforderliche Methode für die Designerunterstützung. - /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. - /// - private void InitializeComponent() - { - this.authButton = new System.Windows.Forms.Button(); - this.label3 = new System.Windows.Forms.Label(); - this.label4 = new System.Windows.Forms.Label(); - this.label5 = new System.Windows.Forms.Label(); - this.label1 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.savedTracksListView = new System.Windows.Forms.ListView(); - this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.savedTracksCountLabel = new System.Windows.Forms.Label(); - this.playlistsListBox = new System.Windows.Forms.ListBox(); - this.playlistsCountLabel = new System.Windows.Forms.Label(); - this.label7 = new System.Windows.Forms.Label(); - this.displayNameLabel = new System.Windows.Forms.Label(); - this.countryLabel = new System.Windows.Forms.Label(); - this.emailLabel = new System.Windows.Forms.Label(); - this.accountLabel = new System.Windows.Forms.Label(); - this.avatarPictureBox = new System.Windows.Forms.PictureBox(); - this.proxyGroupBox = new System.Windows.Forms.GroupBox(); - this.proxyPortUpDown = new System.Windows.Forms.NumericUpDown(); - this.proxyPasswordTextBox = new System.Windows.Forms.TextBox(); - this.label15 = new System.Windows.Forms.Label(); - this.proxyUsernameTextBox = new System.Windows.Forms.TextBox(); - this.label14 = new System.Windows.Forms.Label(); - this.label13 = new System.Windows.Forms.Label(); - this.proxyHostTextBox = new System.Windows.Forms.TextBox(); - this.label12 = new System.Windows.Forms.Label(); - this.applyProxyBtn = new System.Windows.Forms.Button(); - ((System.ComponentModel.ISupportInitialize)(this.avatarPictureBox)).BeginInit(); - this.proxyGroupBox.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.proxyPortUpDown)).BeginInit(); - this.SuspendLayout(); - // - // authButton - // - this.authButton.Location = new System.Drawing.Point(3, 3); - this.authButton.Name = "authButton"; - this.authButton.Size = new System.Drawing.Size(964, 48); - this.authButton.TabIndex = 0; - this.authButton.Text = "Authenticate SpotifyWeb API"; - this.authButton.UseVisualStyleBackColor = true; - this.authButton.Click += new System.EventHandler(this.authButton_Click); - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label3.Location = new System.Drawing.Point(3, 251); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(100, 17); - this.label3.TabIndex = 5; - this.label3.Text = "Display-Name:"; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label4.Location = new System.Drawing.Point(3, 268); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(61, 17); - this.label4.TabIndex = 6; - this.label4.Text = "Country:"; - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label5.Location = new System.Drawing.Point(3, 285); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(51, 17); - this.label5.TabIndex = 7; - this.label5.Text = "E-Mail:"; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label1.Location = new System.Drawing.Point(3, 302); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(100, 17); - this.label1.TabIndex = 8; - this.label1.Text = "Account-Type:"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label2.Location = new System.Drawing.Point(240, 73); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(100, 17); - this.label2.TabIndex = 9; - this.label2.Text = "Saved-Tracks:"; - // - // savedTracksListView - // - this.savedTracksListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeader1, - this.columnHeader2, - this.columnHeader3}); - this.savedTracksListView.FullRowSelect = true; - this.savedTracksListView.Location = new System.Drawing.Point(243, 93); - this.savedTracksListView.Name = "savedTracksListView"; - this.savedTracksListView.Size = new System.Drawing.Size(385, 563); - this.savedTracksListView.TabIndex = 10; - this.savedTracksListView.UseCompatibleStateImageBehavior = false; - this.savedTracksListView.View = System.Windows.Forms.View.Details; - // - // columnHeader1 - // - this.columnHeader1.Text = "Title"; - this.columnHeader1.Width = 120; - // - // columnHeader2 - // - this.columnHeader2.Text = "Artist"; - this.columnHeader2.Width = 117; - // - // columnHeader3 - // - this.columnHeader3.Text = "Album"; - this.columnHeader3.Width = 131; - // - // savedTracksCountLabel - // - this.savedTracksCountLabel.AutoSize = true; - this.savedTracksCountLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.savedTracksCountLabel.Location = new System.Drawing.Point(346, 73); - this.savedTracksCountLabel.Name = "savedTracksCountLabel"; - this.savedTracksCountLabel.Size = new System.Drawing.Size(13, 17); - this.savedTracksCountLabel.TabIndex = 11; - this.savedTracksCountLabel.Text = "-"; - // - // playlistsListBox - // - this.playlistsListBox.FormattingEnabled = true; - this.playlistsListBox.Location = new System.Drawing.Point(634, 93); - this.playlistsListBox.Name = "playlistsListBox"; - this.playlistsListBox.Size = new System.Drawing.Size(305, 563); - this.playlistsListBox.TabIndex = 12; - // - // playlistsCountLabel - // - this.playlistsCountLabel.AutoSize = true; - this.playlistsCountLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.playlistsCountLabel.Location = new System.Drawing.Point(700, 73); - this.playlistsCountLabel.Name = "playlistsCountLabel"; - this.playlistsCountLabel.Size = new System.Drawing.Size(13, 17); - this.playlistsCountLabel.TabIndex = 14; - this.playlistsCountLabel.Text = "-"; - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label7.Location = new System.Drawing.Point(631, 73); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(63, 17); - this.label7.TabIndex = 13; - this.label7.Text = "Playlists:"; - // - // displayNameLabel - // - this.displayNameLabel.AutoSize = true; - this.displayNameLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.displayNameLabel.Location = new System.Drawing.Point(109, 251); - this.displayNameLabel.Name = "displayNameLabel"; - this.displayNameLabel.Size = new System.Drawing.Size(13, 17); - this.displayNameLabel.TabIndex = 15; - this.displayNameLabel.Text = "-"; - // - // countryLabel - // - this.countryLabel.AutoSize = true; - this.countryLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.countryLabel.Location = new System.Drawing.Point(70, 268); - this.countryLabel.Name = "countryLabel"; - this.countryLabel.Size = new System.Drawing.Size(13, 17); - this.countryLabel.TabIndex = 16; - this.countryLabel.Text = "-"; - // - // emailLabel - // - this.emailLabel.AutoSize = true; - this.emailLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.emailLabel.Location = new System.Drawing.Point(60, 285); - this.emailLabel.Name = "emailLabel"; - this.emailLabel.Size = new System.Drawing.Size(13, 17); - this.emailLabel.TabIndex = 17; - this.emailLabel.Text = "-"; - // - // accountLabel - // - this.accountLabel.AutoSize = true; - this.accountLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.accountLabel.Location = new System.Drawing.Point(109, 302); - this.accountLabel.Name = "accountLabel"; - this.accountLabel.Size = new System.Drawing.Size(13, 17); - this.accountLabel.TabIndex = 18; - this.accountLabel.Text = "-"; - // - // avatarPictureBox - // - this.avatarPictureBox.Location = new System.Drawing.Point(3, 322); - this.avatarPictureBox.Name = "avatarPictureBox"; - this.avatarPictureBox.Size = new System.Drawing.Size(234, 212); - this.avatarPictureBox.TabIndex = 19; - this.avatarPictureBox.TabStop = false; - // - // proxyGroupBox - // - this.proxyGroupBox.Controls.Add(this.proxyPortUpDown); - this.proxyGroupBox.Controls.Add(this.proxyPasswordTextBox); - this.proxyGroupBox.Controls.Add(this.label15); - this.proxyGroupBox.Controls.Add(this.proxyUsernameTextBox); - this.proxyGroupBox.Controls.Add(this.label14); - this.proxyGroupBox.Controls.Add(this.label13); - this.proxyGroupBox.Controls.Add(this.proxyHostTextBox); - this.proxyGroupBox.Controls.Add(this.label12); - this.proxyGroupBox.Controls.Add(this.applyProxyBtn); - this.proxyGroupBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 11F); - this.proxyGroupBox.Location = new System.Drawing.Point(6, 73); - this.proxyGroupBox.Name = "proxyGroupBox"; - this.proxyGroupBox.Size = new System.Drawing.Size(231, 167); - this.proxyGroupBox.TabIndex = 20; - this.proxyGroupBox.TabStop = false; - this.proxyGroupBox.Text = "Proxy Config"; - // - // proxyPortUpDown - // - this.proxyPortUpDown.Location = new System.Drawing.Point(50, 47); - this.proxyPortUpDown.Maximum = new decimal(new int[] { - 65535, - 0, - 0, - 0}); - this.proxyPortUpDown.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.proxyPortUpDown.Name = "proxyPortUpDown"; - this.proxyPortUpDown.Size = new System.Drawing.Size(76, 24); - this.proxyPortUpDown.TabIndex = 6; - this.proxyPortUpDown.Value = new decimal(new int[] { - 80, - 0, - 0, - 0}); - // - // proxyPasswordTextBox - // - this.proxyPasswordTextBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.proxyPasswordTextBox.Location = new System.Drawing.Point(85, 103); - this.proxyPasswordTextBox.Name = "proxyPasswordTextBox"; - this.proxyPasswordTextBox.Size = new System.Drawing.Size(140, 20); - this.proxyPasswordTextBox.TabIndex = 42; - // - // label15 - // - this.label15.AutoSize = true; - this.label15.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label15.Location = new System.Drawing.Point(6, 104); - this.label15.Name = "label15"; - this.label15.Size = new System.Drawing.Size(73, 17); - this.label15.TabIndex = 41; - this.label15.Text = "Password:"; - // - // proxyUsernameTextBox - // - this.proxyUsernameTextBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.proxyUsernameTextBox.Location = new System.Drawing.Point(89, 77); - this.proxyUsernameTextBox.Name = "proxyUsernameTextBox"; - this.proxyUsernameTextBox.Size = new System.Drawing.Size(136, 20); - this.proxyUsernameTextBox.TabIndex = 40; - // - // label14 - // - this.label14.AutoSize = true; - this.label14.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label14.Location = new System.Drawing.Point(6, 78); - this.label14.Name = "label14"; - this.label14.Size = new System.Drawing.Size(77, 17); - this.label14.TabIndex = 39; - this.label14.Text = "Username:"; - // - // label13 - // - this.label13.AutoSize = true; - this.label13.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label13.Location = new System.Drawing.Point(6, 51); - this.label13.Name = "label13"; - this.label13.Size = new System.Drawing.Size(38, 17); - this.label13.TabIndex = 37; - this.label13.Text = "Port:"; - // - // proxyHostTextBox - // - this.proxyHostTextBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.proxyHostTextBox.Location = new System.Drawing.Point(49, 21); - this.proxyHostTextBox.Name = "proxyHostTextBox"; - this.proxyHostTextBox.Size = new System.Drawing.Size(176, 20); - this.proxyHostTextBox.TabIndex = 36; - // - // label12 - // - this.label12.AutoSize = true; - this.label12.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label12.Location = new System.Drawing.Point(6, 22); - this.label12.Name = "label12"; - this.label12.Size = new System.Drawing.Size(41, 17); - this.label12.TabIndex = 36; - this.label12.Text = "Host:"; - // - // applyProxyBtn - // - this.applyProxyBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.applyProxyBtn.Location = new System.Drawing.Point(147, 136); - this.applyProxyBtn.Name = "applyProxyBtn"; - this.applyProxyBtn.Size = new System.Drawing.Size(78, 25); - this.applyProxyBtn.TabIndex = 0; - this.applyProxyBtn.Text = "Apply"; - this.applyProxyBtn.UseVisualStyleBackColor = true; - this.applyProxyBtn.Click += new System.EventHandler(this.applyProxyBtn_Click); - // - // WebControl - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.proxyGroupBox); - this.Controls.Add(this.avatarPictureBox); - this.Controls.Add(this.accountLabel); - this.Controls.Add(this.emailLabel); - this.Controls.Add(this.countryLabel); - this.Controls.Add(this.displayNameLabel); - this.Controls.Add(this.playlistsCountLabel); - this.Controls.Add(this.label7); - this.Controls.Add(this.playlistsListBox); - this.Controls.Add(this.savedTracksCountLabel); - this.Controls.Add(this.savedTracksListView); - this.Controls.Add(this.label2); - this.Controls.Add(this.label1); - this.Controls.Add(this.label5); - this.Controls.Add(this.label4); - this.Controls.Add(this.label3); - this.Controls.Add(this.authButton); - this.Name = "WebControl"; - this.Size = new System.Drawing.Size(970, 670); - ((System.ComponentModel.ISupportInitialize)(this.avatarPictureBox)).EndInit(); - this.proxyGroupBox.ResumeLayout(false); - this.proxyGroupBox.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.proxyPortUpDown)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Button authButton; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.ListView savedTracksListView; - private System.Windows.Forms.ColumnHeader columnHeader1; - private System.Windows.Forms.ColumnHeader columnHeader2; - private System.Windows.Forms.ColumnHeader columnHeader3; - private System.Windows.Forms.Label savedTracksCountLabel; - private System.Windows.Forms.ListBox playlistsListBox; - private System.Windows.Forms.Label playlistsCountLabel; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.Label displayNameLabel; - private System.Windows.Forms.Label countryLabel; - private System.Windows.Forms.Label emailLabel; - private System.Windows.Forms.Label accountLabel; - private System.Windows.Forms.PictureBox avatarPictureBox; - private System.Windows.Forms.GroupBox proxyGroupBox; - private System.Windows.Forms.NumericUpDown proxyPortUpDown; - private System.Windows.Forms.TextBox proxyPasswordTextBox; - private System.Windows.Forms.Label label15; - private System.Windows.Forms.TextBox proxyUsernameTextBox; - private System.Windows.Forms.Label label14; - private System.Windows.Forms.Label label13; - private System.Windows.Forms.TextBox proxyHostTextBox; - private System.Windows.Forms.Label label12; - private System.Windows.Forms.Button applyProxyBtn; - } -} diff --git a/SpotifyAPI.Example/WebControl.cs b/SpotifyAPI.Example/WebControl.cs deleted file mode 100644 index a195803f..00000000 --- a/SpotifyAPI.Example/WebControl.cs +++ /dev/null @@ -1,140 +0,0 @@ -using SpotifyAPI.Web; -using SpotifyAPI.Web.Auth; -using SpotifyAPI.Web.Enums; -using SpotifyAPI.Web.Models; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using System.Windows.Forms; -using Image = System.Drawing.Image; - -namespace SpotifyAPI.Example -{ - public partial class WebControl : UserControl - { - private readonly ProxyConfig _proxyConfig; - private SpotifyWebAPI _spotify; - - private PrivateProfile _profile; - private List _savedTracks; - private List _playlists; - - public WebControl() - { - InitializeComponent(); - - _proxyConfig = new ProxyConfig(); - - _savedTracks = new List(); - } - - private async void InitialSetup() - { - if (InvokeRequired) - { - Invoke(new Action(InitialSetup)); - return; - } - - authButton.Enabled = false; - _profile = await _spotify.GetPrivateProfileAsync(); - - _savedTracks = GetSavedTracks(); - savedTracksCountLabel.Text = _savedTracks.Count.ToString(); - _savedTracks.ForEach(track => savedTracksListView.Items.Add(new ListViewItem() - { - Text = track.Name, - SubItems = { string.Join(",", track.Artists.Select(source => source.Name)), track.Album.Name } - })); - - _playlists = GetPlaylists(); - playlistsCountLabel.Text = _playlists.Count.ToString(); - _playlists.ForEach(playlist => playlistsListBox.Items.Add(playlist.Name)); - - displayNameLabel.Text = _profile.DisplayName; - countryLabel.Text = _profile.Country; - emailLabel.Text = _profile.Email; - accountLabel.Text = _profile.Product; - - if (_profile.Images != null && _profile.Images.Count > 0) - { - using (WebClient wc = new WebClient()) - { - byte[] imageBytes = await wc.DownloadDataTaskAsync(new Uri(_profile.Images[0].Url)); - using (MemoryStream stream = new MemoryStream(imageBytes)) - avatarPictureBox.Image = Image.FromStream(stream); - } - } - } - - private List GetSavedTracks() - { - Paging savedTracks = _spotify.GetSavedTracks(); - List list = savedTracks.Items.Select(track => track.Track).ToList(); - - while (savedTracks.Next != null) - { - savedTracks = _spotify.GetSavedTracks(20, savedTracks.Offset + savedTracks.Limit); - list.AddRange(savedTracks.Items.Select(track => track.Track)); - } - - return list; - } - - private List GetPlaylists() - { - Paging playlists = _spotify.GetUserPlaylists(_profile.Id); - List list = playlists.Items.ToList(); - - while (playlists.Next != null) - { - playlists = _spotify.GetUserPlaylists(_profile.Id, 20, playlists.Offset + playlists.Limit); - list.AddRange(playlists.Items); - } - - return list; - } - - private void authButton_Click(object sender, EventArgs e) - { - Task.Run(() => RunAuthentication()); - } - - private async void RunAuthentication() - { - WebAPIFactory webApiFactory = new WebAPIFactory( - "http://localhost", - 8000, - "26d287105e31491889f3cd293d85bfea", - Scope.UserReadPrivate | Scope.UserReadEmail | Scope.PlaylistReadPrivate | Scope.UserLibraryRead | - Scope.UserReadPrivate | Scope.UserFollowRead | Scope.UserReadBirthdate | Scope.UserTopRead | Scope.PlaylistReadCollaborative | - Scope.UserReadRecentlyPlayed | Scope.UserReadPlaybackState | Scope.UserModifyPlaybackState, - _proxyConfig); - - try - { - _spotify = await webApiFactory.GetWebApi(); - } - catch (Exception ex) - { - MessageBox.Show(ex.Message); - } - - if (_spotify == null) - return; - - InitialSetup(); - } - - private void applyProxyBtn_Click(object sender, EventArgs e) - { - _proxyConfig.Host = proxyHostTextBox.Text; - _proxyConfig.Port = (int)proxyPortUpDown.Value; - _proxyConfig.Username = proxyUsernameTextBox.Text; - _proxyConfig.Password = proxyPasswordTextBox.Text; - } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Example/WebControl.resx b/SpotifyAPI.Example/WebControl.resx deleted file mode 100644 index 1af7de15..00000000 --- a/SpotifyAPI.Example/WebControl.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/SpotifyAPI.Tests/Properties/AssemblyInfo.cs b/SpotifyAPI.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index a395e345..00000000 --- a/SpotifyAPI.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// Allgemeine Informationen über eine Assembly werden über die folgenden -// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, -// die mit einer Assembly verknüpft sind. -[assembly: AssemblyTitle("SpotifyAPI.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("HEAVEN KILLERS RELEASE GROUP")] -[assembly: AssemblyProduct("SpotifyAPI.Tests")] -[assembly: AssemblyCopyright("Copyright © HEAVEN KILLERS RELEASE GROUP 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar -// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von -// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. -[assembly: ComVisible(false)] - -// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird -[assembly: Guid("015955d9-d411-4fcc-afc9-bc785216b9b2")] - -// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: -// -// Hauptversion -// Nebenversion -// Buildnummer -// Revision -// -// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern -// übernehmen, indem Sie "*" eingeben: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/SpotifyAPI.Tests/SpotifyAPI.Tests.csproj b/SpotifyAPI.Tests/SpotifyAPI.Tests.csproj deleted file mode 100644 index 51203cdd..00000000 --- a/SpotifyAPI.Tests/SpotifyAPI.Tests.csproj +++ /dev/null @@ -1,86 +0,0 @@ - - - - - Debug - AnyCPU - {A06CE1BA-B2C4-4C3C-9E79-D2E8D36DDF0B} - Library - Properties - SpotifyAPI.Tests - SpotifyAPI.Tests - v4.5 - 512 - ..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll - - - ..\packages\Moq.4.7.145\lib\net45\Moq.dll - - - ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll - - - ..\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll - - - - - - - - - - - - - - - - - - - - {ebbe35e2-7b91-4d7d-b8fc-3a0472f5119d} - SpotifyAPI - - - - - - - - - - - - - - \ No newline at end of file diff --git a/SpotifyAPI.Tests/SpotifyUriTest.cs b/SpotifyAPI.Tests/SpotifyUriTest.cs deleted file mode 100644 index 9326a626..00000000 --- a/SpotifyAPI.Tests/SpotifyUriTest.cs +++ /dev/null @@ -1,54 +0,0 @@ -using NUnit.Framework; -using SpotifyAPI.Local.Models; -using SpotifyAPI.Local.Enums; -using System; - -namespace SpotifyAPI.Tests -{ - [TestFixture] - public class SpotifyUriTest - { - [Test] - public void ShouldThrowArgumentExceptionForInvalidUri() - { - Assert.Throws(() => SpotifyUri.Parse("asdafadfgsrsegqejfa")); - } - - [Test] - public void ShouldCorrectlyParseTrackUri() - { - string testUri = "spotify:track:3QOruXa2lvqIFvOOa2rYyJ"; - SpotifyUri uri = SpotifyUri.Parse(testUri); - - Assert.AreEqual(uri.Base, "spotify"); - - Assert.AreEqual(uri.Type, UriType.track); - Assert.AreEqual(uri.Id, "3QOruXa2lvqIFvOOa2rYyJ"); - Assert.AreEqual(uri.ToString(), testUri); - } - - [Test] - public void ShouldCorrectlyParsePlaylistUri() - { - string testUri = "spotify:user:spotifycharts:playlist:37i9dQZEVXbMDoHDwVN2tF"; - SpotifyUri uri = SpotifyUri.Parse(testUri); - - Assert.AreEqual(uri.Base, "spotify"); - - Assert.AreEqual(uri.Type, UriType.playlist); - Assert.AreEqual(uri.Id, "37i9dQZEVXbMDoHDwVN2tF"); - - Assert.AreEqual(uri.GetUriPropValue(UriType.user), "spotifycharts"); - Assert.AreEqual(uri.ToString(), testUri); - } - - [Test] - public void ShouldHandleNotExistingUriProperty() - { - string testUri = "spotify:track:3QOruXa2lvqIFvOOa2rYyJ"; - SpotifyUri uri = SpotifyUri.Parse(testUri); - Assert.DoesNotThrow(() => uri.GetUriPropValue(UriType.user)); - Assert.IsNull(uri.GetUriPropValue(UriType.user)); - } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Tests/packages.config b/SpotifyAPI.Tests/packages.config deleted file mode 100644 index 1b3f7008..00000000 --- a/SpotifyAPI.Tests/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/AuthUtil.cs b/SpotifyAPI.Web.Auth/AuthUtil.cs new file mode 100644 index 00000000..a6ff6545 --- /dev/null +++ b/SpotifyAPI.Web.Auth/AuthUtil.cs @@ -0,0 +1,29 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace SpotifyAPI.Web.Auth +{ + internal static class AuthUtil + { + public static void OpenBrowser(string url) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + url = url.Replace("&", "^&"); + Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + Process.Start("xdg-open", url); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + Process.Start("open", url); + } + else + { + // throw + } + } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/AuthorizationCodeAuth.cs b/SpotifyAPI.Web.Auth/AuthorizationCodeAuth.cs new file mode 100644 index 00000000..beaec0cb --- /dev/null +++ b/SpotifyAPI.Web.Auth/AuthorizationCodeAuth.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using SpotifyAPI.Web.Enums; +using SpotifyAPI.Web.Models; +using Unosquare.Labs.EmbedIO; +using Unosquare.Labs.EmbedIO.Constants; +using Unosquare.Labs.EmbedIO.Modules; + +namespace SpotifyAPI.Web.Auth +{ + public class AuthorizationCodeAuth : SpotifyAuthServer + { + public string SecretId { get; set; } + + public AuthorizationCodeAuth(string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") + : base("code", "AuthorizationCodeAuth", redirectUri, serverUri, scope, state) + { + } + + public AuthorizationCodeAuth(string clientId, string secretId, string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") + : this(redirectUri, serverUri, scope, state) + { + ClientId = clientId; + SecretId = secretId; + } + + private bool ShouldRegisterNewApp() + { + return string.IsNullOrEmpty(SecretId) || string.IsNullOrEmpty(ClientId); + } + + public override string GetUri() + { + return ShouldRegisterNewApp() ? $"{RedirectUri}/start.html#{State}" : base.GetUri(); + } + + protected override WebServer AdaptWebServer(WebServer webServer) => webServer.WithWebApiController(); + + public async Task ExchangeCode(string code) + { + string auth = Convert.ToBase64String(Encoding.UTF8.GetBytes(ClientId + ":" + SecretId)); + + List> args = new List>() + { + new KeyValuePair("grant_type", "authorization_code"), + new KeyValuePair("code", code), + new KeyValuePair("redirect_uri", RedirectUri) + }; + + HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("Authorization", $"Basic {auth}"); + HttpContent content = new FormUrlEncodedContent(args); + + HttpResponseMessage resp = await client.PostAsync("https://accounts.spotify.com/api/token", content); + string msg = await resp.Content.ReadAsStringAsync(); + + return JsonConvert.DeserializeObject(msg); + } + } + + public class AuthorizationCode + { + public string Code { get; set; } + + public string Error { get; set; } + } + + internal class AuthorizationCodeAuthController : WebApiController + { + [WebApiHandler(HttpVerbs.Get, "/")] + public Task GetEmpty(WebServer server, HttpListenerContext context) + { + string state = context.Request.QueryString["state"]; + AuthorizationCodeAuth.Instances.TryGetValue(state, out SpotifyAuthServer auth); + + string code = null; + string error = context.Request.QueryString["error"]; + if (error == null) + code = context.Request.QueryString["code"]; + + Task.Factory.StartNew(() => auth?.TriggerAuth(new AuthorizationCode + { + Code = code, + Error = error + })); + + return context.StringResponseAsync("OK - This window can be closed now"); + } + + [WebApiHandler(HttpVerbs.Post, "/")] + public bool PostValues(WebServer server, HttpListenerContext context) + { + Dictionary formParams = context.RequestFormDataDictionary(); + + string state = (string) formParams["state"]; + AuthorizationCodeAuth.Instances.TryGetValue(state, out SpotifyAuthServer authServer); + + AuthorizationCodeAuth auth = (AuthorizationCodeAuth) authServer; + auth.ClientId = (string) formParams["clientId"]; + auth.SecretId = (string) formParams["secretId"]; + + string uri = auth.GetUri(); + context.Response.Redirect(uri); + + return true; + } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/CredentialsAuth.cs b/SpotifyAPI.Web.Auth/CredentialsAuth.cs new file mode 100644 index 00000000..45b3d44b --- /dev/null +++ b/SpotifyAPI.Web.Auth/CredentialsAuth.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using SpotifyAPI.Web.Models; + +namespace SpotifyAPI.Web.Auth +{ + public class CredentialsAuth + { + public string ClientSecret { get; set; } + + public string ClientId { get; set; } + + public CredentialsAuth(string clientId, string clientSecret) + { + ClientId = clientId; + ClientSecret = clientSecret; + } + + public async Task GetToken() + { + string auth = Convert.ToBase64String(Encoding.UTF8.GetBytes(ClientId + ":" + ClientSecret)); + + List> args = new List>() + { + new KeyValuePair("grant_type", "client_credentials") + }; + + HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("Authorization", $"Basic {auth}"); + HttpContent content = new FormUrlEncodedContent(args); + + HttpResponseMessage resp = await client.PostAsync("https://accounts.spotify.com/api/token", content); + string msg = await resp.Content.ReadAsStringAsync(); + + return JsonConvert.DeserializeObject(msg); + } + } +} diff --git a/SpotifyAPI.Web.Auth/ImplictGrantAuth.cs b/SpotifyAPI.Web.Auth/ImplictGrantAuth.cs new file mode 100644 index 00000000..80477126 --- /dev/null +++ b/SpotifyAPI.Web.Auth/ImplictGrantAuth.cs @@ -0,0 +1,62 @@ +using System.Net; +using System.Threading.Tasks; +using SpotifyAPI.Web.Enums; +using SpotifyAPI.Web.Models; +using Unosquare.Labs.EmbedIO; +using Unosquare.Labs.EmbedIO.Constants; +using Unosquare.Labs.EmbedIO.Modules; + +namespace SpotifyAPI.Web.Auth +{ + public class ImplictGrantAuth : SpotifyAuthServer + { + public ImplictGrantAuth(string clientId, string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") : + base("token", "ImplicitGrantAuth", redirectUri, serverUri, scope, state) + { + ClientId = clientId; + } + + protected override WebServer AdaptWebServer(WebServer webServer) + { + return webServer.WithWebApiController(); + } + } + + public class ImplictGrantAuthController : WebApiController + { + [WebApiHandler(HttpVerbs.Get, "/auth")] + public Task GetAuth(WebServer server, HttpListenerContext context) + { + string state = context.Request.QueryString["state"]; + SpotifyAuthServer auth = ImplictGrantAuth.GetByState(state); + if (auth == null) + return context.StringResponseAsync( + $"Failed - Unable to find auth request with state \"{state}\" - Please retry"); + + Token token; + string error = context.Request.QueryString["error"]; + if (error == null) + { + string accessToken = context.Request.QueryString["access_token"]; + string tokenType = context.Request.QueryString["token_type"]; + string expiresIn = context.Request.QueryString["expires_in"]; + token = new Token + { + AccessToken = accessToken, + ExpiresIn = double.Parse(expiresIn), + TokenType = tokenType + }; + } + else + { + token = new Token() + { + Error = error + }; + } + + Task.Factory.StartNew(() => auth?.TriggerAuth(token)); + return context.StringResponseAsync("OK - This window can be closed now"); + } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/css/bulma.min.css b/SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/css/bulma.min.css new file mode 100644 index 00000000..59825f7f --- /dev/null +++ b/SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/css/bulma.min.css @@ -0,0 +1 @@ +/*! bulma.io v0.7.1 | MIT License | github.com/jgthms/bulma */@-webkit-keyframes spinAround{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes spinAround{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.breadcrumb,.button,.delete,.file,.is-unselectable,.modal-close,.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous,.tabs{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.navbar-link::after,.select:not(.is-multiple):not(.is-loading)::after{border:3px solid transparent;border-radius:2px;border-right:0;border-top:0;content:" ";display:block;height:.625em;margin-top:-.4375em;pointer-events:none;position:absolute;top:50%;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transform-origin:center;transform-origin:center;width:.625em}.block:not(:last-child),.box:not(:last-child),.breadcrumb:not(:last-child),.content:not(:last-child),.highlight:not(:last-child),.level:not(:last-child),.message:not(:last-child),.notification:not(:last-child),.progress:not(:last-child),.subtitle:not(:last-child),.table-container:not(:last-child),.table:not(:last-child),.tabs:not(:last-child),.title:not(:last-child){margin-bottom:1.5rem}.delete,.modal-close{-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,.2);border:none;border-radius:290486px;cursor:pointer;display:inline-block;flex-grow:0;flex-shrink:0;font-size:0;height:20px;max-height:20px;max-width:20px;min-height:20px;min-width:20px;outline:0;position:relative;vertical-align:top;width:20px}.delete::after,.delete::before,.modal-close::after,.modal-close::before{background-color:#fff;content:"";display:block;left:50%;position:absolute;top:50%;-webkit-transform:translateX(-50%) translateY(-50%) rotate(45deg);transform:translateX(-50%) translateY(-50%) rotate(45deg);-webkit-transform-origin:center center;transform-origin:center center}.delete::before,.modal-close::before{height:2px;width:50%}.delete::after,.modal-close::after{height:50%;width:2px}.delete:focus,.delete:hover,.modal-close:focus,.modal-close:hover{background-color:rgba(10,10,10,.3)}.delete:active,.modal-close:active{background-color:rgba(10,10,10,.4)}.is-small.delete,.is-small.modal-close{height:16px;max-height:16px;max-width:16px;min-height:16px;min-width:16px;width:16px}.is-medium.delete,.is-medium.modal-close{height:24px;max-height:24px;max-width:24px;min-height:24px;min-width:24px;width:24px}.is-large.delete,.is-large.modal-close{height:32px;max-height:32px;max-width:32px;min-height:32px;min-width:32px;width:32px}.button.is-loading::after,.control.is-loading::after,.loader,.select.is-loading::after{-webkit-animation:spinAround .5s infinite linear;animation:spinAround .5s infinite linear;border:2px solid #dbdbdb;border-radius:290486px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}.hero-video,.image.is-16by9 img,.image.is-1by1 img,.image.is-1by2 img,.image.is-1by3 img,.image.is-2by1 img,.image.is-2by3 img,.image.is-3by1 img,.image.is-3by2 img,.image.is-3by4 img,.image.is-3by5 img,.image.is-4by3 img,.image.is-4by5 img,.image.is-5by3 img,.image.is-5by4 img,.image.is-9by16 img,.image.is-square img,.is-overlay,.modal,.modal-background{bottom:0;left:0;position:absolute;right:0;top:0}.button,.file-cta,.file-name,.input,.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous,.select select,.textarea{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:4px;box-shadow:none;display:inline-flex;font-size:1rem;height:2.25em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(.375em - 1px);padding-left:calc(.625em - 1px);padding-right:calc(.625em - 1px);padding-top:calc(.375em - 1px);position:relative;vertical-align:top}.button:active,.button:focus,.file-cta:active,.file-cta:focus,.file-name:active,.file-name:focus,.input:active,.input:focus,.is-active.button,.is-active.file-cta,.is-active.file-name,.is-active.input,.is-active.pagination-ellipsis,.is-active.pagination-link,.is-active.pagination-next,.is-active.pagination-previous,.is-active.textarea,.is-focused.button,.is-focused.file-cta,.is-focused.file-name,.is-focused.input,.is-focused.pagination-ellipsis,.is-focused.pagination-link,.is-focused.pagination-next,.is-focused.pagination-previous,.is-focused.textarea,.pagination-ellipsis:active,.pagination-ellipsis:focus,.pagination-link:active,.pagination-link:focus,.pagination-next:active,.pagination-next:focus,.pagination-previous:active,.pagination-previous:focus,.select select.is-active,.select select.is-focused,.select select:active,.select select:focus,.textarea:active,.textarea:focus{outline:0}.button[disabled],.file-cta[disabled],.file-name[disabled],.input[disabled],.pagination-ellipsis[disabled],.pagination-link[disabled],.pagination-next[disabled],.pagination-previous[disabled],.select select[disabled],.textarea[disabled]{cursor:not-allowed}/*! minireset.css v0.0.3 | MIT License | github.com/jgthms/minireset.css */blockquote,body,dd,dl,dt,fieldset,figure,h1,h2,h3,h4,h5,h6,hr,html,iframe,legend,li,ol,p,pre,textarea,ul{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:400}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,::after,::before{box-sizing:inherit}audio,img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0;text-align:left}html{background-color:#fff;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:hidden;overflow-y:scroll;text-rendering:optimizeLegibility;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;-ms-text-size-adjust:100%;text-size-adjust:100%}article,aside,figure,footer,header,hgroup,section{display:block}body,button,input,select,textarea{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif}code,pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:monospace}body{color:#4a4a4a;font-size:1rem;font-weight:400;line-height:1.5}a{color:#3273dc;cursor:pointer;text-decoration:none}a strong{color:currentColor}a:hover{color:#363636}code{background-color:#f5f5f5;color:#ff3860;font-size:.875em;font-weight:400;padding:.25em .5em .25em}hr{background-color:#f5f5f5;border:none;display:block;height:2px;margin:1.5rem 0}img{height:auto;max-width:100%}input[type=checkbox],input[type=radio]{vertical-align:baseline}small{font-size:.875em}span{font-style:inherit;font-weight:inherit}strong{color:#363636;font-weight:700}pre{-webkit-overflow-scrolling:touch;background-color:#f5f5f5;color:#4a4a4a;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}table td,table th{text-align:left;vertical-align:top}table th{color:#363636}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left!important}.is-pulled-right{float:right!important}.is-clipped{overflow:hidden!important}.is-size-1{font-size:3rem!important}.is-size-2{font-size:2.5rem!important}.is-size-3{font-size:2rem!important}.is-size-4{font-size:1.5rem!important}.is-size-5{font-size:1.25rem!important}.is-size-6{font-size:1rem!important}.is-size-7{font-size:.75rem!important}@media screen and (max-width:768px){.is-size-1-mobile{font-size:3rem!important}.is-size-2-mobile{font-size:2.5rem!important}.is-size-3-mobile{font-size:2rem!important}.is-size-4-mobile{font-size:1.5rem!important}.is-size-5-mobile{font-size:1.25rem!important}.is-size-6-mobile{font-size:1rem!important}.is-size-7-mobile{font-size:.75rem!important}}@media screen and (min-width:769px),print{.is-size-1-tablet{font-size:3rem!important}.is-size-2-tablet{font-size:2.5rem!important}.is-size-3-tablet{font-size:2rem!important}.is-size-4-tablet{font-size:1.5rem!important}.is-size-5-tablet{font-size:1.25rem!important}.is-size-6-tablet{font-size:1rem!important}.is-size-7-tablet{font-size:.75rem!important}}@media screen and (max-width:1087px){.is-size-1-touch{font-size:3rem!important}.is-size-2-touch{font-size:2.5rem!important}.is-size-3-touch{font-size:2rem!important}.is-size-4-touch{font-size:1.5rem!important}.is-size-5-touch{font-size:1.25rem!important}.is-size-6-touch{font-size:1rem!important}.is-size-7-touch{font-size:.75rem!important}}@media screen and (min-width:1088px){.is-size-1-desktop{font-size:3rem!important}.is-size-2-desktop{font-size:2.5rem!important}.is-size-3-desktop{font-size:2rem!important}.is-size-4-desktop{font-size:1.5rem!important}.is-size-5-desktop{font-size:1.25rem!important}.is-size-6-desktop{font-size:1rem!important}.is-size-7-desktop{font-size:.75rem!important}}@media screen and (min-width:1280px){.is-size-1-widescreen{font-size:3rem!important}.is-size-2-widescreen{font-size:2.5rem!important}.is-size-3-widescreen{font-size:2rem!important}.is-size-4-widescreen{font-size:1.5rem!important}.is-size-5-widescreen{font-size:1.25rem!important}.is-size-6-widescreen{font-size:1rem!important}.is-size-7-widescreen{font-size:.75rem!important}}@media screen and (min-width:1472px){.is-size-1-fullhd{font-size:3rem!important}.is-size-2-fullhd{font-size:2.5rem!important}.is-size-3-fullhd{font-size:2rem!important}.is-size-4-fullhd{font-size:1.5rem!important}.is-size-5-fullhd{font-size:1.25rem!important}.is-size-6-fullhd{font-size:1rem!important}.is-size-7-fullhd{font-size:.75rem!important}}.has-text-centered{text-align:center!important}.has-text-justified{text-align:justify!important}.has-text-left{text-align:left!important}.has-text-right{text-align:right!important}@media screen and (max-width:768px){.has-text-centered-mobile{text-align:center!important}}@media screen and (min-width:769px),print{.has-text-centered-tablet{text-align:center!important}}@media screen and (min-width:769px) and (max-width:1087px){.has-text-centered-tablet-only{text-align:center!important}}@media screen and (max-width:1087px){.has-text-centered-touch{text-align:center!important}}@media screen and (min-width:1088px){.has-text-centered-desktop{text-align:center!important}}@media screen and (min-width:1088px) and (max-width:1279px){.has-text-centered-desktop-only{text-align:center!important}}@media screen and (min-width:1280px){.has-text-centered-widescreen{text-align:center!important}}@media screen and (min-width:1280px) and (max-width:1471px){.has-text-centered-widescreen-only{text-align:center!important}}@media screen and (min-width:1472px){.has-text-centered-fullhd{text-align:center!important}}@media screen and (max-width:768px){.has-text-justified-mobile{text-align:justify!important}}@media screen and (min-width:769px),print{.has-text-justified-tablet{text-align:justify!important}}@media screen and (min-width:769px) and (max-width:1087px){.has-text-justified-tablet-only{text-align:justify!important}}@media screen and (max-width:1087px){.has-text-justified-touch{text-align:justify!important}}@media screen and (min-width:1088px){.has-text-justified-desktop{text-align:justify!important}}@media screen and (min-width:1088px) and (max-width:1279px){.has-text-justified-desktop-only{text-align:justify!important}}@media screen and (min-width:1280px){.has-text-justified-widescreen{text-align:justify!important}}@media screen and (min-width:1280px) and (max-width:1471px){.has-text-justified-widescreen-only{text-align:justify!important}}@media screen and (min-width:1472px){.has-text-justified-fullhd{text-align:justify!important}}@media screen and (max-width:768px){.has-text-left-mobile{text-align:left!important}}@media screen and (min-width:769px),print{.has-text-left-tablet{text-align:left!important}}@media screen and (min-width:769px) and (max-width:1087px){.has-text-left-tablet-only{text-align:left!important}}@media screen and (max-width:1087px){.has-text-left-touch{text-align:left!important}}@media screen and (min-width:1088px){.has-text-left-desktop{text-align:left!important}}@media screen and (min-width:1088px) and (max-width:1279px){.has-text-left-desktop-only{text-align:left!important}}@media screen and (min-width:1280px){.has-text-left-widescreen{text-align:left!important}}@media screen and (min-width:1280px) and (max-width:1471px){.has-text-left-widescreen-only{text-align:left!important}}@media screen and (min-width:1472px){.has-text-left-fullhd{text-align:left!important}}@media screen and (max-width:768px){.has-text-right-mobile{text-align:right!important}}@media screen and (min-width:769px),print{.has-text-right-tablet{text-align:right!important}}@media screen and (min-width:769px) and (max-width:1087px){.has-text-right-tablet-only{text-align:right!important}}@media screen and (max-width:1087px){.has-text-right-touch{text-align:right!important}}@media screen and (min-width:1088px){.has-text-right-desktop{text-align:right!important}}@media screen and (min-width:1088px) and (max-width:1279px){.has-text-right-desktop-only{text-align:right!important}}@media screen and (min-width:1280px){.has-text-right-widescreen{text-align:right!important}}@media screen and (min-width:1280px) and (max-width:1471px){.has-text-right-widescreen-only{text-align:right!important}}@media screen and (min-width:1472px){.has-text-right-fullhd{text-align:right!important}}.is-capitalized{text-transform:capitalize!important}.is-lowercase{text-transform:lowercase!important}.is-uppercase{text-transform:uppercase!important}.is-italic{font-style:italic!important}.has-text-white{color:#fff!important}a.has-text-white:focus,a.has-text-white:hover{color:#e6e6e6!important}.has-background-white{background-color:#fff!important}.has-text-black{color:#0a0a0a!important}a.has-text-black:focus,a.has-text-black:hover{color:#000!important}.has-background-black{background-color:#0a0a0a!important}.has-text-light{color:#f5f5f5!important}a.has-text-light:focus,a.has-text-light:hover{color:#dbdbdb!important}.has-background-light{background-color:#f5f5f5!important}.has-text-dark{color:#363636!important}a.has-text-dark:focus,a.has-text-dark:hover{color:#1c1c1c!important}.has-background-dark{background-color:#363636!important}.has-text-primary{color:#00d1b2!important}a.has-text-primary:focus,a.has-text-primary:hover{color:#009e86!important}.has-background-primary{background-color:#00d1b2!important}.has-text-link{color:#3273dc!important}a.has-text-link:focus,a.has-text-link:hover{color:#205bbc!important}.has-background-link{background-color:#3273dc!important}.has-text-info{color:#209cee!important}a.has-text-info:focus,a.has-text-info:hover{color:#0f81cc!important}.has-background-info{background-color:#209cee!important}.has-text-success{color:#23d160!important}a.has-text-success:focus,a.has-text-success:hover{color:#1ca64c!important}.has-background-success{background-color:#23d160!important}.has-text-warning{color:#ffdd57!important}a.has-text-warning:focus,a.has-text-warning:hover{color:#ffd324!important}.has-background-warning{background-color:#ffdd57!important}.has-text-danger{color:#ff3860!important}a.has-text-danger:focus,a.has-text-danger:hover{color:#ff0537!important}.has-background-danger{background-color:#ff3860!important}.has-text-black-bis{color:#121212!important}.has-background-black-bis{background-color:#121212!important}.has-text-black-ter{color:#242424!important}.has-background-black-ter{background-color:#242424!important}.has-text-grey-darker{color:#363636!important}.has-background-grey-darker{background-color:#363636!important}.has-text-grey-dark{color:#4a4a4a!important}.has-background-grey-dark{background-color:#4a4a4a!important}.has-text-grey{color:#7a7a7a!important}.has-background-grey{background-color:#7a7a7a!important}.has-text-grey-light{color:#b5b5b5!important}.has-background-grey-light{background-color:#b5b5b5!important}.has-text-grey-lighter{color:#dbdbdb!important}.has-background-grey-lighter{background-color:#dbdbdb!important}.has-text-white-ter{color:#f5f5f5!important}.has-background-white-ter{background-color:#f5f5f5!important}.has-text-white-bis{color:#fafafa!important}.has-background-white-bis{background-color:#fafafa!important}.has-text-weight-light{font-weight:300!important}.has-text-weight-normal{font-weight:400!important}.has-text-weight-semibold{font-weight:600!important}.has-text-weight-bold{font-weight:700!important}.is-block{display:block!important}@media screen and (max-width:768px){.is-block-mobile{display:block!important}}@media screen and (min-width:769px),print{.is-block-tablet{display:block!important}}@media screen and (min-width:769px) and (max-width:1087px){.is-block-tablet-only{display:block!important}}@media screen and (max-width:1087px){.is-block-touch{display:block!important}}@media screen and (min-width:1088px){.is-block-desktop{display:block!important}}@media screen and (min-width:1088px) and (max-width:1279px){.is-block-desktop-only{display:block!important}}@media screen and (min-width:1280px){.is-block-widescreen{display:block!important}}@media screen and (min-width:1280px) and (max-width:1471px){.is-block-widescreen-only{display:block!important}}@media screen and (min-width:1472px){.is-block-fullhd{display:block!important}}.is-flex{display:flex!important}@media screen and (max-width:768px){.is-flex-mobile{display:flex!important}}@media screen and (min-width:769px),print{.is-flex-tablet{display:flex!important}}@media screen and (min-width:769px) and (max-width:1087px){.is-flex-tablet-only{display:flex!important}}@media screen and (max-width:1087px){.is-flex-touch{display:flex!important}}@media screen and (min-width:1088px){.is-flex-desktop{display:flex!important}}@media screen and (min-width:1088px) and (max-width:1279px){.is-flex-desktop-only{display:flex!important}}@media screen and (min-width:1280px){.is-flex-widescreen{display:flex!important}}@media screen and (min-width:1280px) and (max-width:1471px){.is-flex-widescreen-only{display:flex!important}}@media screen and (min-width:1472px){.is-flex-fullhd{display:flex!important}}.is-inline{display:inline!important}@media screen and (max-width:768px){.is-inline-mobile{display:inline!important}}@media screen and (min-width:769px),print{.is-inline-tablet{display:inline!important}}@media screen and (min-width:769px) and (max-width:1087px){.is-inline-tablet-only{display:inline!important}}@media screen and (max-width:1087px){.is-inline-touch{display:inline!important}}@media screen and (min-width:1088px){.is-inline-desktop{display:inline!important}}@media screen and (min-width:1088px) and (max-width:1279px){.is-inline-desktop-only{display:inline!important}}@media screen and (min-width:1280px){.is-inline-widescreen{display:inline!important}}@media screen and (min-width:1280px) and (max-width:1471px){.is-inline-widescreen-only{display:inline!important}}@media screen and (min-width:1472px){.is-inline-fullhd{display:inline!important}}.is-inline-block{display:inline-block!important}@media screen and (max-width:768px){.is-inline-block-mobile{display:inline-block!important}}@media screen and (min-width:769px),print{.is-inline-block-tablet{display:inline-block!important}}@media screen and (min-width:769px) and (max-width:1087px){.is-inline-block-tablet-only{display:inline-block!important}}@media screen and (max-width:1087px){.is-inline-block-touch{display:inline-block!important}}@media screen and (min-width:1088px){.is-inline-block-desktop{display:inline-block!important}}@media screen and (min-width:1088px) and (max-width:1279px){.is-inline-block-desktop-only{display:inline-block!important}}@media screen and (min-width:1280px){.is-inline-block-widescreen{display:inline-block!important}}@media screen and (min-width:1280px) and (max-width:1471px){.is-inline-block-widescreen-only{display:inline-block!important}}@media screen and (min-width:1472px){.is-inline-block-fullhd{display:inline-block!important}}.is-inline-flex{display:inline-flex!important}@media screen and (max-width:768px){.is-inline-flex-mobile{display:inline-flex!important}}@media screen and (min-width:769px),print{.is-inline-flex-tablet{display:inline-flex!important}}@media screen and (min-width:769px) and (max-width:1087px){.is-inline-flex-tablet-only{display:inline-flex!important}}@media screen and (max-width:1087px){.is-inline-flex-touch{display:inline-flex!important}}@media screen and (min-width:1088px){.is-inline-flex-desktop{display:inline-flex!important}}@media screen and (min-width:1088px) and (max-width:1279px){.is-inline-flex-desktop-only{display:inline-flex!important}}@media screen and (min-width:1280px){.is-inline-flex-widescreen{display:inline-flex!important}}@media screen and (min-width:1280px) and (max-width:1471px){.is-inline-flex-widescreen-only{display:inline-flex!important}}@media screen and (min-width:1472px){.is-inline-flex-fullhd{display:inline-flex!important}}.is-hidden{display:none!important}@media screen and (max-width:768px){.is-hidden-mobile{display:none!important}}@media screen and (min-width:769px),print{.is-hidden-tablet{display:none!important}}@media screen and (min-width:769px) and (max-width:1087px){.is-hidden-tablet-only{display:none!important}}@media screen and (max-width:1087px){.is-hidden-touch{display:none!important}}@media screen and (min-width:1088px){.is-hidden-desktop{display:none!important}}@media screen and (min-width:1088px) and (max-width:1279px){.is-hidden-desktop-only{display:none!important}}@media screen and (min-width:1280px){.is-hidden-widescreen{display:none!important}}@media screen and (min-width:1280px) and (max-width:1471px){.is-hidden-widescreen-only{display:none!important}}@media screen and (min-width:1472px){.is-hidden-fullhd{display:none!important}}.is-invisible{visibility:hidden!important}@media screen and (max-width:768px){.is-invisible-mobile{visibility:hidden!important}}@media screen and (min-width:769px),print{.is-invisible-tablet{visibility:hidden!important}}@media screen and (min-width:769px) and (max-width:1087px){.is-invisible-tablet-only{visibility:hidden!important}}@media screen and (max-width:1087px){.is-invisible-touch{visibility:hidden!important}}@media screen and (min-width:1088px){.is-invisible-desktop{visibility:hidden!important}}@media screen and (min-width:1088px) and (max-width:1279px){.is-invisible-desktop-only{visibility:hidden!important}}@media screen and (min-width:1280px){.is-invisible-widescreen{visibility:hidden!important}}@media screen and (min-width:1280px) and (max-width:1471px){.is-invisible-widescreen-only{visibility:hidden!important}}@media screen and (min-width:1472px){.is-invisible-fullhd{visibility:hidden!important}}.is-marginless{margin:0!important}.is-paddingless{padding:0!important}.is-radiusless{border-radius:0!important}.is-shadowless{box-shadow:none!important}.box{background-color:#fff;border-radius:6px;box-shadow:0 2px 3px rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.1);color:#4a4a4a;display:block;padding:1.25rem}a.box:focus,a.box:hover{box-shadow:0 2px 3px rgba(10,10,10,.1),0 0 0 1px #3273dc}a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,.2),0 0 0 1px #3273dc}.button{background-color:#fff;border-color:#dbdbdb;border-width:1px;color:#363636;cursor:pointer;justify-content:center;padding-bottom:calc(.375em - 1px);padding-left:.75em;padding-right:.75em;padding-top:calc(.375em - 1px);text-align:center;white-space:nowrap}.button strong{color:inherit}.button .icon,.button .icon.is-large,.button .icon.is-medium,.button .icon.is-small{height:1.5em;width:1.5em}.button .icon:first-child:not(:last-child){margin-left:calc(-.375em - 1px);margin-right:.1875em}.button .icon:last-child:not(:first-child){margin-left:.1875em;margin-right:calc(-.375em - 1px)}.button .icon:first-child:last-child{margin-left:calc(-.375em - 1px);margin-right:calc(-.375em - 1px)}.button.is-hovered,.button:hover{border-color:#b5b5b5;color:#363636}.button.is-focused,.button:focus{border-color:#3273dc;color:#363636}.button.is-focused:not(:active),.button:focus:not(:active){box-shadow:0 0 0 .125em rgba(50,115,220,.25)}.button.is-active,.button:active{border-color:#4a4a4a;color:#363636}.button.is-text{background-color:transparent;border-color:transparent;color:#4a4a4a;text-decoration:underline}.button.is-text.is-focused,.button.is-text.is-hovered,.button.is-text:focus,.button.is-text:hover{background-color:#f5f5f5;color:#363636}.button.is-text.is-active,.button.is-text:active{background-color:#e8e8e8;color:#363636}.button.is-text[disabled]{background-color:transparent;border-color:transparent;box-shadow:none}.button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}.button.is-white.is-hovered,.button.is-white:hover{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.button.is-white.is-focused,.button.is-white:focus{border-color:transparent;color:#0a0a0a}.button.is-white.is-focused:not(:active),.button.is-white:focus:not(:active){box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.button.is-white.is-active,.button.is-white:active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.button.is-white[disabled]{background-color:#fff;border-color:transparent;box-shadow:none}.button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted:hover{background-color:#000}.button.is-white.is-inverted[disabled]{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}.button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-white.is-outlined:focus,.button.is-white.is-outlined:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-white.is-outlined[disabled]{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-white.is-inverted.is-outlined:focus,.button.is-white.is-inverted.is-outlined:hover{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-outlined[disabled]{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}.button.is-black.is-hovered,.button.is-black:hover{background-color:#040404;border-color:transparent;color:#fff}.button.is-black.is-focused,.button.is-black:focus{border-color:transparent;color:#fff}.button.is-black.is-focused:not(:active),.button.is-black:focus:not(:active){box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.button.is-black.is-active,.button.is-black:active{background-color:#000;border-color:transparent;color:#fff}.button.is-black[disabled]{background-color:#0a0a0a;border-color:transparent;box-shadow:none}.button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted:hover{background-color:#f2f2f2}.button.is-black.is-inverted[disabled]{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}.button.is-black.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-black.is-outlined:focus,.button.is-black.is-outlined:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-black.is-outlined[disabled]{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-black.is-inverted.is-outlined:focus,.button.is-black.is-inverted.is-outlined:hover{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-outlined[disabled]{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-light{background-color:#f5f5f5;border-color:transparent;color:#363636}.button.is-light.is-hovered,.button.is-light:hover{background-color:#eee;border-color:transparent;color:#363636}.button.is-light.is-focused,.button.is-light:focus{border-color:transparent;color:#363636}.button.is-light.is-focused:not(:active),.button.is-light:focus:not(:active){box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.button.is-light.is-active,.button.is-light:active{background-color:#e8e8e8;border-color:transparent;color:#363636}.button.is-light[disabled]{background-color:#f5f5f5;border-color:transparent;box-shadow:none}.button.is-light.is-inverted{background-color:#363636;color:#f5f5f5}.button.is-light.is-inverted:hover{background-color:#292929}.button.is-light.is-inverted[disabled]{background-color:#363636;border-color:transparent;box-shadow:none;color:#f5f5f5}.button.is-light.is-loading::after{border-color:transparent transparent #363636 #363636!important}.button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;color:#f5f5f5}.button.is-light.is-outlined:focus,.button.is-light.is-outlined:hover{background-color:#f5f5f5;border-color:#f5f5f5;color:#363636}.button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #f5f5f5 #f5f5f5!important}.button.is-light.is-outlined[disabled]{background-color:transparent;border-color:#f5f5f5;box-shadow:none;color:#f5f5f5}.button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:#363636;color:#363636}.button.is-light.is-inverted.is-outlined:focus,.button.is-light.is-inverted.is-outlined:hover{background-color:#363636;color:#f5f5f5}.button.is-light.is-inverted.is-outlined[disabled]{background-color:transparent;border-color:#363636;box-shadow:none;color:#363636}.button.is-dark{background-color:#363636;border-color:transparent;color:#f5f5f5}.button.is-dark.is-hovered,.button.is-dark:hover{background-color:#2f2f2f;border-color:transparent;color:#f5f5f5}.button.is-dark.is-focused,.button.is-dark:focus{border-color:transparent;color:#f5f5f5}.button.is-dark.is-focused:not(:active),.button.is-dark:focus:not(:active){box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.button.is-dark.is-active,.button.is-dark:active{background-color:#292929;border-color:transparent;color:#f5f5f5}.button.is-dark[disabled]{background-color:#363636;border-color:transparent;box-shadow:none}.button.is-dark.is-inverted{background-color:#f5f5f5;color:#363636}.button.is-dark.is-inverted:hover{background-color:#e8e8e8}.button.is-dark.is-inverted[disabled]{background-color:#f5f5f5;border-color:transparent;box-shadow:none;color:#363636}.button.is-dark.is-loading::after{border-color:transparent transparent #f5f5f5 #f5f5f5!important}.button.is-dark.is-outlined{background-color:transparent;border-color:#363636;color:#363636}.button.is-dark.is-outlined:focus,.button.is-dark.is-outlined:hover{background-color:#363636;border-color:#363636;color:#f5f5f5}.button.is-dark.is-outlined.is-loading::after{border-color:transparent transparent #363636 #363636!important}.button.is-dark.is-outlined[disabled]{background-color:transparent;border-color:#363636;box-shadow:none;color:#363636}.button.is-dark.is-inverted.is-outlined{background-color:transparent;border-color:#f5f5f5;color:#f5f5f5}.button.is-dark.is-inverted.is-outlined:focus,.button.is-dark.is-inverted.is-outlined:hover{background-color:#f5f5f5;color:#363636}.button.is-dark.is-inverted.is-outlined[disabled]{background-color:transparent;border-color:#f5f5f5;box-shadow:none;color:#f5f5f5}.button.is-primary{background-color:#00d1b2;border-color:transparent;color:#fff}.button.is-primary.is-hovered,.button.is-primary:hover{background-color:#00c4a7;border-color:transparent;color:#fff}.button.is-primary.is-focused,.button.is-primary:focus{border-color:transparent;color:#fff}.button.is-primary.is-focused:not(:active),.button.is-primary:focus:not(:active){box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.button.is-primary.is-active,.button.is-primary:active{background-color:#00b89c;border-color:transparent;color:#fff}.button.is-primary[disabled]{background-color:#00d1b2;border-color:transparent;box-shadow:none}.button.is-primary.is-inverted{background-color:#fff;color:#00d1b2}.button.is-primary.is-inverted:hover{background-color:#f2f2f2}.button.is-primary.is-inverted[disabled]{background-color:#fff;border-color:transparent;box-shadow:none;color:#00d1b2}.button.is-primary.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-primary.is-outlined{background-color:transparent;border-color:#00d1b2;color:#00d1b2}.button.is-primary.is-outlined:focus,.button.is-primary.is-outlined:hover{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.button.is-primary.is-outlined.is-loading::after{border-color:transparent transparent #00d1b2 #00d1b2!important}.button.is-primary.is-outlined[disabled]{background-color:transparent;border-color:#00d1b2;box-shadow:none;color:#00d1b2}.button.is-primary.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-primary.is-inverted.is-outlined:focus,.button.is-primary.is-inverted.is-outlined:hover{background-color:#fff;color:#00d1b2}.button.is-primary.is-inverted.is-outlined[disabled]{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-link{background-color:#3273dc;border-color:transparent;color:#fff}.button.is-link.is-hovered,.button.is-link:hover{background-color:#276cda;border-color:transparent;color:#fff}.button.is-link.is-focused,.button.is-link:focus{border-color:transparent;color:#fff}.button.is-link.is-focused:not(:active),.button.is-link:focus:not(:active){box-shadow:0 0 0 .125em rgba(50,115,220,.25)}.button.is-link.is-active,.button.is-link:active{background-color:#2366d1;border-color:transparent;color:#fff}.button.is-link[disabled]{background-color:#3273dc;border-color:transparent;box-shadow:none}.button.is-link.is-inverted{background-color:#fff;color:#3273dc}.button.is-link.is-inverted:hover{background-color:#f2f2f2}.button.is-link.is-inverted[disabled]{background-color:#fff;border-color:transparent;box-shadow:none;color:#3273dc}.button.is-link.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-link.is-outlined{background-color:transparent;border-color:#3273dc;color:#3273dc}.button.is-link.is-outlined:focus,.button.is-link.is-outlined:hover{background-color:#3273dc;border-color:#3273dc;color:#fff}.button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #3273dc #3273dc!important}.button.is-link.is-outlined[disabled]{background-color:transparent;border-color:#3273dc;box-shadow:none;color:#3273dc}.button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-link.is-inverted.is-outlined:focus,.button.is-link.is-inverted.is-outlined:hover{background-color:#fff;color:#3273dc}.button.is-link.is-inverted.is-outlined[disabled]{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-info{background-color:#209cee;border-color:transparent;color:#fff}.button.is-info.is-hovered,.button.is-info:hover{background-color:#1496ed;border-color:transparent;color:#fff}.button.is-info.is-focused,.button.is-info:focus{border-color:transparent;color:#fff}.button.is-info.is-focused:not(:active),.button.is-info:focus:not(:active){box-shadow:0 0 0 .125em rgba(32,156,238,.25)}.button.is-info.is-active,.button.is-info:active{background-color:#118fe4;border-color:transparent;color:#fff}.button.is-info[disabled]{background-color:#209cee;border-color:transparent;box-shadow:none}.button.is-info.is-inverted{background-color:#fff;color:#209cee}.button.is-info.is-inverted:hover{background-color:#f2f2f2}.button.is-info.is-inverted[disabled]{background-color:#fff;border-color:transparent;box-shadow:none;color:#209cee}.button.is-info.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-info.is-outlined{background-color:transparent;border-color:#209cee;color:#209cee}.button.is-info.is-outlined:focus,.button.is-info.is-outlined:hover{background-color:#209cee;border-color:#209cee;color:#fff}.button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #209cee #209cee!important}.button.is-info.is-outlined[disabled]{background-color:transparent;border-color:#209cee;box-shadow:none;color:#209cee}.button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-info.is-inverted.is-outlined:focus,.button.is-info.is-inverted.is-outlined:hover{background-color:#fff;color:#209cee}.button.is-info.is-inverted.is-outlined[disabled]{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-success{background-color:#23d160;border-color:transparent;color:#fff}.button.is-success.is-hovered,.button.is-success:hover{background-color:#22c65b;border-color:transparent;color:#fff}.button.is-success.is-focused,.button.is-success:focus{border-color:transparent;color:#fff}.button.is-success.is-focused:not(:active),.button.is-success:focus:not(:active){box-shadow:0 0 0 .125em rgba(35,209,96,.25)}.button.is-success.is-active,.button.is-success:active{background-color:#20bc56;border-color:transparent;color:#fff}.button.is-success[disabled]{background-color:#23d160;border-color:transparent;box-shadow:none}.button.is-success.is-inverted{background-color:#fff;color:#23d160}.button.is-success.is-inverted:hover{background-color:#f2f2f2}.button.is-success.is-inverted[disabled]{background-color:#fff;border-color:transparent;box-shadow:none;color:#23d160}.button.is-success.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-success.is-outlined{background-color:transparent;border-color:#23d160;color:#23d160}.button.is-success.is-outlined:focus,.button.is-success.is-outlined:hover{background-color:#23d160;border-color:#23d160;color:#fff}.button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #23d160 #23d160!important}.button.is-success.is-outlined[disabled]{background-color:transparent;border-color:#23d160;box-shadow:none;color:#23d160}.button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-success.is-inverted.is-outlined:focus,.button.is-success.is-inverted.is-outlined:hover{background-color:#fff;color:#23d160}.button.is-success.is-inverted.is-outlined[disabled]{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-warning{background-color:#ffdd57;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-hovered,.button.is-warning:hover{background-color:#ffdb4a;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-focused,.button.is-warning:focus{border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-focused:not(:active),.button.is-warning:focus:not(:active){box-shadow:0 0 0 .125em rgba(255,221,87,.25)}.button.is-warning.is-active,.button.is-warning:active{background-color:#ffd83d;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning[disabled]{background-color:#ffdd57;border-color:transparent;box-shadow:none}.button.is-warning.is-inverted{background-color:rgba(0,0,0,.7);color:#ffdd57}.button.is-warning.is-inverted:hover{background-color:rgba(0,0,0,.7)}.button.is-warning.is-inverted[disabled]{background-color:rgba(0,0,0,.7);border-color:transparent;box-shadow:none;color:#ffdd57}.button.is-warning.is-loading::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-warning.is-outlined{background-color:transparent;border-color:#ffdd57;color:#ffdd57}.button.is-warning.is-outlined:focus,.button.is-warning.is-outlined:hover{background-color:#ffdd57;border-color:#ffdd57;color:rgba(0,0,0,.7)}.button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ffdd57 #ffdd57!important}.button.is-warning.is-outlined[disabled]{background-color:transparent;border-color:#ffdd57;box-shadow:none;color:#ffdd57}.button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);color:rgba(0,0,0,.7)}.button.is-warning.is-inverted.is-outlined:focus,.button.is-warning.is-inverted.is-outlined:hover{background-color:rgba(0,0,0,.7);color:#ffdd57}.button.is-warning.is-inverted.is-outlined[disabled]{background-color:transparent;border-color:rgba(0,0,0,.7);box-shadow:none;color:rgba(0,0,0,.7)}.button.is-danger{background-color:#ff3860;border-color:transparent;color:#fff}.button.is-danger.is-hovered,.button.is-danger:hover{background-color:#ff2b56;border-color:transparent;color:#fff}.button.is-danger.is-focused,.button.is-danger:focus{border-color:transparent;color:#fff}.button.is-danger.is-focused:not(:active),.button.is-danger:focus:not(:active){box-shadow:0 0 0 .125em rgba(255,56,96,.25)}.button.is-danger.is-active,.button.is-danger:active{background-color:#ff1f4b;border-color:transparent;color:#fff}.button.is-danger[disabled]{background-color:#ff3860;border-color:transparent;box-shadow:none}.button.is-danger.is-inverted{background-color:#fff;color:#ff3860}.button.is-danger.is-inverted:hover{background-color:#f2f2f2}.button.is-danger.is-inverted[disabled]{background-color:#fff;border-color:transparent;box-shadow:none;color:#ff3860}.button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-danger.is-outlined{background-color:transparent;border-color:#ff3860;color:#ff3860}.button.is-danger.is-outlined:focus,.button.is-danger.is-outlined:hover{background-color:#ff3860;border-color:#ff3860;color:#fff}.button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #ff3860 #ff3860!important}.button.is-danger.is-outlined[disabled]{background-color:transparent;border-color:#ff3860;box-shadow:none;color:#ff3860}.button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-danger.is-inverted.is-outlined:focus,.button.is-danger.is-inverted.is-outlined:hover{background-color:#fff;color:#ff3860}.button.is-danger.is-inverted.is-outlined[disabled]{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-small{border-radius:2px;font-size:.75rem}.button.is-medium{font-size:1.25rem}.button.is-large{font-size:1.5rem}.button[disabled]{background-color:#fff;border-color:#dbdbdb;box-shadow:none;opacity:.5}.button.is-fullwidth{display:flex;width:100%}.button.is-loading{color:transparent!important;pointer-events:none}.button.is-loading::after{position:absolute;left:calc(50% - (1em / 2));top:calc(50% - (1em / 2));position:absolute!important}.button.is-static{background-color:#f5f5f5;border-color:#dbdbdb;color:#7a7a7a;box-shadow:none;pointer-events:none}.button.is-rounded{border-radius:290486px;padding-left:1em;padding-right:1em}.buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.buttons .button{margin-bottom:.5rem}.buttons .button:not(:last-child){margin-right:.5rem}.buttons:last-child{margin-bottom:-.5rem}.buttons:not(:last-child){margin-bottom:1rem}.buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}.buttons.has-addons .button:last-child{margin-right:0}.buttons.has-addons .button.is-hovered,.buttons.has-addons .button:hover{z-index:2}.buttons.has-addons .button.is-active,.buttons.has-addons .button.is-focused,.buttons.has-addons .button.is-selected,.buttons.has-addons .button:active,.buttons.has-addons .button:focus{z-index:3}.buttons.has-addons .button.is-active:hover,.buttons.has-addons .button.is-focused:hover,.buttons.has-addons .button.is-selected:hover,.buttons.has-addons .button:active:hover,.buttons.has-addons .button:focus:hover{z-index:4}.buttons.has-addons .button.is-expanded{flex-grow:1}.buttons.is-centered{justify-content:center}.buttons.is-right{justify-content:flex-end}.container{margin:0 auto;position:relative}@media screen and (min-width:1088px){.container{max-width:960px;width:960px}.container.is-fluid{margin-left:64px;margin-right:64px;max-width:none;width:auto}}@media screen and (max-width:1279px){.container.is-widescreen{max-width:1152px;width:auto}}@media screen and (max-width:1471px){.container.is-fullhd{max-width:1344px;width:auto}}@media screen and (min-width:1280px){.container{max-width:1152px;width:1152px}}@media screen and (min-width:1472px){.container{max-width:1344px;width:1344px}}.content li+li{margin-top:.25em}.content blockquote:not(:last-child),.content dl:not(:last-child),.content ol:not(:last-child),.content p:not(:last-child),.content pre:not(:last-child),.content table:not(:last-child),.content ul:not(:last-child){margin-bottom:1em}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6{color:#363636;font-weight:600;line-height:1.125}.content h1{font-size:2em;margin-bottom:.5em}.content h1:not(:first-child){margin-top:1em}.content h2{font-size:1.75em;margin-bottom:.5714em}.content h2:not(:first-child){margin-top:1.1428em}.content h3{font-size:1.5em;margin-bottom:.6666em}.content h3:not(:first-child){margin-top:1.3333em}.content h4{font-size:1.25em;margin-bottom:.8em}.content h5{font-size:1.125em;margin-bottom:.8888em}.content h6{font-size:1em;margin-bottom:1em}.content blockquote{background-color:#f5f5f5;border-left:5px solid #dbdbdb;padding:1.25em 1.5em}.content ol{list-style:decimal outside;margin-left:2em;margin-top:1em}.content ul{list-style:disc outside;margin-left:2em;margin-top:1em}.content ul ul{list-style-type:circle;margin-top:.5em}.content ul ul ul{list-style-type:square}.content dd{margin-left:2em}.content figure{margin-left:2em;margin-right:2em;text-align:center}.content figure:not(:first-child){margin-top:2em}.content figure:not(:last-child){margin-bottom:2em}.content figure img{display:inline-block}.content figure figcaption{font-style:italic}.content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:1.25em 1.5em;white-space:pre;word-wrap:normal}.content sub,.content sup{font-size:75%}.content table{width:100%}.content table td,.content table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:.5em .75em;vertical-align:top}.content table th{color:#363636;text-align:left}.content table thead td,.content table thead th{border-width:0 0 2px;color:#363636}.content table tfoot td,.content table tfoot th{border-width:2px 0 0;color:#363636}.content table tbody tr:last-child td,.content table tbody tr:last-child th{border-bottom-width:0}.content.is-small{font-size:.75rem}.content.is-medium{font-size:1.25rem}.content.is-large{font-size:1.5rem}.input,.textarea{background-color:#fff;border-color:#dbdbdb;color:#363636;box-shadow:inset 0 1px 2px rgba(10,10,10,.1);max-width:100%;width:100%}.input::-moz-placeholder,.textarea::-moz-placeholder{color:rgba(54,54,54,.3)}.input::-webkit-input-placeholder,.textarea::-webkit-input-placeholder{color:rgba(54,54,54,.3)}.input:-moz-placeholder,.textarea:-moz-placeholder{color:rgba(54,54,54,.3)}.input:-ms-input-placeholder,.textarea:-ms-input-placeholder{color:rgba(54,54,54,.3)}.input.is-hovered,.input:hover,.textarea.is-hovered,.textarea:hover{border-color:#b5b5b5}.input.is-active,.input.is-focused,.input:active,.input:focus,.textarea.is-active,.textarea.is-focused,.textarea:active,.textarea:focus{border-color:#3273dc;box-shadow:0 0 0 .125em rgba(50,115,220,.25)}.input[disabled],.textarea[disabled]{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none;color:#7a7a7a}.input[disabled]::-moz-placeholder,.textarea[disabled]::-moz-placeholder{color:rgba(122,122,122,.3)}.input[disabled]::-webkit-input-placeholder,.textarea[disabled]::-webkit-input-placeholder{color:rgba(122,122,122,.3)}.input[disabled]:-moz-placeholder,.textarea[disabled]:-moz-placeholder{color:rgba(122,122,122,.3)}.input[disabled]:-ms-input-placeholder,.textarea[disabled]:-ms-input-placeholder{color:rgba(122,122,122,.3)}.input[readonly],.textarea[readonly]{box-shadow:none}.input.is-white,.textarea.is-white{border-color:#fff}.input.is-white.is-active,.input.is-white.is-focused,.input.is-white:active,.input.is-white:focus,.textarea.is-white.is-active,.textarea.is-white.is-focused,.textarea.is-white:active,.textarea.is-white:focus{box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.input.is-black,.textarea.is-black{border-color:#0a0a0a}.input.is-black.is-active,.input.is-black.is-focused,.input.is-black:active,.input.is-black:focus,.textarea.is-black.is-active,.textarea.is-black.is-focused,.textarea.is-black:active,.textarea.is-black:focus{box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.input.is-light,.textarea.is-light{border-color:#f5f5f5}.input.is-light.is-active,.input.is-light.is-focused,.input.is-light:active,.input.is-light:focus,.textarea.is-light.is-active,.textarea.is-light.is-focused,.textarea.is-light:active,.textarea.is-light:focus{box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.input.is-dark,.textarea.is-dark{border-color:#363636}.input.is-dark.is-active,.input.is-dark.is-focused,.input.is-dark:active,.input.is-dark:focus,.textarea.is-dark.is-active,.textarea.is-dark.is-focused,.textarea.is-dark:active,.textarea.is-dark:focus{box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.input.is-primary,.textarea.is-primary{border-color:#00d1b2}.input.is-primary.is-active,.input.is-primary.is-focused,.input.is-primary:active,.input.is-primary:focus,.textarea.is-primary.is-active,.textarea.is-primary.is-focused,.textarea.is-primary:active,.textarea.is-primary:focus{box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.input.is-link,.textarea.is-link{border-color:#3273dc}.input.is-link.is-active,.input.is-link.is-focused,.input.is-link:active,.input.is-link:focus,.textarea.is-link.is-active,.textarea.is-link.is-focused,.textarea.is-link:active,.textarea.is-link:focus{box-shadow:0 0 0 .125em rgba(50,115,220,.25)}.input.is-info,.textarea.is-info{border-color:#209cee}.input.is-info.is-active,.input.is-info.is-focused,.input.is-info:active,.input.is-info:focus,.textarea.is-info.is-active,.textarea.is-info.is-focused,.textarea.is-info:active,.textarea.is-info:focus{box-shadow:0 0 0 .125em rgba(32,156,238,.25)}.input.is-success,.textarea.is-success{border-color:#23d160}.input.is-success.is-active,.input.is-success.is-focused,.input.is-success:active,.input.is-success:focus,.textarea.is-success.is-active,.textarea.is-success.is-focused,.textarea.is-success:active,.textarea.is-success:focus{box-shadow:0 0 0 .125em rgba(35,209,96,.25)}.input.is-warning,.textarea.is-warning{border-color:#ffdd57}.input.is-warning.is-active,.input.is-warning.is-focused,.input.is-warning:active,.input.is-warning:focus,.textarea.is-warning.is-active,.textarea.is-warning.is-focused,.textarea.is-warning:active,.textarea.is-warning:focus{box-shadow:0 0 0 .125em rgba(255,221,87,.25)}.input.is-danger,.textarea.is-danger{border-color:#ff3860}.input.is-danger.is-active,.input.is-danger.is-focused,.input.is-danger:active,.input.is-danger:focus,.textarea.is-danger.is-active,.textarea.is-danger.is-focused,.textarea.is-danger:active,.textarea.is-danger:focus{box-shadow:0 0 0 .125em rgba(255,56,96,.25)}.input.is-small,.textarea.is-small{border-radius:2px;font-size:.75rem}.input.is-medium,.textarea.is-medium{font-size:1.25rem}.input.is-large,.textarea.is-large{font-size:1.5rem}.input.is-fullwidth,.textarea.is-fullwidth{display:block;width:100%}.input.is-inline,.textarea.is-inline{display:inline;width:auto}.input.is-rounded{border-radius:290486px;padding-left:1em;padding-right:1em}.input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.textarea{display:block;max-width:100%;min-width:100%;padding:.625em;resize:vertical}.textarea:not([rows]){max-height:600px;min-height:120px}.textarea[rows]{height:initial}.textarea.has-fixed-size{resize:none}.checkbox,.radio{cursor:pointer;display:inline-block;line-height:1.25;position:relative}.checkbox input,.radio input{cursor:pointer}.checkbox:hover,.radio:hover{color:#363636}.checkbox[disabled],.radio[disabled]{color:#7a7a7a;cursor:not-allowed}.radio+.radio{margin-left:.5em}.select{display:inline-block;max-width:100%;position:relative;vertical-align:top}.select:not(.is-multiple){height:2.25em}.select:not(.is-multiple):not(.is-loading)::after{border-color:#3273dc;right:1.125em;z-index:4}.select.is-rounded select{border-radius:290486px;padding-left:1em}.select select{background-color:#fff;border-color:#dbdbdb;color:#363636;cursor:pointer;display:block;font-size:1em;max-width:100%;outline:0}.select select::-moz-placeholder{color:rgba(54,54,54,.3)}.select select::-webkit-input-placeholder{color:rgba(54,54,54,.3)}.select select:-moz-placeholder{color:rgba(54,54,54,.3)}.select select:-ms-input-placeholder{color:rgba(54,54,54,.3)}.select select.is-hovered,.select select:hover{border-color:#b5b5b5}.select select.is-active,.select select.is-focused,.select select:active,.select select:focus{border-color:#3273dc;box-shadow:0 0 0 .125em rgba(50,115,220,.25)}.select select[disabled]{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none;color:#7a7a7a}.select select[disabled]::-moz-placeholder{color:rgba(122,122,122,.3)}.select select[disabled]::-webkit-input-placeholder{color:rgba(122,122,122,.3)}.select select[disabled]:-moz-placeholder{color:rgba(122,122,122,.3)}.select select[disabled]:-ms-input-placeholder{color:rgba(122,122,122,.3)}.select select::-ms-expand{display:none}.select select[disabled]:hover{border-color:#f5f5f5}.select select:not([multiple]){padding-right:2.5em}.select select[multiple]{height:initial;padding:0}.select select[multiple] option{padding:.5em 1em}.select:not(.is-multiple):not(.is-loading):hover::after{border-color:#363636}.select.is-white:not(:hover)::after{border-color:#fff}.select.is-white select{border-color:#fff}.select.is-white select.is-hovered,.select.is-white select:hover{border-color:#f2f2f2}.select.is-white select.is-active,.select.is-white select.is-focused,.select.is-white select:active,.select.is-white select:focus{box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.select.is-black:not(:hover)::after{border-color:#0a0a0a}.select.is-black select{border-color:#0a0a0a}.select.is-black select.is-hovered,.select.is-black select:hover{border-color:#000}.select.is-black select.is-active,.select.is-black select.is-focused,.select.is-black select:active,.select.is-black select:focus{box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.select.is-light:not(:hover)::after{border-color:#f5f5f5}.select.is-light select{border-color:#f5f5f5}.select.is-light select.is-hovered,.select.is-light select:hover{border-color:#e8e8e8}.select.is-light select.is-active,.select.is-light select.is-focused,.select.is-light select:active,.select.is-light select:focus{box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.select.is-dark:not(:hover)::after{border-color:#363636}.select.is-dark select{border-color:#363636}.select.is-dark select.is-hovered,.select.is-dark select:hover{border-color:#292929}.select.is-dark select.is-active,.select.is-dark select.is-focused,.select.is-dark select:active,.select.is-dark select:focus{box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.select.is-primary:not(:hover)::after{border-color:#00d1b2}.select.is-primary select{border-color:#00d1b2}.select.is-primary select.is-hovered,.select.is-primary select:hover{border-color:#00b89c}.select.is-primary select.is-active,.select.is-primary select.is-focused,.select.is-primary select:active,.select.is-primary select:focus{box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.select.is-link:not(:hover)::after{border-color:#3273dc}.select.is-link select{border-color:#3273dc}.select.is-link select.is-hovered,.select.is-link select:hover{border-color:#2366d1}.select.is-link select.is-active,.select.is-link select.is-focused,.select.is-link select:active,.select.is-link select:focus{box-shadow:0 0 0 .125em rgba(50,115,220,.25)}.select.is-info:not(:hover)::after{border-color:#209cee}.select.is-info select{border-color:#209cee}.select.is-info select.is-hovered,.select.is-info select:hover{border-color:#118fe4}.select.is-info select.is-active,.select.is-info select.is-focused,.select.is-info select:active,.select.is-info select:focus{box-shadow:0 0 0 .125em rgba(32,156,238,.25)}.select.is-success:not(:hover)::after{border-color:#23d160}.select.is-success select{border-color:#23d160}.select.is-success select.is-hovered,.select.is-success select:hover{border-color:#20bc56}.select.is-success select.is-active,.select.is-success select.is-focused,.select.is-success select:active,.select.is-success select:focus{box-shadow:0 0 0 .125em rgba(35,209,96,.25)}.select.is-warning:not(:hover)::after{border-color:#ffdd57}.select.is-warning select{border-color:#ffdd57}.select.is-warning select.is-hovered,.select.is-warning select:hover{border-color:#ffd83d}.select.is-warning select.is-active,.select.is-warning select.is-focused,.select.is-warning select:active,.select.is-warning select:focus{box-shadow:0 0 0 .125em rgba(255,221,87,.25)}.select.is-danger:not(:hover)::after{border-color:#ff3860}.select.is-danger select{border-color:#ff3860}.select.is-danger select.is-hovered,.select.is-danger select:hover{border-color:#ff1f4b}.select.is-danger select.is-active,.select.is-danger select.is-focused,.select.is-danger select:active,.select.is-danger select:focus{box-shadow:0 0 0 .125em rgba(255,56,96,.25)}.select.is-small{border-radius:2px;font-size:.75rem}.select.is-medium{font-size:1.25rem}.select.is-large{font-size:1.5rem}.select.is-disabled::after{border-color:#7a7a7a}.select.is-fullwidth{width:100%}.select.is-fullwidth select{width:100%}.select.is-loading::after{margin-top:0;position:absolute;right:.625em;top:.625em;-webkit-transform:none;transform:none}.select.is-loading.is-small:after{font-size:.75rem}.select.is-loading.is-medium:after{font-size:1.25rem}.select.is-loading.is-large:after{font-size:1.5rem}.file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}.file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}.file.is-white.is-hovered .file-cta,.file.is-white:hover .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.file.is-white.is-focused .file-cta,.file.is-white:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(255,255,255,.25);color:#0a0a0a}.file.is-white.is-active .file-cta,.file.is-white:active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}.file.is-black.is-hovered .file-cta,.file.is-black:hover .file-cta{background-color:#040404;border-color:transparent;color:#fff}.file.is-black.is-focused .file-cta,.file.is-black:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(10,10,10,.25);color:#fff}.file.is-black.is-active .file-cta,.file.is-black:active .file-cta{background-color:#000;border-color:transparent;color:#fff}.file.is-light .file-cta{background-color:#f5f5f5;border-color:transparent;color:#363636}.file.is-light.is-hovered .file-cta,.file.is-light:hover .file-cta{background-color:#eee;border-color:transparent;color:#363636}.file.is-light.is-focused .file-cta,.file.is-light:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(245,245,245,.25);color:#363636}.file.is-light.is-active .file-cta,.file.is-light:active .file-cta{background-color:#e8e8e8;border-color:transparent;color:#363636}.file.is-dark .file-cta{background-color:#363636;border-color:transparent;color:#f5f5f5}.file.is-dark.is-hovered .file-cta,.file.is-dark:hover .file-cta{background-color:#2f2f2f;border-color:transparent;color:#f5f5f5}.file.is-dark.is-focused .file-cta,.file.is-dark:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(54,54,54,.25);color:#f5f5f5}.file.is-dark.is-active .file-cta,.file.is-dark:active .file-cta{background-color:#292929;border-color:transparent;color:#f5f5f5}.file.is-primary .file-cta{background-color:#00d1b2;border-color:transparent;color:#fff}.file.is-primary.is-hovered .file-cta,.file.is-primary:hover .file-cta{background-color:#00c4a7;border-color:transparent;color:#fff}.file.is-primary.is-focused .file-cta,.file.is-primary:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(0,209,178,.25);color:#fff}.file.is-primary.is-active .file-cta,.file.is-primary:active .file-cta{background-color:#00b89c;border-color:transparent;color:#fff}.file.is-link .file-cta{background-color:#3273dc;border-color:transparent;color:#fff}.file.is-link.is-hovered .file-cta,.file.is-link:hover .file-cta{background-color:#276cda;border-color:transparent;color:#fff}.file.is-link.is-focused .file-cta,.file.is-link:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(50,115,220,.25);color:#fff}.file.is-link.is-active .file-cta,.file.is-link:active .file-cta{background-color:#2366d1;border-color:transparent;color:#fff}.file.is-info .file-cta{background-color:#209cee;border-color:transparent;color:#fff}.file.is-info.is-hovered .file-cta,.file.is-info:hover .file-cta{background-color:#1496ed;border-color:transparent;color:#fff}.file.is-info.is-focused .file-cta,.file.is-info:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(32,156,238,.25);color:#fff}.file.is-info.is-active .file-cta,.file.is-info:active .file-cta{background-color:#118fe4;border-color:transparent;color:#fff}.file.is-success .file-cta{background-color:#23d160;border-color:transparent;color:#fff}.file.is-success.is-hovered .file-cta,.file.is-success:hover .file-cta{background-color:#22c65b;border-color:transparent;color:#fff}.file.is-success.is-focused .file-cta,.file.is-success:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(35,209,96,.25);color:#fff}.file.is-success.is-active .file-cta,.file.is-success:active .file-cta{background-color:#20bc56;border-color:transparent;color:#fff}.file.is-warning .file-cta{background-color:#ffdd57;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-warning.is-hovered .file-cta,.file.is-warning:hover .file-cta{background-color:#ffdb4a;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-warning.is-focused .file-cta,.file.is-warning:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(255,221,87,.25);color:rgba(0,0,0,.7)}.file.is-warning.is-active .file-cta,.file.is-warning:active .file-cta{background-color:#ffd83d;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-danger .file-cta{background-color:#ff3860;border-color:transparent;color:#fff}.file.is-danger.is-hovered .file-cta,.file.is-danger:hover .file-cta{background-color:#ff2b56;border-color:transparent;color:#fff}.file.is-danger.is-focused .file-cta,.file.is-danger:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(255,56,96,.25);color:#fff}.file.is-danger.is-active .file-cta,.file.is-danger:active .file-cta{background-color:#ff1f4b;border-color:transparent;color:#fff}.file.is-small{font-size:.75rem}.file.is-medium{font-size:1.25rem}.file.is-medium .file-icon .fa{font-size:21px}.file.is-large{font-size:1.5rem}.file.is-large .file-icon .fa{font-size:28px}.file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}.file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}.file.has-name.is-empty .file-cta{border-radius:4px}.file.has-name.is-empty .file-name{display:none}.file.is-boxed .file-label{flex-direction:column}.file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}.file.is-boxed .file-name{border-width:0 1px 1px}.file.is-boxed .file-icon{height:1.5em;width:1.5em}.file.is-boxed .file-icon .fa{font-size:21px}.file.is-boxed.is-small .file-icon .fa{font-size:14px}.file.is-boxed.is-medium .file-icon .fa{font-size:28px}.file.is-boxed.is-large .file-icon .fa{font-size:35px}.file.is-boxed.has-name .file-cta{border-radius:4px 4px 0 0}.file.is-boxed.has-name .file-name{border-radius:0 0 4px 4px;border-width:0 1px 1px}.file.is-centered{justify-content:center}.file.is-fullwidth .file-label{width:100%}.file.is-fullwidth .file-name{flex-grow:1;max-width:none}.file.is-right{justify-content:flex-end}.file.is-right .file-cta{border-radius:0 4px 4px 0}.file.is-right .file-name{border-radius:4px 0 0 4px;border-width:1px 0 1px 1px;order:-1}.file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}.file-label:hover .file-cta{background-color:#eee;color:#363636}.file-label:hover .file-name{border-color:#d5d5d5}.file-label:active .file-cta{background-color:#e8e8e8;color:#363636}.file-label:active .file-name{border-color:#cfcfcf}.file-input{height:.01em;left:0;outline:0;position:absolute;top:0;width:.01em}.file-cta,.file-name{border-color:#dbdbdb;border-radius:4px;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}.file-cta{background-color:#f5f5f5;color:#4a4a4a}.file-name{border-color:#dbdbdb;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:left;text-overflow:ellipsis}.file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}.file-icon .fa{font-size:14px}.label{color:#363636;display:block;font-size:1rem;font-weight:700}.label:not(:last-child){margin-bottom:.5em}.label.is-small{font-size:.75rem}.label.is-medium{font-size:1.25rem}.label.is-large{font-size:1.5rem}.help{display:block;font-size:.75rem;margin-top:.25rem}.help.is-white{color:#fff}.help.is-black{color:#0a0a0a}.help.is-light{color:#f5f5f5}.help.is-dark{color:#363636}.help.is-primary{color:#00d1b2}.help.is-link{color:#3273dc}.help.is-info{color:#209cee}.help.is-success{color:#23d160}.help.is-warning{color:#ffdd57}.help.is-danger{color:#ff3860}.field:not(:last-child){margin-bottom:.75rem}.field.has-addons{display:flex;justify-content:flex-start}.field.has-addons .control:not(:last-child){margin-right:-1px}.field.has-addons .control:not(:first-child):not(:last-child) .button,.field.has-addons .control:not(:first-child):not(:last-child) .input,.field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}.field.has-addons .control:first-child .button,.field.has-addons .control:first-child .input,.field.has-addons .control:first-child .select select{border-bottom-right-radius:0;border-top-right-radius:0}.field.has-addons .control:last-child .button,.field.has-addons .control:last-child .input,.field.has-addons .control:last-child .select select{border-bottom-left-radius:0;border-top-left-radius:0}.field.has-addons .control .button.is-hovered,.field.has-addons .control .button:hover,.field.has-addons .control .input.is-hovered,.field.has-addons .control .input:hover,.field.has-addons .control .select select.is-hovered,.field.has-addons .control .select select:hover{z-index:2}.field.has-addons .control .button.is-active,.field.has-addons .control .button.is-focused,.field.has-addons .control .button:active,.field.has-addons .control .button:focus,.field.has-addons .control .input.is-active,.field.has-addons .control .input.is-focused,.field.has-addons .control .input:active,.field.has-addons .control .input:focus,.field.has-addons .control .select select.is-active,.field.has-addons .control .select select.is-focused,.field.has-addons .control .select select:active,.field.has-addons .control .select select:focus{z-index:3}.field.has-addons .control .button.is-active:hover,.field.has-addons .control .button.is-focused:hover,.field.has-addons .control .button:active:hover,.field.has-addons .control .button:focus:hover,.field.has-addons .control .input.is-active:hover,.field.has-addons .control .input.is-focused:hover,.field.has-addons .control .input:active:hover,.field.has-addons .control .input:focus:hover,.field.has-addons .control .select select.is-active:hover,.field.has-addons .control .select select.is-focused:hover,.field.has-addons .control .select select:active:hover,.field.has-addons .control .select select:focus:hover{z-index:4}.field.has-addons .control.is-expanded{flex-grow:1}.field.has-addons.has-addons-centered{justify-content:center}.field.has-addons.has-addons-right{justify-content:flex-end}.field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}.field.is-grouped{display:flex;justify-content:flex-start}.field.is-grouped>.control{flex-shrink:0}.field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:.75rem}.field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}.field.is-grouped.is-grouped-centered{justify-content:center}.field.is-grouped.is-grouped-right{justify-content:flex-end}.field.is-grouped.is-grouped-multiline{flex-wrap:wrap}.field.is-grouped.is-grouped-multiline>.control:last-child,.field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:.75rem}.field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-.75rem}.field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width:769px),print{.field.is-horizontal{display:flex}}.field-label .label{font-size:inherit}@media screen and (max-width:768px){.field-label{margin-bottom:.5rem}}@media screen and (min-width:769px),print{.field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}.field-label.is-small{font-size:.75rem;padding-top:.375em}.field-label.is-normal{padding-top:.375em}.field-label.is-medium{font-size:1.25rem;padding-top:.375em}.field-label.is-large{font-size:1.5rem;padding-top:.375em}}.field-body .field .field{margin-bottom:0}@media screen and (min-width:769px),print{.field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}.field-body .field{margin-bottom:0}.field-body>.field{flex-shrink:1}.field-body>.field:not(.is-narrow){flex-grow:1}.field-body>.field:not(:last-child){margin-right:.75rem}}.control{font-size:1rem;position:relative;text-align:left}.control.has-icon .icon{color:#dbdbdb;height:2.25em;pointer-events:none;position:absolute;top:0;width:2.25em;z-index:4}.control.has-icon .input:focus+.icon{color:#7a7a7a}.control.has-icon .input.is-small+.icon{font-size:.75rem}.control.has-icon .input.is-medium+.icon{font-size:1.25rem}.control.has-icon .input.is-large+.icon{font-size:1.5rem}.control.has-icon:not(.has-icon-right) .icon{left:0}.control.has-icon:not(.has-icon-right) .input{padding-left:2.25em}.control.has-icon.has-icon-right .icon{right:0}.control.has-icon.has-icon-right .input{padding-right:2.25em}.control.has-icons-left .input:focus~.icon,.control.has-icons-left .select:focus~.icon,.control.has-icons-right .input:focus~.icon,.control.has-icons-right .select:focus~.icon{color:#7a7a7a}.control.has-icons-left .input.is-small~.icon,.control.has-icons-left .select.is-small~.icon,.control.has-icons-right .input.is-small~.icon,.control.has-icons-right .select.is-small~.icon{font-size:.75rem}.control.has-icons-left .input.is-medium~.icon,.control.has-icons-left .select.is-medium~.icon,.control.has-icons-right .input.is-medium~.icon,.control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}.control.has-icons-left .input.is-large~.icon,.control.has-icons-left .select.is-large~.icon,.control.has-icons-right .input.is-large~.icon,.control.has-icons-right .select.is-large~.icon{font-size:1.5rem}.control.has-icons-left .icon,.control.has-icons-right .icon{color:#dbdbdb;height:2.25em;pointer-events:none;position:absolute;top:0;width:2.25em;z-index:4}.control.has-icons-left .input,.control.has-icons-left .select select{padding-left:2.25em}.control.has-icons-left .icon.is-left{left:0}.control.has-icons-right .input,.control.has-icons-right .select select{padding-right:2.25em}.control.has-icons-right .icon.is-right{right:0}.control.is-loading::after{position:absolute!important;right:.625em;top:.625em;z-index:4}.control.is-loading.is-small:after{font-size:.75rem}.control.is-loading.is-medium:after{font-size:1.25rem}.control.is-loading.is-large:after{font-size:1.5rem}.icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}.icon.is-small{height:1rem;width:1rem}.icon.is-medium{height:2rem;width:2rem}.icon.is-large{height:3rem;width:3rem}.image{display:block;position:relative}.image img{display:block;height:auto;width:100%}.image img.is-rounded{border-radius:290486px}.image.is-16by9 img,.image.is-1by1 img,.image.is-1by2 img,.image.is-1by3 img,.image.is-2by1 img,.image.is-2by3 img,.image.is-3by1 img,.image.is-3by2 img,.image.is-3by4 img,.image.is-3by5 img,.image.is-4by3 img,.image.is-4by5 img,.image.is-5by3 img,.image.is-5by4 img,.image.is-9by16 img,.image.is-square img{height:100%;width:100%}.image.is-1by1,.image.is-square{padding-top:100%}.image.is-5by4{padding-top:80%}.image.is-4by3{padding-top:75%}.image.is-3by2{padding-top:66.6666%}.image.is-5by3{padding-top:60%}.image.is-16by9{padding-top:56.25%}.image.is-2by1{padding-top:50%}.image.is-3by1{padding-top:33.3333%}.image.is-4by5{padding-top:125%}.image.is-3by4{padding-top:133.3333%}.image.is-2by3{padding-top:150%}.image.is-3by5{padding-top:166.6666%}.image.is-9by16{padding-top:177.7777%}.image.is-1by2{padding-top:200%}.image.is-1by3{padding-top:300%}.image.is-16x16{height:16px;width:16px}.image.is-24x24{height:24px;width:24px}.image.is-32x32{height:32px;width:32px}.image.is-48x48{height:48px;width:48px}.image.is-64x64{height:64px;width:64px}.image.is-96x96{height:96px;width:96px}.image.is-128x128{height:128px;width:128px}.notification{background-color:#f5f5f5;border-radius:4px;padding:1.25rem 2.5rem 1.25rem 1.5rem;position:relative}.notification a:not(.button){color:currentColor;text-decoration:underline}.notification strong{color:currentColor}.notification code,.notification pre{background:#fff}.notification pre code{background:0 0}.notification>.delete{position:absolute;right:.5rem;top:.5rem}.notification .content,.notification .subtitle,.notification .title{color:currentColor}.notification.is-white{background-color:#fff;color:#0a0a0a}.notification.is-black{background-color:#0a0a0a;color:#fff}.notification.is-light{background-color:#f5f5f5;color:#363636}.notification.is-dark{background-color:#363636;color:#f5f5f5}.notification.is-primary{background-color:#00d1b2;color:#fff}.notification.is-link{background-color:#3273dc;color:#fff}.notification.is-info{background-color:#209cee;color:#fff}.notification.is-success{background-color:#23d160;color:#fff}.notification.is-warning{background-color:#ffdd57;color:rgba(0,0,0,.7)}.notification.is-danger{background-color:#ff3860;color:#fff}.progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:290486px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}.progress::-webkit-progress-bar{background-color:#dbdbdb}.progress::-webkit-progress-value{background-color:#4a4a4a}.progress::-moz-progress-bar{background-color:#4a4a4a}.progress::-ms-fill{background-color:#4a4a4a;border:none}.progress.is-white::-webkit-progress-value{background-color:#fff}.progress.is-white::-moz-progress-bar{background-color:#fff}.progress.is-white::-ms-fill{background-color:#fff}.progress.is-black::-webkit-progress-value{background-color:#0a0a0a}.progress.is-black::-moz-progress-bar{background-color:#0a0a0a}.progress.is-black::-ms-fill{background-color:#0a0a0a}.progress.is-light::-webkit-progress-value{background-color:#f5f5f5}.progress.is-light::-moz-progress-bar{background-color:#f5f5f5}.progress.is-light::-ms-fill{background-color:#f5f5f5}.progress.is-dark::-webkit-progress-value{background-color:#363636}.progress.is-dark::-moz-progress-bar{background-color:#363636}.progress.is-dark::-ms-fill{background-color:#363636}.progress.is-primary::-webkit-progress-value{background-color:#00d1b2}.progress.is-primary::-moz-progress-bar{background-color:#00d1b2}.progress.is-primary::-ms-fill{background-color:#00d1b2}.progress.is-link::-webkit-progress-value{background-color:#3273dc}.progress.is-link::-moz-progress-bar{background-color:#3273dc}.progress.is-link::-ms-fill{background-color:#3273dc}.progress.is-info::-webkit-progress-value{background-color:#209cee}.progress.is-info::-moz-progress-bar{background-color:#209cee}.progress.is-info::-ms-fill{background-color:#209cee}.progress.is-success::-webkit-progress-value{background-color:#23d160}.progress.is-success::-moz-progress-bar{background-color:#23d160}.progress.is-success::-ms-fill{background-color:#23d160}.progress.is-warning::-webkit-progress-value{background-color:#ffdd57}.progress.is-warning::-moz-progress-bar{background-color:#ffdd57}.progress.is-warning::-ms-fill{background-color:#ffdd57}.progress.is-danger::-webkit-progress-value{background-color:#ff3860}.progress.is-danger::-moz-progress-bar{background-color:#ff3860}.progress.is-danger::-ms-fill{background-color:#ff3860}.progress.is-small{height:.75rem}.progress.is-medium{height:1.25rem}.progress.is-large{height:1.5rem}.table{background-color:#fff;color:#363636}.table td,.table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:.5em .75em;vertical-align:top}.table td.is-white,.table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}.table td.is-black,.table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.table td.is-light,.table th.is-light{background-color:#f5f5f5;border-color:#f5f5f5;color:#363636}.table td.is-dark,.table th.is-dark{background-color:#363636;border-color:#363636;color:#f5f5f5}.table td.is-primary,.table th.is-primary{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.table td.is-link,.table th.is-link{background-color:#3273dc;border-color:#3273dc;color:#fff}.table td.is-info,.table th.is-info{background-color:#209cee;border-color:#209cee;color:#fff}.table td.is-success,.table th.is-success{background-color:#23d160;border-color:#23d160;color:#fff}.table td.is-warning,.table th.is-warning{background-color:#ffdd57;border-color:#ffdd57;color:rgba(0,0,0,.7)}.table td.is-danger,.table th.is-danger{background-color:#ff3860;border-color:#ff3860;color:#fff}.table td.is-narrow,.table th.is-narrow{white-space:nowrap;width:1%}.table td.is-selected,.table th.is-selected{background-color:#00d1b2;color:#fff}.table td.is-selected a,.table td.is-selected strong,.table th.is-selected a,.table th.is-selected strong{color:currentColor}.table th{color:#363636;text-align:left}.table tr.is-selected{background-color:#00d1b2;color:#fff}.table tr.is-selected a,.table tr.is-selected strong{color:currentColor}.table tr.is-selected td,.table tr.is-selected th{border-color:#fff;color:currentColor}.table thead td,.table thead th{border-width:0 0 2px;color:#363636}.table tfoot td,.table tfoot th{border-width:2px 0 0;color:#363636}.table tbody tr:last-child td,.table tbody tr:last-child th{border-bottom-width:0}.table.is-bordered td,.table.is-bordered th{border-width:1px}.table.is-bordered tr:last-child td,.table.is-bordered tr:last-child th{border-bottom-width:1px}.table.is-fullwidth{width:100%}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#f5f5f5}.table.is-narrow td,.table.is-narrow th{padding:.25em .5em}.table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#fafafa}.table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}.tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.tags .tag{margin-bottom:.5rem}.tags .tag:not(:last-child){margin-right:.5rem}.tags:last-child{margin-bottom:-.5rem}.tags:not(:last-child){margin-bottom:1rem}.tags.has-addons .tag{margin-right:0}.tags.has-addons .tag:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.tags.has-addons .tag:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.tags.is-centered{justify-content:center}.tags.is-centered .tag{margin-right:.25rem;margin-left:.25rem}.tags.is-right{justify-content:flex-end}.tags.is-right .tag:not(:first-child){margin-left:.5rem}.tags.is-right .tag:not(:last-child){margin-right:0}.tag:not(body){align-items:center;background-color:#f5f5f5;border-radius:4px;color:#4a4a4a;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:.75em;padding-right:.75em;white-space:nowrap}.tag:not(body) .delete{margin-left:.25rem;margin-right:-.375rem}.tag:not(body).is-white{background-color:#fff;color:#0a0a0a}.tag:not(body).is-black{background-color:#0a0a0a;color:#fff}.tag:not(body).is-light{background-color:#f5f5f5;color:#363636}.tag:not(body).is-dark{background-color:#363636;color:#f5f5f5}.tag:not(body).is-primary{background-color:#00d1b2;color:#fff}.tag:not(body).is-link{background-color:#3273dc;color:#fff}.tag:not(body).is-info{background-color:#209cee;color:#fff}.tag:not(body).is-success{background-color:#23d160;color:#fff}.tag:not(body).is-warning{background-color:#ffdd57;color:rgba(0,0,0,.7)}.tag:not(body).is-danger{background-color:#ff3860;color:#fff}.tag:not(body).is-medium{font-size:1rem}.tag:not(body).is-large{font-size:1.25rem}.tag:not(body) .icon:first-child:not(:last-child){margin-left:-.375em;margin-right:.1875em}.tag:not(body) .icon:last-child:not(:first-child){margin-left:.1875em;margin-right:-.375em}.tag:not(body) .icon:first-child:last-child{margin-left:-.375em;margin-right:-.375em}.tag:not(body).is-delete{margin-left:1px;padding:0;position:relative;width:2em}.tag:not(body).is-delete::after,.tag:not(body).is-delete::before{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;-webkit-transform:translateX(-50%) translateY(-50%) rotate(45deg);transform:translateX(-50%) translateY(-50%) rotate(45deg);-webkit-transform-origin:center center;transform-origin:center center}.tag:not(body).is-delete::before{height:1px;width:50%}.tag:not(body).is-delete::after{height:50%;width:1px}.tag:not(body).is-delete:focus,.tag:not(body).is-delete:hover{background-color:#e8e8e8}.tag:not(body).is-delete:active{background-color:#dbdbdb}.tag:not(body).is-rounded{border-radius:290486px}a.tag:hover{text-decoration:underline}.subtitle,.title{word-break:break-word}.subtitle em,.subtitle span,.title em,.title span{font-weight:inherit}.subtitle sub,.title sub{font-size:.75em}.subtitle sup,.title sup{font-size:.75em}.subtitle .tag,.title .tag{vertical-align:middle}.title{color:#363636;font-size:2rem;font-weight:600;line-height:1.125}.title strong{color:inherit;font-weight:inherit}.title+.highlight{margin-top:-.75rem}.title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}.title.is-1{font-size:3rem}.title.is-2{font-size:2.5rem}.title.is-3{font-size:2rem}.title.is-4{font-size:1.5rem}.title.is-5{font-size:1.25rem}.title.is-6{font-size:1rem}.title.is-7{font-size:.75rem}.subtitle{color:#4a4a4a;font-size:1.25rem;font-weight:400;line-height:1.25}.subtitle strong{color:#363636;font-weight:600}.subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}.subtitle.is-1{font-size:3rem}.subtitle.is-2{font-size:2.5rem}.subtitle.is-3{font-size:2rem}.subtitle.is-4{font-size:1.5rem}.subtitle.is-5{font-size:1.25rem}.subtitle.is-6{font-size:1rem}.subtitle.is-7{font-size:.75rem}.heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}.highlight{font-weight:400;max-width:100%;overflow:hidden;padding:0}.highlight pre{overflow:auto;max-width:100%}.number{align-items:center;background-color:#f5f5f5;border-radius:290486px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:.25rem .5rem;text-align:center;vertical-align:top}.breadcrumb{font-size:1rem;white-space:nowrap}.breadcrumb a{align-items:center;color:#3273dc;display:flex;justify-content:center;padding:0 .75em}.breadcrumb a:hover{color:#363636}.breadcrumb li{align-items:center;display:flex}.breadcrumb li:first-child a{padding-left:0}.breadcrumb li.is-active a{color:#363636;cursor:default;pointer-events:none}.breadcrumb li+li::before{color:#b5b5b5;content:"\0002f"}.breadcrumb ol,.breadcrumb ul{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}.breadcrumb .icon:first-child{margin-right:.5em}.breadcrumb .icon:last-child{margin-left:.5em}.breadcrumb.is-centered ol,.breadcrumb.is-centered ul{justify-content:center}.breadcrumb.is-right ol,.breadcrumb.is-right ul{justify-content:flex-end}.breadcrumb.is-small{font-size:.75rem}.breadcrumb.is-medium{font-size:1.25rem}.breadcrumb.is-large{font-size:1.5rem}.breadcrumb.has-arrow-separator li+li::before{content:"\02192"}.breadcrumb.has-bullet-separator li+li::before{content:"\02022"}.breadcrumb.has-dot-separator li+li::before{content:"\000b7"}.breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}.card{background-color:#fff;box-shadow:0 2px 3px rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.1);color:#4a4a4a;max-width:100%;position:relative}.card-header{background-color:none;align-items:stretch;box-shadow:0 1px 2px rgba(10,10,10,.1);display:flex}.card-header-title{align-items:center;color:#363636;display:flex;flex-grow:1;font-weight:700;padding:.75rem}.card-header-title.is-centered{justify-content:center}.card-header-icon{align-items:center;cursor:pointer;display:flex;justify-content:center;padding:.75rem}.card-image{display:block;position:relative}.card-content{background-color:none;padding:1.5rem}.card-footer{background-color:none;border-top:1px solid #dbdbdb;align-items:stretch;display:flex}.card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}.card-footer-item:not(:last-child){border-right:1px solid #dbdbdb}.card .media:not(:last-child){margin-bottom:.75rem}.dropdown{display:inline-flex;position:relative;vertical-align:top}.dropdown.is-active .dropdown-menu,.dropdown.is-hoverable:hover .dropdown-menu{display:block}.dropdown.is-right .dropdown-menu{left:auto;right:0}.dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}.dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}.dropdown-content{background-color:#fff;border-radius:4px;box-shadow:0 2px 3px rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.1);padding-bottom:.5rem;padding-top:.5rem}.dropdown-item{color:#4a4a4a;display:block;font-size:.875rem;line-height:1.5;padding:.375rem 1rem;position:relative}a.dropdown-item{padding-right:3rem;white-space:nowrap}a.dropdown-item:hover{background-color:#f5f5f5;color:#0a0a0a}a.dropdown-item.is-active{background-color:#3273dc;color:#fff}.dropdown-divider{background-color:#dbdbdb;border:none;display:block;height:1px;margin:.5rem 0}.level{align-items:center;justify-content:space-between}.level code{border-radius:4px}.level img{display:inline-block;vertical-align:top}.level.is-mobile{display:flex}.level.is-mobile .level-left,.level.is-mobile .level-right{display:flex}.level.is-mobile .level-left+.level-right{margin-top:0}.level.is-mobile .level-item{margin-right:.75rem}.level.is-mobile .level-item:not(:last-child){margin-bottom:0}.level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width:769px),print{.level{display:flex}.level>.level-item:not(.is-narrow){flex-grow:1}}.level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}.level-item .subtitle,.level-item .title{margin-bottom:0}@media screen and (max-width:768px){.level-item:not(:last-child){margin-bottom:.75rem}}.level-left,.level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.level-left .level-item.is-flexible,.level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width:769px),print{.level-left .level-item:not(:last-child),.level-right .level-item:not(:last-child){margin-right:.75rem}}.level-left{align-items:center;justify-content:flex-start}@media screen and (max-width:768px){.level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width:769px),print{.level-left{display:flex}}.level-right{align-items:center;justify-content:flex-end}@media screen and (min-width:769px),print{.level-right{display:flex}}.media{align-items:flex-start;display:flex;text-align:left}.media .content:not(:last-child){margin-bottom:.75rem}.media .media{border-top:1px solid rgba(219,219,219,.5);display:flex;padding-top:.75rem}.media .media .content:not(:last-child),.media .media .control:not(:last-child){margin-bottom:.5rem}.media .media .media{padding-top:.5rem}.media .media .media+.media{margin-top:.5rem}.media+.media{border-top:1px solid rgba(219,219,219,.5);margin-top:1rem;padding-top:1rem}.media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}.media-left,.media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.media-left{margin-right:1rem}.media-right{margin-left:1rem}.media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:left}.menu{font-size:1rem}.menu.is-small{font-size:.75rem}.menu.is-medium{font-size:1.25rem}.menu.is-large{font-size:1.5rem}.menu-list{line-height:1.25}.menu-list a{border-radius:2px;color:#4a4a4a;display:block;padding:.5em .75em}.menu-list a:hover{background-color:#f5f5f5;color:#363636}.menu-list a.is-active{background-color:#3273dc;color:#fff}.menu-list li ul{border-left:1px solid #dbdbdb;margin:.75em;padding-left:.75em}.menu-label{color:#7a7a7a;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}.menu-label:not(:first-child){margin-top:1em}.menu-label:not(:last-child){margin-bottom:1em}.message{background-color:#f5f5f5;border-radius:4px;font-size:1rem}.message strong{color:currentColor}.message a:not(.button):not(.tag){color:currentColor;text-decoration:underline}.message.is-small{font-size:.75rem}.message.is-medium{font-size:1.25rem}.message.is-large{font-size:1.5rem}.message.is-white{background-color:#fff}.message.is-white .message-header{background-color:#fff;color:#0a0a0a}.message.is-white .message-body{border-color:#fff;color:#4d4d4d}.message.is-black{background-color:#fafafa}.message.is-black .message-header{background-color:#0a0a0a;color:#fff}.message.is-black .message-body{border-color:#0a0a0a;color:#090909}.message.is-light{background-color:#fafafa}.message.is-light .message-header{background-color:#f5f5f5;color:#363636}.message.is-light .message-body{border-color:#f5f5f5;color:#505050}.message.is-dark{background-color:#fafafa}.message.is-dark .message-header{background-color:#363636;color:#f5f5f5}.message.is-dark .message-body{border-color:#363636;color:#2a2a2a}.message.is-primary{background-color:#f5fffd}.message.is-primary .message-header{background-color:#00d1b2;color:#fff}.message.is-primary .message-body{border-color:#00d1b2;color:#021310}.message.is-link{background-color:#f6f9fe}.message.is-link .message-header{background-color:#3273dc;color:#fff}.message.is-link .message-body{border-color:#3273dc;color:#22509a}.message.is-info{background-color:#f6fbfe}.message.is-info .message-header{background-color:#209cee;color:#fff}.message.is-info .message-body{border-color:#209cee;color:#12537e}.message.is-success{background-color:#f6fef9}.message.is-success .message-header{background-color:#23d160;color:#fff}.message.is-success .message-body{border-color:#23d160;color:#0e301a}.message.is-warning{background-color:#fffdf5}.message.is-warning .message-header{background-color:#ffdd57;color:rgba(0,0,0,.7)}.message.is-warning .message-body{border-color:#ffdd57;color:#3b3108}.message.is-danger{background-color:#fff5f7}.message.is-danger .message-header{background-color:#ff3860;color:#fff}.message.is-danger .message-body{border-color:#ff3860;color:#cd0930}.message-header{align-items:center;background-color:#4a4a4a;border-radius:4px 4px 0 0;color:#fff;display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:.75em 1em;position:relative}.message-header .delete{flex-grow:0;flex-shrink:0;margin-left:.75em}.message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}.message-body{border-color:#dbdbdb;border-radius:4px;border-style:solid;border-width:0 0 0 4px;color:#4a4a4a;padding:1.25em 1.5em}.message-body code,.message-body pre{background-color:#fff}.message-body pre code{background-color:transparent}.modal{align-items:center;display:none;justify-content:center;overflow:hidden;position:fixed;z-index:40}.modal.is-active{display:flex}.modal-background{background-color:rgba(10,10,10,.86)}.modal-card,.modal-content{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width:769px),print{.modal-card,.modal-content{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}.modal-close{background:0 0;height:40px;position:fixed;right:20px;top:20px;width:40px}.modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden}.modal-card-foot,.modal-card-head{align-items:center;background-color:#f5f5f5;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}.modal-card-head{border-bottom:1px solid #dbdbdb;border-top-left-radius:6px;border-top-right-radius:6px}.modal-card-title{color:#363636;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}.modal-card-foot{border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:1px solid #dbdbdb}.modal-card-foot .button:not(:last-child){margin-right:10px}.modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}.navbar{background-color:#fff;min-height:3.25rem;position:relative;z-index:30}.navbar.is-white{background-color:#fff;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link,.navbar.is-white .navbar-brand>.navbar-item{color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link.is-active,.navbar.is-white .navbar-brand .navbar-link:hover,.navbar.is-white .navbar-brand>a.navbar-item.is-active,.navbar.is-white .navbar-brand>a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}@media screen and (min-width:1088px){.navbar.is-white .navbar-end .navbar-link,.navbar.is-white .navbar-end>.navbar-item,.navbar.is-white .navbar-start .navbar-link,.navbar.is-white .navbar-start>.navbar-item{color:#0a0a0a}.navbar.is-white .navbar-end .navbar-link.is-active,.navbar.is-white .navbar-end .navbar-link:hover,.navbar.is-white .navbar-end>a.navbar-item.is-active,.navbar.is-white .navbar-end>a.navbar-item:hover,.navbar.is-white .navbar-start .navbar-link.is-active,.navbar.is-white .navbar-start .navbar-link:hover,.navbar.is-white .navbar-start>a.navbar-item.is-active,.navbar.is-white .navbar-start>a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-end .navbar-link::after,.navbar.is-white .navbar-start .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-white .navbar-item.has-dropdown:hover .navbar-link{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}.navbar.is-black{background-color:#0a0a0a;color:#fff}.navbar.is-black .navbar-brand .navbar-link,.navbar.is-black .navbar-brand>.navbar-item{color:#fff}.navbar.is-black .navbar-brand .navbar-link.is-active,.navbar.is-black .navbar-brand .navbar-link:hover,.navbar.is-black .navbar-brand>a.navbar-item.is-active,.navbar.is-black .navbar-brand>a.navbar-item:hover{background-color:#000;color:#fff}.navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}@media screen and (min-width:1088px){.navbar.is-black .navbar-end .navbar-link,.navbar.is-black .navbar-end>.navbar-item,.navbar.is-black .navbar-start .navbar-link,.navbar.is-black .navbar-start>.navbar-item{color:#fff}.navbar.is-black .navbar-end .navbar-link.is-active,.navbar.is-black .navbar-end .navbar-link:hover,.navbar.is-black .navbar-end>a.navbar-item.is-active,.navbar.is-black .navbar-end>a.navbar-item:hover,.navbar.is-black .navbar-start .navbar-link.is-active,.navbar.is-black .navbar-start .navbar-link:hover,.navbar.is-black .navbar-start>a.navbar-item.is-active,.navbar.is-black .navbar-start>a.navbar-item:hover{background-color:#000;color:#fff}.navbar.is-black .navbar-end .navbar-link::after,.navbar.is-black .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-black .navbar-item.has-dropdown:hover .navbar-link{background-color:#000;color:#fff}.navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}.navbar.is-light{background-color:#f5f5f5;color:#363636}.navbar.is-light .navbar-brand .navbar-link,.navbar.is-light .navbar-brand>.navbar-item{color:#363636}.navbar.is-light .navbar-brand .navbar-link.is-active,.navbar.is-light .navbar-brand .navbar-link:hover,.navbar.is-light .navbar-brand>a.navbar-item.is-active,.navbar.is-light .navbar-brand>a.navbar-item:hover{background-color:#e8e8e8;color:#363636}.navbar.is-light .navbar-brand .navbar-link::after{border-color:#363636}@media screen and (min-width:1088px){.navbar.is-light .navbar-end .navbar-link,.navbar.is-light .navbar-end>.navbar-item,.navbar.is-light .navbar-start .navbar-link,.navbar.is-light .navbar-start>.navbar-item{color:#363636}.navbar.is-light .navbar-end .navbar-link.is-active,.navbar.is-light .navbar-end .navbar-link:hover,.navbar.is-light .navbar-end>a.navbar-item.is-active,.navbar.is-light .navbar-end>a.navbar-item:hover,.navbar.is-light .navbar-start .navbar-link.is-active,.navbar.is-light .navbar-start .navbar-link:hover,.navbar.is-light .navbar-start>a.navbar-item.is-active,.navbar.is-light .navbar-start>a.navbar-item:hover{background-color:#e8e8e8;color:#363636}.navbar.is-light .navbar-end .navbar-link::after,.navbar.is-light .navbar-start .navbar-link::after{border-color:#363636}.navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-light .navbar-item.has-dropdown:hover .navbar-link{background-color:#e8e8e8;color:#363636}.navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#363636}}.navbar.is-dark{background-color:#363636;color:#f5f5f5}.navbar.is-dark .navbar-brand .navbar-link,.navbar.is-dark .navbar-brand>.navbar-item{color:#f5f5f5}.navbar.is-dark .navbar-brand .navbar-link.is-active,.navbar.is-dark .navbar-brand .navbar-link:hover,.navbar.is-dark .navbar-brand>a.navbar-item.is-active,.navbar.is-dark .navbar-brand>a.navbar-item:hover{background-color:#292929;color:#f5f5f5}.navbar.is-dark .navbar-brand .navbar-link::after{border-color:#f5f5f5}@media screen and (min-width:1088px){.navbar.is-dark .navbar-end .navbar-link,.navbar.is-dark .navbar-end>.navbar-item,.navbar.is-dark .navbar-start .navbar-link,.navbar.is-dark .navbar-start>.navbar-item{color:#f5f5f5}.navbar.is-dark .navbar-end .navbar-link.is-active,.navbar.is-dark .navbar-end .navbar-link:hover,.navbar.is-dark .navbar-end>a.navbar-item.is-active,.navbar.is-dark .navbar-end>a.navbar-item:hover,.navbar.is-dark .navbar-start .navbar-link.is-active,.navbar.is-dark .navbar-start .navbar-link:hover,.navbar.is-dark .navbar-start>a.navbar-item.is-active,.navbar.is-dark .navbar-start>a.navbar-item:hover{background-color:#292929;color:#f5f5f5}.navbar.is-dark .navbar-end .navbar-link::after,.navbar.is-dark .navbar-start .navbar-link::after{border-color:#f5f5f5}.navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link{background-color:#292929;color:#f5f5f5}.navbar.is-dark .navbar-dropdown a.navbar-item.is-active{background-color:#363636;color:#f5f5f5}}.navbar.is-primary{background-color:#00d1b2;color:#fff}.navbar.is-primary .navbar-brand .navbar-link,.navbar.is-primary .navbar-brand>.navbar-item{color:#fff}.navbar.is-primary .navbar-brand .navbar-link.is-active,.navbar.is-primary .navbar-brand .navbar-link:hover,.navbar.is-primary .navbar-brand>a.navbar-item.is-active,.navbar.is-primary .navbar-brand>a.navbar-item:hover{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-brand .navbar-link::after{border-color:#fff}@media screen and (min-width:1088px){.navbar.is-primary .navbar-end .navbar-link,.navbar.is-primary .navbar-end>.navbar-item,.navbar.is-primary .navbar-start .navbar-link,.navbar.is-primary .navbar-start>.navbar-item{color:#fff}.navbar.is-primary .navbar-end .navbar-link.is-active,.navbar.is-primary .navbar-end .navbar-link:hover,.navbar.is-primary .navbar-end>a.navbar-item.is-active,.navbar.is-primary .navbar-end>a.navbar-item:hover,.navbar.is-primary .navbar-start .navbar-link.is-active,.navbar.is-primary .navbar-start .navbar-link:hover,.navbar.is-primary .navbar-start>a.navbar-item.is-active,.navbar.is-primary .navbar-start>a.navbar-item:hover{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-end .navbar-link::after,.navbar.is-primary .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-dropdown a.navbar-item.is-active{background-color:#00d1b2;color:#fff}}.navbar.is-link{background-color:#3273dc;color:#fff}.navbar.is-link .navbar-brand .navbar-link,.navbar.is-link .navbar-brand>.navbar-item{color:#fff}.navbar.is-link .navbar-brand .navbar-link.is-active,.navbar.is-link .navbar-brand .navbar-link:hover,.navbar.is-link .navbar-brand>a.navbar-item.is-active,.navbar.is-link .navbar-brand>a.navbar-item:hover{background-color:#2366d1;color:#fff}.navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}@media screen and (min-width:1088px){.navbar.is-link .navbar-end .navbar-link,.navbar.is-link .navbar-end>.navbar-item,.navbar.is-link .navbar-start .navbar-link,.navbar.is-link .navbar-start>.navbar-item{color:#fff}.navbar.is-link .navbar-end .navbar-link.is-active,.navbar.is-link .navbar-end .navbar-link:hover,.navbar.is-link .navbar-end>a.navbar-item.is-active,.navbar.is-link .navbar-end>a.navbar-item:hover,.navbar.is-link .navbar-start .navbar-link.is-active,.navbar.is-link .navbar-start .navbar-link:hover,.navbar.is-link .navbar-start>a.navbar-item.is-active,.navbar.is-link .navbar-start>a.navbar-item:hover{background-color:#2366d1;color:#fff}.navbar.is-link .navbar-end .navbar-link::after,.navbar.is-link .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-link .navbar-item.has-dropdown:hover .navbar-link{background-color:#2366d1;color:#fff}.navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#3273dc;color:#fff}}.navbar.is-info{background-color:#209cee;color:#fff}.navbar.is-info .navbar-brand .navbar-link,.navbar.is-info .navbar-brand>.navbar-item{color:#fff}.navbar.is-info .navbar-brand .navbar-link.is-active,.navbar.is-info .navbar-brand .navbar-link:hover,.navbar.is-info .navbar-brand>a.navbar-item.is-active,.navbar.is-info .navbar-brand>a.navbar-item:hover{background-color:#118fe4;color:#fff}.navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}@media screen and (min-width:1088px){.navbar.is-info .navbar-end .navbar-link,.navbar.is-info .navbar-end>.navbar-item,.navbar.is-info .navbar-start .navbar-link,.navbar.is-info .navbar-start>.navbar-item{color:#fff}.navbar.is-info .navbar-end .navbar-link.is-active,.navbar.is-info .navbar-end .navbar-link:hover,.navbar.is-info .navbar-end>a.navbar-item.is-active,.navbar.is-info .navbar-end>a.navbar-item:hover,.navbar.is-info .navbar-start .navbar-link.is-active,.navbar.is-info .navbar-start .navbar-link:hover,.navbar.is-info .navbar-start>a.navbar-item.is-active,.navbar.is-info .navbar-start>a.navbar-item:hover{background-color:#118fe4;color:#fff}.navbar.is-info .navbar-end .navbar-link::after,.navbar.is-info .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-info .navbar-item.has-dropdown:hover .navbar-link{background-color:#118fe4;color:#fff}.navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#209cee;color:#fff}}.navbar.is-success{background-color:#23d160;color:#fff}.navbar.is-success .navbar-brand .navbar-link,.navbar.is-success .navbar-brand>.navbar-item{color:#fff}.navbar.is-success .navbar-brand .navbar-link.is-active,.navbar.is-success .navbar-brand .navbar-link:hover,.navbar.is-success .navbar-brand>a.navbar-item.is-active,.navbar.is-success .navbar-brand>a.navbar-item:hover{background-color:#20bc56;color:#fff}.navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}@media screen and (min-width:1088px){.navbar.is-success .navbar-end .navbar-link,.navbar.is-success .navbar-end>.navbar-item,.navbar.is-success .navbar-start .navbar-link,.navbar.is-success .navbar-start>.navbar-item{color:#fff}.navbar.is-success .navbar-end .navbar-link.is-active,.navbar.is-success .navbar-end .navbar-link:hover,.navbar.is-success .navbar-end>a.navbar-item.is-active,.navbar.is-success .navbar-end>a.navbar-item:hover,.navbar.is-success .navbar-start .navbar-link.is-active,.navbar.is-success .navbar-start .navbar-link:hover,.navbar.is-success .navbar-start>a.navbar-item.is-active,.navbar.is-success .navbar-start>a.navbar-item:hover{background-color:#20bc56;color:#fff}.navbar.is-success .navbar-end .navbar-link::after,.navbar.is-success .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-success .navbar-item.has-dropdown:hover .navbar-link{background-color:#20bc56;color:#fff}.navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#23d160;color:#fff}}.navbar.is-warning{background-color:#ffdd57;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link,.navbar.is-warning .navbar-brand>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link.is-active,.navbar.is-warning .navbar-brand .navbar-link:hover,.navbar.is-warning .navbar-brand>a.navbar-item.is-active,.navbar.is-warning .navbar-brand>a.navbar-item:hover{background-color:#ffd83d;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,.7)}@media screen and (min-width:1088px){.navbar.is-warning .navbar-end .navbar-link,.navbar.is-warning .navbar-end>.navbar-item,.navbar.is-warning .navbar-start .navbar-link,.navbar.is-warning .navbar-start>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-end .navbar-link.is-active,.navbar.is-warning .navbar-end .navbar-link:hover,.navbar.is-warning .navbar-end>a.navbar-item.is-active,.navbar.is-warning .navbar-end>a.navbar-item:hover,.navbar.is-warning .navbar-start .navbar-link.is-active,.navbar.is-warning .navbar-start .navbar-link:hover,.navbar.is-warning .navbar-start>a.navbar-item.is-active,.navbar.is-warning .navbar-start>a.navbar-item:hover{background-color:#ffd83d;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-end .navbar-link::after,.navbar.is-warning .navbar-start .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link{background-color:#ffd83d;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ffdd57;color:rgba(0,0,0,.7)}}.navbar.is-danger{background-color:#ff3860;color:#fff}.navbar.is-danger .navbar-brand .navbar-link,.navbar.is-danger .navbar-brand>.navbar-item{color:#fff}.navbar.is-danger .navbar-brand .navbar-link.is-active,.navbar.is-danger .navbar-brand .navbar-link:hover,.navbar.is-danger .navbar-brand>a.navbar-item.is-active,.navbar.is-danger .navbar-brand>a.navbar-item:hover{background-color:#ff1f4b;color:#fff}.navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}@media screen and (min-width:1088px){.navbar.is-danger .navbar-end .navbar-link,.navbar.is-danger .navbar-end>.navbar-item,.navbar.is-danger .navbar-start .navbar-link,.navbar.is-danger .navbar-start>.navbar-item{color:#fff}.navbar.is-danger .navbar-end .navbar-link.is-active,.navbar.is-danger .navbar-end .navbar-link:hover,.navbar.is-danger .navbar-end>a.navbar-item.is-active,.navbar.is-danger .navbar-end>a.navbar-item:hover,.navbar.is-danger .navbar-start .navbar-link.is-active,.navbar.is-danger .navbar-start .navbar-link:hover,.navbar.is-danger .navbar-start>a.navbar-item.is-active,.navbar.is-danger .navbar-start>a.navbar-item:hover{background-color:#ff1f4b;color:#fff}.navbar.is-danger .navbar-end .navbar-link::after,.navbar.is-danger .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link{background-color:#ff1f4b;color:#fff}.navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#ff3860;color:#fff}}.navbar>.container{align-items:stretch;display:flex;min-height:3.25rem;width:100%}.navbar.has-shadow{box-shadow:0 2px 0 0 #f5f5f5}.navbar.is-fixed-bottom,.navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom{bottom:0}.navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #f5f5f5}.navbar.is-fixed-top{top:0}body.has-navbar-fixed-top,html.has-navbar-fixed-top{padding-top:3.25rem}body.has-navbar-fixed-bottom,html.has-navbar-fixed-bottom{padding-bottom:3.25rem}.navbar-brand,.navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:3.25rem}.navbar-brand a.navbar-item:hover{background-color:transparent}.navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}.navbar-burger{cursor:pointer;display:block;height:3.25rem;position:relative;width:3.25rem;margin-left:auto}.navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;-webkit-transform-origin:center;transform-origin:center;transition-duration:86ms;transition-property:background-color,opacity,-webkit-transform;transition-property:background-color,opacity,transform;transition-property:background-color,opacity,transform,-webkit-transform;transition-timing-function:ease-out;width:16px}.navbar-burger span:nth-child(1){top:calc(50% - 6px)}.navbar-burger span:nth-child(2){top:calc(50% - 1px)}.navbar-burger span:nth-child(3){top:calc(50% + 4px)}.navbar-burger:hover{background-color:rgba(0,0,0,.05)}.navbar-burger.is-active span:nth-child(1){-webkit-transform:translateY(5px) rotate(45deg);transform:translateY(5px) rotate(45deg)}.navbar-burger.is-active span:nth-child(2){opacity:0}.navbar-burger.is-active span:nth-child(3){-webkit-transform:translateY(-5px) rotate(-45deg);transform:translateY(-5px) rotate(-45deg)}.navbar-menu{display:none}.navbar-item,.navbar-link{color:#4a4a4a;display:block;line-height:1.5;padding:.5rem .75rem;position:relative}.navbar-item .icon:only-child,.navbar-link .icon:only-child{margin-left:-.25rem;margin-right:-.25rem}.navbar-link,a.navbar-item{cursor:pointer}.navbar-link.is-active,.navbar-link:hover,a.navbar-item.is-active,a.navbar-item:hover{background-color:#fafafa;color:#3273dc}.navbar-item{display:block;flex-grow:0;flex-shrink:0}.navbar-item img{max-height:1.75rem}.navbar-item.has-dropdown{padding:0}.navbar-item.is-expanded{flex-grow:1;flex-shrink:1}.navbar-item.is-tab{border-bottom:1px solid transparent;min-height:3.25rem;padding-bottom:calc(.5rem - 1px)}.navbar-item.is-tab:hover{background-color:transparent;border-bottom-color:#3273dc}.navbar-item.is-tab.is-active{background-color:transparent;border-bottom-color:#3273dc;border-bottom-style:solid;border-bottom-width:3px;color:#3273dc;padding-bottom:calc(.5rem - 3px)}.navbar-content{flex-grow:1;flex-shrink:1}.navbar-link{padding-right:2.5em}.navbar-link::after{border-color:#3273dc;margin-top:-.375em;right:1.125em}.navbar-dropdown{font-size:.875rem;padding-bottom:.5rem;padding-top:.5rem}.navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}.navbar-divider{background-color:#f5f5f5;border:none;display:none;height:2px;margin:.5rem 0}@media screen and (max-width:1087px){.navbar>.container{display:block}.navbar-brand .navbar-item,.navbar-tabs .navbar-item{align-items:center;display:flex}.navbar-link::after{display:none}.navbar-menu{background-color:#fff;box-shadow:0 8px 16px rgba(10,10,10,.1);padding:.5rem 0}.navbar-menu.is-active{display:block}.navbar.is-fixed-bottom-touch,.navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-touch{bottom:0}.navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,.1)}.navbar.is-fixed-top-touch{top:0}.navbar.is-fixed-top .navbar-menu,.navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 3.25rem);overflow:auto}body.has-navbar-fixed-top-touch,html.has-navbar-fixed-top-touch{padding-top:3.25rem}body.has-navbar-fixed-bottom-touch,html.has-navbar-fixed-bottom-touch{padding-bottom:3.25rem}}@media screen and (min-width:1088px){.navbar,.navbar-end,.navbar-menu,.navbar-start{align-items:stretch;display:flex}.navbar{min-height:3.25rem}.navbar.is-spaced{padding:1rem 2rem}.navbar.is-spaced .navbar-end,.navbar.is-spaced .navbar-start{align-items:center}.navbar.is-spaced .navbar-link,.navbar.is-spaced a.navbar-item{border-radius:4px}.navbar.is-transparent .navbar-link.is-active,.navbar.is-transparent .navbar-link:hover,.navbar.is-transparent a.navbar-item.is-active,.navbar.is-transparent a.navbar-item:hover{background-color:transparent!important}.navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent!important}.navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#3273dc}.navbar-burger{display:none}.navbar-item,.navbar-link{align-items:center;display:flex}.navbar-item{display:flex}.navbar-item.has-dropdown{align-items:stretch}.navbar-item.has-dropdown-up .navbar-link::after{-webkit-transform:rotate(135deg) translate(.25em,-.25em);transform:rotate(135deg) translate(.25em,-.25em)}.navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:2px solid #dbdbdb;border-radius:6px 6px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,.1);top:auto}.navbar-item.is-active .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar-item.is-active .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-active .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown{opacity:1;pointer-events:auto;-webkit-transform:translateY(0);transform:translateY(0)}.navbar-menu{flex-grow:1;flex-shrink:0}.navbar-start{justify-content:flex-start;margin-right:auto}.navbar-end{justify-content:flex-end;margin-left:auto}.navbar-dropdown{background-color:#fff;border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:2px solid #dbdbdb;box-shadow:0 8px 8px rgba(10,10,10,.1);display:none;font-size:.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}.navbar-dropdown .navbar-item{padding:.375rem 1rem;white-space:nowrap}.navbar-dropdown a.navbar-item{padding-right:3rem}.navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#3273dc}.navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-dropdown{border-radius:6px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));-webkit-transform:translateY(-5px);transform:translateY(-5px);transition-duration:86ms;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.navbar-dropdown.is-right{left:auto;right:0}.navbar-divider{display:block}.container>.navbar .navbar-brand,.navbar>.container .navbar-brand{margin-left:-1rem}.container>.navbar .navbar-menu,.navbar>.container .navbar-menu{margin-right:-1rem}.navbar.is-fixed-bottom-desktop,.navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-desktop{bottom:0}.navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,.1)}.navbar.is-fixed-top-desktop{top:0}body.has-navbar-fixed-top-desktop,html.has-navbar-fixed-top-desktop{padding-top:3.25rem}body.has-navbar-fixed-bottom-desktop,html.has-navbar-fixed-bottom-desktop{padding-bottom:3.25rem}body.has-spaced-navbar-fixed-top,html.has-spaced-navbar-fixed-top{padding-top:5.25rem}body.has-spaced-navbar-fixed-bottom,html.has-spaced-navbar-fixed-bottom{padding-bottom:5.25rem}.navbar-link.is-active,a.navbar-item.is-active{color:#0a0a0a}.navbar-link.is-active:not(:hover),a.navbar-item.is-active:not(:hover){background-color:transparent}.navbar-item.has-dropdown.is-active .navbar-link,.navbar-item.has-dropdown:hover .navbar-link{background-color:#fafafa}}.pagination{font-size:1rem;margin:-.25rem}.pagination.is-small{font-size:.75rem}.pagination.is-medium{font-size:1.25rem}.pagination.is-large{font-size:1.5rem}.pagination.is-rounded .pagination-next,.pagination.is-rounded .pagination-previous{padding-left:1em;padding-right:1em;border-radius:290486px}.pagination.is-rounded .pagination-link{border-radius:290486px}.pagination,.pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous{font-size:1em;padding-left:.5em;padding-right:.5em;justify-content:center;margin:.25rem;text-align:center}.pagination-link,.pagination-next,.pagination-previous{border-color:#dbdbdb;color:#363636;min-width:2.25em}.pagination-link:hover,.pagination-next:hover,.pagination-previous:hover{border-color:#b5b5b5;color:#363636}.pagination-link:focus,.pagination-next:focus,.pagination-previous:focus{border-color:#3273dc}.pagination-link:active,.pagination-next:active,.pagination-previous:active{box-shadow:inset 0 1px 2px rgba(10,10,10,.2)}.pagination-link[disabled],.pagination-next[disabled],.pagination-previous[disabled]{background-color:#dbdbdb;border-color:#dbdbdb;box-shadow:none;color:#7a7a7a;opacity:.5}.pagination-next,.pagination-previous{padding-left:.75em;padding-right:.75em;white-space:nowrap}.pagination-link.is-current{background-color:#3273dc;border-color:#3273dc;color:#fff}.pagination-ellipsis{color:#b5b5b5;pointer-events:none}.pagination-list{flex-wrap:wrap}@media screen and (max-width:768px){.pagination{flex-wrap:wrap}.pagination-next,.pagination-previous{flex-grow:1;flex-shrink:1}.pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width:769px),print{.pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}.pagination-previous{order:2}.pagination-next{order:3}.pagination{justify-content:space-between}.pagination.is-centered .pagination-previous{order:1}.pagination.is-centered .pagination-list{justify-content:center;order:2}.pagination.is-centered .pagination-next{order:3}.pagination.is-right .pagination-previous{order:1}.pagination.is-right .pagination-next{order:2}.pagination.is-right .pagination-list{justify-content:flex-end;order:3}}.panel{font-size:1rem}.panel:not(:last-child){margin-bottom:1.5rem}.panel-block,.panel-heading,.panel-tabs{border-bottom:1px solid #dbdbdb;border-left:1px solid #dbdbdb;border-right:1px solid #dbdbdb}.panel-block:first-child,.panel-heading:first-child,.panel-tabs:first-child{border-top:1px solid #dbdbdb}.panel-heading{background-color:#f5f5f5;border-radius:4px 4px 0 0;color:#363636;font-size:1.25em;font-weight:300;line-height:1.25;padding:.5em .75em}.panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}.panel-tabs a{border-bottom:1px solid #dbdbdb;margin-bottom:-1px;padding:.5em}.panel-tabs a.is-active{border-bottom-color:#4a4a4a;color:#363636}.panel-list a{color:#4a4a4a}.panel-list a:hover{color:#3273dc}.panel-block{align-items:center;color:#363636;display:flex;justify-content:flex-start;padding:.5em .75em}.panel-block input[type=checkbox]{margin-right:.75em}.panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}.panel-block.is-wrapped{flex-wrap:wrap}.panel-block.is-active{border-left-color:#3273dc;color:#363636}.panel-block.is-active .panel-icon{color:#3273dc}a.panel-block,label.panel-block{cursor:pointer}a.panel-block:hover,label.panel-block:hover{background-color:#f5f5f5}.panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#7a7a7a;margin-right:.75em}.panel-icon .fa{font-size:inherit;line-height:inherit}.tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}.tabs a{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;color:#4a4a4a;display:flex;justify-content:center;margin-bottom:-1px;padding:.5em 1em;vertical-align:top}.tabs a:hover{border-bottom-color:#363636;color:#363636}.tabs li{display:block}.tabs li.is-active a{border-bottom-color:#3273dc;color:#3273dc}.tabs ul{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}.tabs ul.is-left{padding-right:.75em}.tabs ul.is-center{flex:none;justify-content:center;padding-left:.75em;padding-right:.75em}.tabs ul.is-right{justify-content:flex-end;padding-left:.75em}.tabs .icon:first-child{margin-right:.5em}.tabs .icon:last-child{margin-left:.5em}.tabs.is-centered ul{justify-content:center}.tabs.is-right ul{justify-content:flex-end}.tabs.is-boxed a{border:1px solid transparent;border-radius:4px 4px 0 0}.tabs.is-boxed a:hover{background-color:#f5f5f5;border-bottom-color:#dbdbdb}.tabs.is-boxed li.is-active a{background-color:#fff;border-color:#dbdbdb;border-bottom-color:transparent!important}.tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}.tabs.is-toggle a{border-color:#dbdbdb;border-style:solid;border-width:1px;margin-bottom:0;position:relative}.tabs.is-toggle a:hover{background-color:#f5f5f5;border-color:#b5b5b5;z-index:2}.tabs.is-toggle li+li{margin-left:-1px}.tabs.is-toggle li:first-child a{border-radius:4px 0 0 4px}.tabs.is-toggle li:last-child a{border-radius:0 4px 4px 0}.tabs.is-toggle li.is-active a{background-color:#3273dc;border-color:#3273dc;color:#fff;z-index:1}.tabs.is-toggle ul{border-bottom:none}.tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:290486px;border-top-left-radius:290486px;padding-left:1.25em}.tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:290486px;border-top-right-radius:290486px;padding-right:1.25em}.tabs.is-small{font-size:.75rem}.tabs.is-medium{font-size:1.25rem}.tabs.is-large{font-size:1.5rem}.column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>.column.is-narrow{flex:none}.columns.is-mobile>.column.is-full{flex:none;width:100%}.columns.is-mobile>.column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>.column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>.column.is-half{flex:none;width:50%}.columns.is-mobile>.column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>.column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>.column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>.column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>.column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>.column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>.column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>.column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>.column.is-offset-half{margin-left:50%}.columns.is-mobile>.column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>.column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>.column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>.column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>.column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>.column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>.column.is-1{flex:none;width:8.33333%}.columns.is-mobile>.column.is-offset-1{margin-left:8.33333%}.columns.is-mobile>.column.is-2{flex:none;width:16.66667%}.columns.is-mobile>.column.is-offset-2{margin-left:16.66667%}.columns.is-mobile>.column.is-3{flex:none;width:25%}.columns.is-mobile>.column.is-offset-3{margin-left:25%}.columns.is-mobile>.column.is-4{flex:none;width:33.33333%}.columns.is-mobile>.column.is-offset-4{margin-left:33.33333%}.columns.is-mobile>.column.is-5{flex:none;width:41.66667%}.columns.is-mobile>.column.is-offset-5{margin-left:41.66667%}.columns.is-mobile>.column.is-6{flex:none;width:50%}.columns.is-mobile>.column.is-offset-6{margin-left:50%}.columns.is-mobile>.column.is-7{flex:none;width:58.33333%}.columns.is-mobile>.column.is-offset-7{margin-left:58.33333%}.columns.is-mobile>.column.is-8{flex:none;width:66.66667%}.columns.is-mobile>.column.is-offset-8{margin-left:66.66667%}.columns.is-mobile>.column.is-9{flex:none;width:75%}.columns.is-mobile>.column.is-offset-9{margin-left:75%}.columns.is-mobile>.column.is-10{flex:none;width:83.33333%}.columns.is-mobile>.column.is-offset-10{margin-left:83.33333%}.columns.is-mobile>.column.is-11{flex:none;width:91.66667%}.columns.is-mobile>.column.is-offset-11{margin-left:91.66667%}.columns.is-mobile>.column.is-12{flex:none;width:100%}.columns.is-mobile>.column.is-offset-12{margin-left:100%}@media screen and (max-width:768px){.column.is-narrow-mobile{flex:none}.column.is-full-mobile{flex:none;width:100%}.column.is-three-quarters-mobile{flex:none;width:75%}.column.is-two-thirds-mobile{flex:none;width:66.6666%}.column.is-half-mobile{flex:none;width:50%}.column.is-one-third-mobile{flex:none;width:33.3333%}.column.is-one-quarter-mobile{flex:none;width:25%}.column.is-one-fifth-mobile{flex:none;width:20%}.column.is-two-fifths-mobile{flex:none;width:40%}.column.is-three-fifths-mobile{flex:none;width:60%}.column.is-four-fifths-mobile{flex:none;width:80%}.column.is-offset-three-quarters-mobile{margin-left:75%}.column.is-offset-two-thirds-mobile{margin-left:66.6666%}.column.is-offset-half-mobile{margin-left:50%}.column.is-offset-one-third-mobile{margin-left:33.3333%}.column.is-offset-one-quarter-mobile{margin-left:25%}.column.is-offset-one-fifth-mobile{margin-left:20%}.column.is-offset-two-fifths-mobile{margin-left:40%}.column.is-offset-three-fifths-mobile{margin-left:60%}.column.is-offset-four-fifths-mobile{margin-left:80%}.column.is-1-mobile{flex:none;width:8.33333%}.column.is-offset-1-mobile{margin-left:8.33333%}.column.is-2-mobile{flex:none;width:16.66667%}.column.is-offset-2-mobile{margin-left:16.66667%}.column.is-3-mobile{flex:none;width:25%}.column.is-offset-3-mobile{margin-left:25%}.column.is-4-mobile{flex:none;width:33.33333%}.column.is-offset-4-mobile{margin-left:33.33333%}.column.is-5-mobile{flex:none;width:41.66667%}.column.is-offset-5-mobile{margin-left:41.66667%}.column.is-6-mobile{flex:none;width:50%}.column.is-offset-6-mobile{margin-left:50%}.column.is-7-mobile{flex:none;width:58.33333%}.column.is-offset-7-mobile{margin-left:58.33333%}.column.is-8-mobile{flex:none;width:66.66667%}.column.is-offset-8-mobile{margin-left:66.66667%}.column.is-9-mobile{flex:none;width:75%}.column.is-offset-9-mobile{margin-left:75%}.column.is-10-mobile{flex:none;width:83.33333%}.column.is-offset-10-mobile{margin-left:83.33333%}.column.is-11-mobile{flex:none;width:91.66667%}.column.is-offset-11-mobile{margin-left:91.66667%}.column.is-12-mobile{flex:none;width:100%}.column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width:769px),print{.column.is-narrow,.column.is-narrow-tablet{flex:none}.column.is-full,.column.is-full-tablet{flex:none;width:100%}.column.is-three-quarters,.column.is-three-quarters-tablet{flex:none;width:75%}.column.is-two-thirds,.column.is-two-thirds-tablet{flex:none;width:66.6666%}.column.is-half,.column.is-half-tablet{flex:none;width:50%}.column.is-one-third,.column.is-one-third-tablet{flex:none;width:33.3333%}.column.is-one-quarter,.column.is-one-quarter-tablet{flex:none;width:25%}.column.is-one-fifth,.column.is-one-fifth-tablet{flex:none;width:20%}.column.is-two-fifths,.column.is-two-fifths-tablet{flex:none;width:40%}.column.is-three-fifths,.column.is-three-fifths-tablet{flex:none;width:60%}.column.is-four-fifths,.column.is-four-fifths-tablet{flex:none;width:80%}.column.is-offset-three-quarters,.column.is-offset-three-quarters-tablet{margin-left:75%}.column.is-offset-two-thirds,.column.is-offset-two-thirds-tablet{margin-left:66.6666%}.column.is-offset-half,.column.is-offset-half-tablet{margin-left:50%}.column.is-offset-one-third,.column.is-offset-one-third-tablet{margin-left:33.3333%}.column.is-offset-one-quarter,.column.is-offset-one-quarter-tablet{margin-left:25%}.column.is-offset-one-fifth,.column.is-offset-one-fifth-tablet{margin-left:20%}.column.is-offset-two-fifths,.column.is-offset-two-fifths-tablet{margin-left:40%}.column.is-offset-three-fifths,.column.is-offset-three-fifths-tablet{margin-left:60%}.column.is-offset-four-fifths,.column.is-offset-four-fifths-tablet{margin-left:80%}.column.is-1,.column.is-1-tablet{flex:none;width:8.33333%}.column.is-offset-1,.column.is-offset-1-tablet{margin-left:8.33333%}.column.is-2,.column.is-2-tablet{flex:none;width:16.66667%}.column.is-offset-2,.column.is-offset-2-tablet{margin-left:16.66667%}.column.is-3,.column.is-3-tablet{flex:none;width:25%}.column.is-offset-3,.column.is-offset-3-tablet{margin-left:25%}.column.is-4,.column.is-4-tablet{flex:none;width:33.33333%}.column.is-offset-4,.column.is-offset-4-tablet{margin-left:33.33333%}.column.is-5,.column.is-5-tablet{flex:none;width:41.66667%}.column.is-offset-5,.column.is-offset-5-tablet{margin-left:41.66667%}.column.is-6,.column.is-6-tablet{flex:none;width:50%}.column.is-offset-6,.column.is-offset-6-tablet{margin-left:50%}.column.is-7,.column.is-7-tablet{flex:none;width:58.33333%}.column.is-offset-7,.column.is-offset-7-tablet{margin-left:58.33333%}.column.is-8,.column.is-8-tablet{flex:none;width:66.66667%}.column.is-offset-8,.column.is-offset-8-tablet{margin-left:66.66667%}.column.is-9,.column.is-9-tablet{flex:none;width:75%}.column.is-offset-9,.column.is-offset-9-tablet{margin-left:75%}.column.is-10,.column.is-10-tablet{flex:none;width:83.33333%}.column.is-offset-10,.column.is-offset-10-tablet{margin-left:83.33333%}.column.is-11,.column.is-11-tablet{flex:none;width:91.66667%}.column.is-offset-11,.column.is-offset-11-tablet{margin-left:91.66667%}.column.is-12,.column.is-12-tablet{flex:none;width:100%}.column.is-offset-12,.column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width:1087px){.column.is-narrow-touch{flex:none}.column.is-full-touch{flex:none;width:100%}.column.is-three-quarters-touch{flex:none;width:75%}.column.is-two-thirds-touch{flex:none;width:66.6666%}.column.is-half-touch{flex:none;width:50%}.column.is-one-third-touch{flex:none;width:33.3333%}.column.is-one-quarter-touch{flex:none;width:25%}.column.is-one-fifth-touch{flex:none;width:20%}.column.is-two-fifths-touch{flex:none;width:40%}.column.is-three-fifths-touch{flex:none;width:60%}.column.is-four-fifths-touch{flex:none;width:80%}.column.is-offset-three-quarters-touch{margin-left:75%}.column.is-offset-two-thirds-touch{margin-left:66.6666%}.column.is-offset-half-touch{margin-left:50%}.column.is-offset-one-third-touch{margin-left:33.3333%}.column.is-offset-one-quarter-touch{margin-left:25%}.column.is-offset-one-fifth-touch{margin-left:20%}.column.is-offset-two-fifths-touch{margin-left:40%}.column.is-offset-three-fifths-touch{margin-left:60%}.column.is-offset-four-fifths-touch{margin-left:80%}.column.is-1-touch{flex:none;width:8.33333%}.column.is-offset-1-touch{margin-left:8.33333%}.column.is-2-touch{flex:none;width:16.66667%}.column.is-offset-2-touch{margin-left:16.66667%}.column.is-3-touch{flex:none;width:25%}.column.is-offset-3-touch{margin-left:25%}.column.is-4-touch{flex:none;width:33.33333%}.column.is-offset-4-touch{margin-left:33.33333%}.column.is-5-touch{flex:none;width:41.66667%}.column.is-offset-5-touch{margin-left:41.66667%}.column.is-6-touch{flex:none;width:50%}.column.is-offset-6-touch{margin-left:50%}.column.is-7-touch{flex:none;width:58.33333%}.column.is-offset-7-touch{margin-left:58.33333%}.column.is-8-touch{flex:none;width:66.66667%}.column.is-offset-8-touch{margin-left:66.66667%}.column.is-9-touch{flex:none;width:75%}.column.is-offset-9-touch{margin-left:75%}.column.is-10-touch{flex:none;width:83.33333%}.column.is-offset-10-touch{margin-left:83.33333%}.column.is-11-touch{flex:none;width:91.66667%}.column.is-offset-11-touch{margin-left:91.66667%}.column.is-12-touch{flex:none;width:100%}.column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width:1088px){.column.is-narrow-desktop{flex:none}.column.is-full-desktop{flex:none;width:100%}.column.is-three-quarters-desktop{flex:none;width:75%}.column.is-two-thirds-desktop{flex:none;width:66.6666%}.column.is-half-desktop{flex:none;width:50%}.column.is-one-third-desktop{flex:none;width:33.3333%}.column.is-one-quarter-desktop{flex:none;width:25%}.column.is-one-fifth-desktop{flex:none;width:20%}.column.is-two-fifths-desktop{flex:none;width:40%}.column.is-three-fifths-desktop{flex:none;width:60%}.column.is-four-fifths-desktop{flex:none;width:80%}.column.is-offset-three-quarters-desktop{margin-left:75%}.column.is-offset-two-thirds-desktop{margin-left:66.6666%}.column.is-offset-half-desktop{margin-left:50%}.column.is-offset-one-third-desktop{margin-left:33.3333%}.column.is-offset-one-quarter-desktop{margin-left:25%}.column.is-offset-one-fifth-desktop{margin-left:20%}.column.is-offset-two-fifths-desktop{margin-left:40%}.column.is-offset-three-fifths-desktop{margin-left:60%}.column.is-offset-four-fifths-desktop{margin-left:80%}.column.is-1-desktop{flex:none;width:8.33333%}.column.is-offset-1-desktop{margin-left:8.33333%}.column.is-2-desktop{flex:none;width:16.66667%}.column.is-offset-2-desktop{margin-left:16.66667%}.column.is-3-desktop{flex:none;width:25%}.column.is-offset-3-desktop{margin-left:25%}.column.is-4-desktop{flex:none;width:33.33333%}.column.is-offset-4-desktop{margin-left:33.33333%}.column.is-5-desktop{flex:none;width:41.66667%}.column.is-offset-5-desktop{margin-left:41.66667%}.column.is-6-desktop{flex:none;width:50%}.column.is-offset-6-desktop{margin-left:50%}.column.is-7-desktop{flex:none;width:58.33333%}.column.is-offset-7-desktop{margin-left:58.33333%}.column.is-8-desktop{flex:none;width:66.66667%}.column.is-offset-8-desktop{margin-left:66.66667%}.column.is-9-desktop{flex:none;width:75%}.column.is-offset-9-desktop{margin-left:75%}.column.is-10-desktop{flex:none;width:83.33333%}.column.is-offset-10-desktop{margin-left:83.33333%}.column.is-11-desktop{flex:none;width:91.66667%}.column.is-offset-11-desktop{margin-left:91.66667%}.column.is-12-desktop{flex:none;width:100%}.column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width:1280px){.column.is-narrow-widescreen{flex:none}.column.is-full-widescreen{flex:none;width:100%}.column.is-three-quarters-widescreen{flex:none;width:75%}.column.is-two-thirds-widescreen{flex:none;width:66.6666%}.column.is-half-widescreen{flex:none;width:50%}.column.is-one-third-widescreen{flex:none;width:33.3333%}.column.is-one-quarter-widescreen{flex:none;width:25%}.column.is-one-fifth-widescreen{flex:none;width:20%}.column.is-two-fifths-widescreen{flex:none;width:40%}.column.is-three-fifths-widescreen{flex:none;width:60%}.column.is-four-fifths-widescreen{flex:none;width:80%}.column.is-offset-three-quarters-widescreen{margin-left:75%}.column.is-offset-two-thirds-widescreen{margin-left:66.6666%}.column.is-offset-half-widescreen{margin-left:50%}.column.is-offset-one-third-widescreen{margin-left:33.3333%}.column.is-offset-one-quarter-widescreen{margin-left:25%}.column.is-offset-one-fifth-widescreen{margin-left:20%}.column.is-offset-two-fifths-widescreen{margin-left:40%}.column.is-offset-three-fifths-widescreen{margin-left:60%}.column.is-offset-four-fifths-widescreen{margin-left:80%}.column.is-1-widescreen{flex:none;width:8.33333%}.column.is-offset-1-widescreen{margin-left:8.33333%}.column.is-2-widescreen{flex:none;width:16.66667%}.column.is-offset-2-widescreen{margin-left:16.66667%}.column.is-3-widescreen{flex:none;width:25%}.column.is-offset-3-widescreen{margin-left:25%}.column.is-4-widescreen{flex:none;width:33.33333%}.column.is-offset-4-widescreen{margin-left:33.33333%}.column.is-5-widescreen{flex:none;width:41.66667%}.column.is-offset-5-widescreen{margin-left:41.66667%}.column.is-6-widescreen{flex:none;width:50%}.column.is-offset-6-widescreen{margin-left:50%}.column.is-7-widescreen{flex:none;width:58.33333%}.column.is-offset-7-widescreen{margin-left:58.33333%}.column.is-8-widescreen{flex:none;width:66.66667%}.column.is-offset-8-widescreen{margin-left:66.66667%}.column.is-9-widescreen{flex:none;width:75%}.column.is-offset-9-widescreen{margin-left:75%}.column.is-10-widescreen{flex:none;width:83.33333%}.column.is-offset-10-widescreen{margin-left:83.33333%}.column.is-11-widescreen{flex:none;width:91.66667%}.column.is-offset-11-widescreen{margin-left:91.66667%}.column.is-12-widescreen{flex:none;width:100%}.column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width:1472px){.column.is-narrow-fullhd{flex:none}.column.is-full-fullhd{flex:none;width:100%}.column.is-three-quarters-fullhd{flex:none;width:75%}.column.is-two-thirds-fullhd{flex:none;width:66.6666%}.column.is-half-fullhd{flex:none;width:50%}.column.is-one-third-fullhd{flex:none;width:33.3333%}.column.is-one-quarter-fullhd{flex:none;width:25%}.column.is-one-fifth-fullhd{flex:none;width:20%}.column.is-two-fifths-fullhd{flex:none;width:40%}.column.is-three-fifths-fullhd{flex:none;width:60%}.column.is-four-fifths-fullhd{flex:none;width:80%}.column.is-offset-three-quarters-fullhd{margin-left:75%}.column.is-offset-two-thirds-fullhd{margin-left:66.6666%}.column.is-offset-half-fullhd{margin-left:50%}.column.is-offset-one-third-fullhd{margin-left:33.3333%}.column.is-offset-one-quarter-fullhd{margin-left:25%}.column.is-offset-one-fifth-fullhd{margin-left:20%}.column.is-offset-two-fifths-fullhd{margin-left:40%}.column.is-offset-three-fifths-fullhd{margin-left:60%}.column.is-offset-four-fifths-fullhd{margin-left:80%}.column.is-1-fullhd{flex:none;width:8.33333%}.column.is-offset-1-fullhd{margin-left:8.33333%}.column.is-2-fullhd{flex:none;width:16.66667%}.column.is-offset-2-fullhd{margin-left:16.66667%}.column.is-3-fullhd{flex:none;width:25%}.column.is-offset-3-fullhd{margin-left:25%}.column.is-4-fullhd{flex:none;width:33.33333%}.column.is-offset-4-fullhd{margin-left:33.33333%}.column.is-5-fullhd{flex:none;width:41.66667%}.column.is-offset-5-fullhd{margin-left:41.66667%}.column.is-6-fullhd{flex:none;width:50%}.column.is-offset-6-fullhd{margin-left:50%}.column.is-7-fullhd{flex:none;width:58.33333%}.column.is-offset-7-fullhd{margin-left:58.33333%}.column.is-8-fullhd{flex:none;width:66.66667%}.column.is-offset-8-fullhd{margin-left:66.66667%}.column.is-9-fullhd{flex:none;width:75%}.column.is-offset-9-fullhd{margin-left:75%}.column.is-10-fullhd{flex:none;width:83.33333%}.column.is-offset-10-fullhd{margin-left:83.33333%}.column.is-11-fullhd{flex:none;width:91.66667%}.column.is-offset-11-fullhd{margin-left:91.66667%}.column.is-12-fullhd{flex:none;width:100%}.column.is-offset-12-fullhd{margin-left:100%}}.columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.columns:last-child{margin-bottom:-.75rem}.columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}.columns.is-centered{justify-content:center}.columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}.columns.is-gapless>.column{margin:0;padding:0!important}.columns.is-gapless:not(:last-child){margin-bottom:1.5rem}.columns.is-gapless:last-child{margin-bottom:0}.columns.is-mobile{display:flex}.columns.is-multiline{flex-wrap:wrap}.columns.is-vcentered{align-items:center}@media screen and (min-width:769px),print{.columns:not(.is-desktop){display:flex}}@media screen and (min-width:1088px){.columns.is-desktop{display:flex}}.columns.is-variable{--columnGap:0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}.columns.is-variable .column{padding-left:var(--columnGap);padding-right:var(--columnGap)}.columns.is-variable.is-0{--columnGap:0rem}.columns.is-variable.is-1{--columnGap:0.25rem}.columns.is-variable.is-2{--columnGap:0.5rem}.columns.is-variable.is-3{--columnGap:0.75rem}.columns.is-variable.is-4{--columnGap:1rem}.columns.is-variable.is-5{--columnGap:1.25rem}.columns.is-variable.is-6{--columnGap:1.5rem}.columns.is-variable.is-7{--columnGap:1.75rem}.columns.is-variable.is-8{--columnGap:2rem}.tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:-webkit-min-content;min-height:-moz-min-content;min-height:min-content}.tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.tile.is-ancestor:last-child{margin-bottom:-.75rem}.tile.is-ancestor:not(:last-child){margin-bottom:.75rem}.tile.is-child{margin:0!important}.tile.is-parent{padding:.75rem}.tile.is-vertical{flex-direction:column}.tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem!important}@media screen and (min-width:769px),print{.tile:not(.is-child){display:flex}.tile.is-1{flex:none;width:8.33333%}.tile.is-2{flex:none;width:16.66667%}.tile.is-3{flex:none;width:25%}.tile.is-4{flex:none;width:33.33333%}.tile.is-5{flex:none;width:41.66667%}.tile.is-6{flex:none;width:50%}.tile.is-7{flex:none;width:58.33333%}.tile.is-8{flex:none;width:66.66667%}.tile.is-9{flex:none;width:75%}.tile.is-10{flex:none;width:83.33333%}.tile.is-11{flex:none;width:91.66667%}.tile.is-12{flex:none;width:100%}}.hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}.hero .navbar{background:0 0}.hero .tabs ul{border-bottom:none}.hero.is-white{background-color:#fff;color:#0a0a0a}.hero.is-white a:not(.button):not(.dropdown-item):not(.tag),.hero.is-white strong{color:inherit}.hero.is-white .title{color:#0a0a0a}.hero.is-white .subtitle{color:rgba(10,10,10,.9)}.hero.is-white .subtitle a:not(.button),.hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width:1087px){.hero.is-white .navbar-menu{background-color:#fff}}.hero.is-white .navbar-item,.hero.is-white .navbar-link{color:rgba(10,10,10,.7)}.hero.is-white .navbar-link.is-active,.hero.is-white .navbar-link:hover,.hero.is-white a.navbar-item.is-active,.hero.is-white a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.hero.is-white .tabs a{color:#0a0a0a;opacity:.9}.hero.is-white .tabs a:hover{opacity:1}.hero.is-white .tabs li.is-active a{opacity:1}.hero.is-white .tabs.is-boxed a,.hero.is-white .tabs.is-toggle a{color:#0a0a0a}.hero.is-white .tabs.is-boxed a:hover,.hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-white .tabs.is-boxed li.is-active a,.hero.is-white .tabs.is-boxed li.is-active a:hover,.hero.is-white .tabs.is-toggle li.is-active a,.hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.hero.is-white.is-bold{background-image:linear-gradient(141deg,#e6e6e6 0,#fff 71%,#fff 100%)}@media screen and (max-width:768px){.hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg,#e6e6e6 0,#fff 71%,#fff 100%)}}.hero.is-black{background-color:#0a0a0a;color:#fff}.hero.is-black a:not(.button):not(.dropdown-item):not(.tag),.hero.is-black strong{color:inherit}.hero.is-black .title{color:#fff}.hero.is-black .subtitle{color:rgba(255,255,255,.9)}.hero.is-black .subtitle a:not(.button),.hero.is-black .subtitle strong{color:#fff}@media screen and (max-width:1087px){.hero.is-black .navbar-menu{background-color:#0a0a0a}}.hero.is-black .navbar-item,.hero.is-black .navbar-link{color:rgba(255,255,255,.7)}.hero.is-black .navbar-link.is-active,.hero.is-black .navbar-link:hover,.hero.is-black a.navbar-item.is-active,.hero.is-black a.navbar-item:hover{background-color:#000;color:#fff}.hero.is-black .tabs a{color:#fff;opacity:.9}.hero.is-black .tabs a:hover{opacity:1}.hero.is-black .tabs li.is-active a{opacity:1}.hero.is-black .tabs.is-boxed a,.hero.is-black .tabs.is-toggle a{color:#fff}.hero.is-black .tabs.is-boxed a:hover,.hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-black .tabs.is-boxed li.is-active a,.hero.is-black .tabs.is-boxed li.is-active a:hover,.hero.is-black .tabs.is-toggle li.is-active a,.hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.hero.is-black.is-bold{background-image:linear-gradient(141deg,#000 0,#0a0a0a 71%,#181616 100%)}@media screen and (max-width:768px){.hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg,#000 0,#0a0a0a 71%,#181616 100%)}}.hero.is-light{background-color:#f5f5f5;color:#363636}.hero.is-light a:not(.button):not(.dropdown-item):not(.tag),.hero.is-light strong{color:inherit}.hero.is-light .title{color:#363636}.hero.is-light .subtitle{color:rgba(54,54,54,.9)}.hero.is-light .subtitle a:not(.button),.hero.is-light .subtitle strong{color:#363636}@media screen and (max-width:1087px){.hero.is-light .navbar-menu{background-color:#f5f5f5}}.hero.is-light .navbar-item,.hero.is-light .navbar-link{color:rgba(54,54,54,.7)}.hero.is-light .navbar-link.is-active,.hero.is-light .navbar-link:hover,.hero.is-light a.navbar-item.is-active,.hero.is-light a.navbar-item:hover{background-color:#e8e8e8;color:#363636}.hero.is-light .tabs a{color:#363636;opacity:.9}.hero.is-light .tabs a:hover{opacity:1}.hero.is-light .tabs li.is-active a{opacity:1}.hero.is-light .tabs.is-boxed a,.hero.is-light .tabs.is-toggle a{color:#363636}.hero.is-light .tabs.is-boxed a:hover,.hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-light .tabs.is-boxed li.is-active a,.hero.is-light .tabs.is-boxed li.is-active a:hover,.hero.is-light .tabs.is-toggle li.is-active a,.hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:#363636;border-color:#363636;color:#f5f5f5}.hero.is-light.is-bold{background-image:linear-gradient(141deg,#dfd8d9 0,#f5f5f5 71%,#fff 100%)}@media screen and (max-width:768px){.hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg,#dfd8d9 0,#f5f5f5 71%,#fff 100%)}}.hero.is-dark{background-color:#363636;color:#f5f5f5}.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag),.hero.is-dark strong{color:inherit}.hero.is-dark .title{color:#f5f5f5}.hero.is-dark .subtitle{color:rgba(245,245,245,.9)}.hero.is-dark .subtitle a:not(.button),.hero.is-dark .subtitle strong{color:#f5f5f5}@media screen and (max-width:1087px){.hero.is-dark .navbar-menu{background-color:#363636}}.hero.is-dark .navbar-item,.hero.is-dark .navbar-link{color:rgba(245,245,245,.7)}.hero.is-dark .navbar-link.is-active,.hero.is-dark .navbar-link:hover,.hero.is-dark a.navbar-item.is-active,.hero.is-dark a.navbar-item:hover{background-color:#292929;color:#f5f5f5}.hero.is-dark .tabs a{color:#f5f5f5;opacity:.9}.hero.is-dark .tabs a:hover{opacity:1}.hero.is-dark .tabs li.is-active a{opacity:1}.hero.is-dark .tabs.is-boxed a,.hero.is-dark .tabs.is-toggle a{color:#f5f5f5}.hero.is-dark .tabs.is-boxed a:hover,.hero.is-dark .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-dark .tabs.is-boxed li.is-active a,.hero.is-dark .tabs.is-boxed li.is-active a:hover,.hero.is-dark .tabs.is-toggle li.is-active a,.hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#f5f5f5;border-color:#f5f5f5;color:#363636}.hero.is-dark.is-bold{background-image:linear-gradient(141deg,#1f191a 0,#363636 71%,#46403f 100%)}@media screen and (max-width:768px){.hero.is-dark.is-bold .navbar-menu{background-image:linear-gradient(141deg,#1f191a 0,#363636 71%,#46403f 100%)}}.hero.is-primary{background-color:#00d1b2;color:#fff}.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag),.hero.is-primary strong{color:inherit}.hero.is-primary .title{color:#fff}.hero.is-primary .subtitle{color:rgba(255,255,255,.9)}.hero.is-primary .subtitle a:not(.button),.hero.is-primary .subtitle strong{color:#fff}@media screen and (max-width:1087px){.hero.is-primary .navbar-menu{background-color:#00d1b2}}.hero.is-primary .navbar-item,.hero.is-primary .navbar-link{color:rgba(255,255,255,.7)}.hero.is-primary .navbar-link.is-active,.hero.is-primary .navbar-link:hover,.hero.is-primary a.navbar-item.is-active,.hero.is-primary a.navbar-item:hover{background-color:#00b89c;color:#fff}.hero.is-primary .tabs a{color:#fff;opacity:.9}.hero.is-primary .tabs a:hover{opacity:1}.hero.is-primary .tabs li.is-active a{opacity:1}.hero.is-primary .tabs.is-boxed a,.hero.is-primary .tabs.is-toggle a{color:#fff}.hero.is-primary .tabs.is-boxed a:hover,.hero.is-primary .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-primary .tabs.is-boxed li.is-active a,.hero.is-primary .tabs.is-boxed li.is-active a:hover,.hero.is-primary .tabs.is-toggle li.is-active a,.hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#00d1b2}.hero.is-primary.is-bold{background-image:linear-gradient(141deg,#009e6c 0,#00d1b2 71%,#00e7eb 100%)}@media screen and (max-width:768px){.hero.is-primary.is-bold .navbar-menu{background-image:linear-gradient(141deg,#009e6c 0,#00d1b2 71%,#00e7eb 100%)}}.hero.is-link{background-color:#3273dc;color:#fff}.hero.is-link a:not(.button):not(.dropdown-item):not(.tag),.hero.is-link strong{color:inherit}.hero.is-link .title{color:#fff}.hero.is-link .subtitle{color:rgba(255,255,255,.9)}.hero.is-link .subtitle a:not(.button),.hero.is-link .subtitle strong{color:#fff}@media screen and (max-width:1087px){.hero.is-link .navbar-menu{background-color:#3273dc}}.hero.is-link .navbar-item,.hero.is-link .navbar-link{color:rgba(255,255,255,.7)}.hero.is-link .navbar-link.is-active,.hero.is-link .navbar-link:hover,.hero.is-link a.navbar-item.is-active,.hero.is-link a.navbar-item:hover{background-color:#2366d1;color:#fff}.hero.is-link .tabs a{color:#fff;opacity:.9}.hero.is-link .tabs a:hover{opacity:1}.hero.is-link .tabs li.is-active a{opacity:1}.hero.is-link .tabs.is-boxed a,.hero.is-link .tabs.is-toggle a{color:#fff}.hero.is-link .tabs.is-boxed a:hover,.hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-link .tabs.is-boxed li.is-active a,.hero.is-link .tabs.is-boxed li.is-active a:hover,.hero.is-link .tabs.is-toggle li.is-active a,.hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#3273dc}.hero.is-link.is-bold{background-image:linear-gradient(141deg,#1577c6 0,#3273dc 71%,#4366e5 100%)}@media screen and (max-width:768px){.hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg,#1577c6 0,#3273dc 71%,#4366e5 100%)}}.hero.is-info{background-color:#209cee;color:#fff}.hero.is-info a:not(.button):not(.dropdown-item):not(.tag),.hero.is-info strong{color:inherit}.hero.is-info .title{color:#fff}.hero.is-info .subtitle{color:rgba(255,255,255,.9)}.hero.is-info .subtitle a:not(.button),.hero.is-info .subtitle strong{color:#fff}@media screen and (max-width:1087px){.hero.is-info .navbar-menu{background-color:#209cee}}.hero.is-info .navbar-item,.hero.is-info .navbar-link{color:rgba(255,255,255,.7)}.hero.is-info .navbar-link.is-active,.hero.is-info .navbar-link:hover,.hero.is-info a.navbar-item.is-active,.hero.is-info a.navbar-item:hover{background-color:#118fe4;color:#fff}.hero.is-info .tabs a{color:#fff;opacity:.9}.hero.is-info .tabs a:hover{opacity:1}.hero.is-info .tabs li.is-active a{opacity:1}.hero.is-info .tabs.is-boxed a,.hero.is-info .tabs.is-toggle a{color:#fff}.hero.is-info .tabs.is-boxed a:hover,.hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-info .tabs.is-boxed li.is-active a,.hero.is-info .tabs.is-boxed li.is-active a:hover,.hero.is-info .tabs.is-toggle li.is-active a,.hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#209cee}.hero.is-info.is-bold{background-image:linear-gradient(141deg,#04a6d7 0,#209cee 71%,#3287f5 100%)}@media screen and (max-width:768px){.hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg,#04a6d7 0,#209cee 71%,#3287f5 100%)}}.hero.is-success{background-color:#23d160;color:#fff}.hero.is-success a:not(.button):not(.dropdown-item):not(.tag),.hero.is-success strong{color:inherit}.hero.is-success .title{color:#fff}.hero.is-success .subtitle{color:rgba(255,255,255,.9)}.hero.is-success .subtitle a:not(.button),.hero.is-success .subtitle strong{color:#fff}@media screen and (max-width:1087px){.hero.is-success .navbar-menu{background-color:#23d160}}.hero.is-success .navbar-item,.hero.is-success .navbar-link{color:rgba(255,255,255,.7)}.hero.is-success .navbar-link.is-active,.hero.is-success .navbar-link:hover,.hero.is-success a.navbar-item.is-active,.hero.is-success a.navbar-item:hover{background-color:#20bc56;color:#fff}.hero.is-success .tabs a{color:#fff;opacity:.9}.hero.is-success .tabs a:hover{opacity:1}.hero.is-success .tabs li.is-active a{opacity:1}.hero.is-success .tabs.is-boxed a,.hero.is-success .tabs.is-toggle a{color:#fff}.hero.is-success .tabs.is-boxed a:hover,.hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-success .tabs.is-boxed li.is-active a,.hero.is-success .tabs.is-boxed li.is-active a:hover,.hero.is-success .tabs.is-toggle li.is-active a,.hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#23d160}.hero.is-success.is-bold{background-image:linear-gradient(141deg,#12af2f 0,#23d160 71%,#2ce28a 100%)}@media screen and (max-width:768px){.hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg,#12af2f 0,#23d160 71%,#2ce28a 100%)}}.hero.is-warning{background-color:#ffdd57;color:rgba(0,0,0,.7)}.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag),.hero.is-warning strong{color:inherit}.hero.is-warning .title{color:rgba(0,0,0,.7)}.hero.is-warning .subtitle{color:rgba(0,0,0,.9)}.hero.is-warning .subtitle a:not(.button),.hero.is-warning .subtitle strong{color:rgba(0,0,0,.7)}@media screen and (max-width:1087px){.hero.is-warning .navbar-menu{background-color:#ffdd57}}.hero.is-warning .navbar-item,.hero.is-warning .navbar-link{color:rgba(0,0,0,.7)}.hero.is-warning .navbar-link.is-active,.hero.is-warning .navbar-link:hover,.hero.is-warning a.navbar-item.is-active,.hero.is-warning a.navbar-item:hover{background-color:#ffd83d;color:rgba(0,0,0,.7)}.hero.is-warning .tabs a{color:rgba(0,0,0,.7);opacity:.9}.hero.is-warning .tabs a:hover{opacity:1}.hero.is-warning .tabs li.is-active a{opacity:1}.hero.is-warning .tabs.is-boxed a,.hero.is-warning .tabs.is-toggle a{color:rgba(0,0,0,.7)}.hero.is-warning .tabs.is-boxed a:hover,.hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-warning .tabs.is-boxed li.is-active a,.hero.is-warning .tabs.is-boxed li.is-active a:hover,.hero.is-warning .tabs.is-toggle li.is-active a,.hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,.7);border-color:rgba(0,0,0,.7);color:#ffdd57}.hero.is-warning.is-bold{background-image:linear-gradient(141deg,#ffaf24 0,#ffdd57 71%,#fffa70 100%)}@media screen and (max-width:768px){.hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg,#ffaf24 0,#ffdd57 71%,#fffa70 100%)}}.hero.is-danger{background-color:#ff3860;color:#fff}.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag),.hero.is-danger strong{color:inherit}.hero.is-danger .title{color:#fff}.hero.is-danger .subtitle{color:rgba(255,255,255,.9)}.hero.is-danger .subtitle a:not(.button),.hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width:1087px){.hero.is-danger .navbar-menu{background-color:#ff3860}}.hero.is-danger .navbar-item,.hero.is-danger .navbar-link{color:rgba(255,255,255,.7)}.hero.is-danger .navbar-link.is-active,.hero.is-danger .navbar-link:hover,.hero.is-danger a.navbar-item.is-active,.hero.is-danger a.navbar-item:hover{background-color:#ff1f4b;color:#fff}.hero.is-danger .tabs a{color:#fff;opacity:.9}.hero.is-danger .tabs a:hover{opacity:1}.hero.is-danger .tabs li.is-active a{opacity:1}.hero.is-danger .tabs.is-boxed a,.hero.is-danger .tabs.is-toggle a{color:#fff}.hero.is-danger .tabs.is-boxed a:hover,.hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-danger .tabs.is-boxed li.is-active a,.hero.is-danger .tabs.is-boxed li.is-active a:hover,.hero.is-danger .tabs.is-toggle li.is-active a,.hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#ff3860}.hero.is-danger.is-bold{background-image:linear-gradient(141deg,#ff0561 0,#ff3860 71%,#ff5257 100%)}@media screen and (max-width:768px){.hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg,#ff0561 0,#ff3860 71%,#ff5257 100%)}}.hero.is-small .hero-body{padding-bottom:1.5rem;padding-top:1.5rem}@media screen and (min-width:769px),print{.hero.is-medium .hero-body{padding-bottom:9rem;padding-top:9rem}}@media screen and (min-width:769px),print{.hero.is-large .hero-body{padding-bottom:18rem;padding-top:18rem}}.hero.is-fullheight .hero-body,.hero.is-halfheight .hero-body{align-items:center;display:flex}.hero.is-fullheight .hero-body>.container,.hero.is-halfheight .hero-body>.container{flex-grow:1;flex-shrink:1}.hero.is-halfheight{min-height:50vh}.hero.is-fullheight{min-height:100vh}.hero-video{overflow:hidden}.hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.hero-video.is-transparent{opacity:.3}@media screen and (max-width:768px){.hero-video{display:none}}.hero-buttons{margin-top:1.5rem}@media screen and (max-width:768px){.hero-buttons .button{display:flex}.hero-buttons .button:not(:last-child){margin-bottom:.75rem}}@media screen and (min-width:769px),print{.hero-buttons{display:flex;justify-content:center}.hero-buttons .button:not(:last-child){margin-right:1.5rem}}.hero-foot,.hero-head{flex-grow:0;flex-shrink:0}.hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}.section{padding:3rem 1.5rem}@media screen and (min-width:1088px){.section.is-medium{padding:9rem 1.5rem}.section.is-large{padding:18rem 1.5rem}}.footer{background-color:#fafafa;padding:3rem 1.5rem 6rem} \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/images/1.png b/SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/images/1.png new file mode 100644 index 0000000000000000000000000000000000000000..4bb428a7936203ba2187d78e090c71674a63652c GIT binary patch literal 38997 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 literal 0 HcmV?d00001 diff --git a/SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/images/2.png b/SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/images/2.png new file mode 100644 index 0000000000000000000000000000000000000000..a01a53ad67ca48284c8b9d5c234126a6dc4a5bbd GIT binary patch literal 16049 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 literal 0 HcmV?d00001 diff --git a/SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/start.html b/SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/start.html new file mode 100644 index 00000000..9b883d4c --- /dev/null +++ b/SpotifyAPI.Web.Auth/Resources/AuthorizationCodeAuth/start.html @@ -0,0 +1,77 @@ + + + + + + + + + + + +
+
+

Spotify Authentication

+
+
+

Introduction

+ +
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/Resources/ImplicitGrantAuth/index.html b/SpotifyAPI.Web.Auth/Resources/ImplicitGrantAuth/index.html new file mode 100644 index 00000000..6197f88c --- /dev/null +++ b/SpotifyAPI.Web.Auth/Resources/ImplicitGrantAuth/index.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/SpotifyAPI.Web.Auth.csproj b/SpotifyAPI.Web.Auth/SpotifyAPI.Web.Auth.csproj new file mode 100644 index 00000000..74dea624 --- /dev/null +++ b/SpotifyAPI.Web.Auth/SpotifyAPI.Web.Auth.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + + diff --git a/SpotifyAPI.Web.Auth/SpotifyAuthServer.cs b/SpotifyAPI.Web.Auth/SpotifyAuthServer.cs new file mode 100644 index 00000000..9b7d6199 --- /dev/null +++ b/SpotifyAPI.Web.Auth/SpotifyAuthServer.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using SpotifyAPI.Web.Enums; +using Unosquare.Labs.EmbedIO; +using Unosquare.Labs.EmbedIO.Modules; + +namespace SpotifyAPI.Web.Auth +{ + public abstract class SpotifyAuthServer + { + public string ClientId { get; set; } + public string ServerUri { get; set; } + public string RedirectUri { get; set; } + public string State { get; set; } + public Scope Scope { get; set; } + public bool ShowDialog { get; set; } + + private readonly string _folder; + private readonly string _type; + protected CancellationTokenSource _serverSource; + + public delegate void OnAuthReceived(object sender, T payload); + public event OnAuthReceived AuthReceived; + + internal static readonly Dictionary> Instances = new Dictionary>(); + + internal SpotifyAuthServer(string type, string folder, string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") + { + _type = type; + _folder = folder; + ServerUri = serverUri; + RedirectUri = redirectUri; + Scope = scope; + State = string.IsNullOrEmpty(state) ? string.Join("", Guid.NewGuid().ToString("n").Take(8)) : state; + } + + public void Start() + { + Instances.Add(State, this); + _serverSource = new CancellationTokenSource(); + WebServer server = AdaptWebServer(WebServer.Create(ServerUri)); + server.RegisterModule(new ResourceFilesModule(typeof(ImplictGrantAuth).Assembly, $"SpotifyAPI.Web.Auth.Resources.{_folder}")); +#pragma warning disable 4014 + server.RunAsync(_serverSource.Token); +#pragma warning restore 4014 + } + + public virtual string GetUri() + { + StringBuilder builder = new StringBuilder("https://accounts.spotify.com/authorize/?"); + builder.Append("client_id=" + ClientId); + builder.Append($"&response_type={_type}"); + builder.Append("&redirect_uri=" + RedirectUri); + builder.Append("&state=" + State); + builder.Append("&scope=" + Scope.GetStringAttribute(" ")); + builder.Append("&show_dialog=" + ShowDialog); + return Uri.EscapeUriString(builder.ToString()); + } + + public void Stop(int delay = 2000) + { + if (_serverSource == null) return; + _serverSource.CancelAfter(delay); + Instances.Remove(State); + } + + public void OpenBrowser() + { + string uri = GetUri(); + AuthUtil.OpenBrowser(uri); + } + + internal void TriggerAuth(T payload) + { + AuthReceived?.Invoke(this, payload); + } + + internal static SpotifyAuthServer GetByState(string state) + { + return Instances.TryGetValue(state, out SpotifyAuthServer auth) ? auth : null; + } + + protected abstract WebServer AdaptWebServer(WebServer webServer); + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Example/Program.cs b/SpotifyAPI.Web.Example/Program.cs new file mode 100644 index 00000000..ece744d9 --- /dev/null +++ b/SpotifyAPI.Web.Example/Program.cs @@ -0,0 +1,74 @@ +using System; +using System.Threading.Tasks; +using SpotifyAPI.Web.Auth; +using SpotifyAPI.Web.Enums; +using SpotifyAPI.Web.Models; + +namespace SpotifyAPI.Web.Example +{ + static class Program + { + private static string _clientId = ""; //""; + private static string _secretId = ""; //""; + + static void Main(string[] args) + { + _clientId = string.IsNullOrEmpty(_clientId) + ? System.Environment.GetEnvironmentVariable("SPOTIFY_CLIENT_ID") + : _clientId; + + _secretId = string.IsNullOrEmpty(_secretId) + ? System.Environment.GetEnvironmentVariable("SPOTIFY_SECRET_ID") + : _secretId; + + Console.WriteLine("####### Spotify API Example #######"); + Console.WriteLine("This example uses AuthorizationCodeAuth."); + Console.WriteLine( + "Tip: If you want to supply your ClientID and SecretId beforehand, use env variables (SPOTIFY_CLIENT_ID and SPOTIFY_SECRET_ID)"); + + + AuthorizationCodeAuth auth = + new AuthorizationCodeAuth(_clientId, _secretId, "http://localhost:4002", "http://localhost:4002", + Scope.PlaylistReadPrivate | Scope.PlaylistReadCollaborative); + auth.AuthReceived += AuthOnAuthReceived; + auth.Start(); + auth.OpenBrowser(); + + Console.ReadLine(); + } + + private static async void AuthOnAuthReceived(object sender, AuthorizationCode payload) + { + AuthorizationCodeAuth auth = (AuthorizationCodeAuth) sender; + auth.Stop(); + + Token token = await auth.ExchangeCode(payload.Code); + SpotifyWebAPI api = new SpotifyWebAPI() + { + AccessToken = token.AccessToken, + TokenType = token.TokenType + }; + PrintUsefulDate(api); + } + + private static async void PrintUsefulDate(SpotifyWebAPI api) + { + PrivateProfile profile = await api.GetPrivateProfileAsync(); + string name = string.IsNullOrEmpty(profile.DisplayName) ? profile.Id : profile.DisplayName; + Console.WriteLine($"Hello there, {name}!"); + + Console.WriteLine("Your playlists:"); + Paging playlists = await api.GetUserPlaylistsAsync(profile.Id); + do + { + playlists.Items.ForEach(playlist => + { + Console.WriteLine($"- {playlist.Name}"); + }); + playlists = await api.GetNextPageAsync(playlists); + } while (playlists.HasNextPage()); + + + } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Example/SpotifyAPI.Web.Example.csproj b/SpotifyAPI.Web.Example/SpotifyAPI.Web.Example.csproj new file mode 100644 index 00000000..84fe660e --- /dev/null +++ b/SpotifyAPI.Web.Example/SpotifyAPI.Web.Example.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp2.0 + latest + + + + + + + + diff --git a/SpotifyAPI.Web.Example/SpotifyAPI.Web.Example.csproj.DotSettings b/SpotifyAPI.Web.Example/SpotifyAPI.Web.Example.csproj.DotSettings new file mode 100644 index 00000000..58ad6c88 --- /dev/null +++ b/SpotifyAPI.Web.Example/SpotifyAPI.Web.Example.csproj.DotSettings @@ -0,0 +1,2 @@ + + CSharp71 \ No newline at end of file diff --git a/SpotifyAPI.Tests/ProxyConfigTest.cs b/SpotifyAPI.Web.Tests/ProxyConfigTest.cs similarity index 99% rename from SpotifyAPI.Tests/ProxyConfigTest.cs rename to SpotifyAPI.Web.Tests/ProxyConfigTest.cs index d4b20b01..bc32e046 100644 --- a/SpotifyAPI.Tests/ProxyConfigTest.cs +++ b/SpotifyAPI.Web.Tests/ProxyConfigTest.cs @@ -1,7 +1,7 @@ using System; using NUnit.Framework; -namespace SpotifyAPI.Tests +namespace SpotifyAPI.Web.Tests { [TestFixture] public class ProxyConfigTest diff --git a/SpotifyAPI.Web.Tests/SpotifyAPI.Web.Tests.csproj b/SpotifyAPI.Web.Tests/SpotifyAPI.Web.Tests.csproj new file mode 100644 index 00000000..c0827cd8 --- /dev/null +++ b/SpotifyAPI.Web.Tests/SpotifyAPI.Web.Tests.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp2.0 + + false + + + + + + + + + + + + + + + diff --git a/SpotifyAPI.Tests/SpotifyWebAPITest.cs b/SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs similarity index 95% rename from SpotifyAPI.Tests/SpotifyWebAPITest.cs rename to SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs index a07c585b..8d4181af 100644 --- a/SpotifyAPI.Tests/SpotifyWebAPITest.cs +++ b/SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs @@ -1,19 +1,18 @@ -using Moq; -using Newtonsoft.Json; -using NUnit.Framework; -using SpotifyAPI.Web; -using SpotifyAPI.Web.Models; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; +using Moq; +using Newtonsoft.Json; +using NUnit.Framework; +using SpotifyAPI.Web.Models; -namespace SpotifyAPI.Tests +namespace SpotifyAPI.Web.Tests { [TestFixture] public class SpotifyWebAPITest { - private static readonly string FixtureDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../fixtures/"); + private static readonly string FixtureDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../fixtures/"); private Mock _mock; private SpotifyWebAPI _spotify; diff --git a/SpotifyAPI.Tests/UtilTest.cs b/SpotifyAPI.Web.Tests/UtilTest.cs similarity index 88% rename from SpotifyAPI.Tests/UtilTest.cs rename to SpotifyAPI.Web.Tests/UtilTest.cs index c78c14ae..67c243d1 100644 --- a/SpotifyAPI.Tests/UtilTest.cs +++ b/SpotifyAPI.Web.Tests/UtilTest.cs @@ -1,8 +1,7 @@ using System; using NUnit.Framework; -using SpotifyAPI.Web; -namespace SpotifyAPI.Tests +namespace SpotifyAPI.Web.Tests { [TestFixture] public class UtilTest diff --git a/SpotifyAPI.Tests/fixtures/private-user.json b/SpotifyAPI.Web.Tests/fixtures/private-user.json similarity index 100% rename from SpotifyAPI.Tests/fixtures/private-user.json rename to SpotifyAPI.Web.Tests/fixtures/private-user.json diff --git a/SpotifyAPI.Tests/fixtures/public-user.json b/SpotifyAPI.Web.Tests/fixtures/public-user.json similarity index 100% rename from SpotifyAPI.Tests/fixtures/public-user.json rename to SpotifyAPI.Web.Tests/fixtures/public-user.json diff --git a/SpotifyAPI/Web/Enums/AlbumType.cs b/SpotifyAPI.Web/Enums/AlbumType.cs similarity index 100% rename from SpotifyAPI/Web/Enums/AlbumType.cs rename to SpotifyAPI.Web/Enums/AlbumType.cs diff --git a/SpotifyAPI/Web/Enums/FollowType.cs b/SpotifyAPI.Web/Enums/FollowType.cs similarity index 100% rename from SpotifyAPI/Web/Enums/FollowType.cs rename to SpotifyAPI.Web/Enums/FollowType.cs diff --git a/SpotifyAPI/Web/Enums/RepeatState.cs b/SpotifyAPI.Web/Enums/RepeatState.cs similarity index 100% rename from SpotifyAPI/Web/Enums/RepeatState.cs rename to SpotifyAPI.Web/Enums/RepeatState.cs diff --git a/SpotifyAPI/Web/Enums/Scope.cs b/SpotifyAPI.Web/Enums/Scope.cs similarity index 100% rename from SpotifyAPI/Web/Enums/Scope.cs rename to SpotifyAPI.Web/Enums/Scope.cs diff --git a/SpotifyAPI/Web/Enums/SearchType.cs b/SpotifyAPI.Web/Enums/SearchType.cs similarity index 100% rename from SpotifyAPI/Web/Enums/SearchType.cs rename to SpotifyAPI.Web/Enums/SearchType.cs diff --git a/SpotifyAPI/Web/Enums/TimeRangeType.cs b/SpotifyAPI.Web/Enums/TimeRangeType.cs similarity index 100% rename from SpotifyAPI/Web/Enums/TimeRangeType.cs rename to SpotifyAPI.Web/Enums/TimeRangeType.cs diff --git a/SpotifyAPI/Web/IClient.cs b/SpotifyAPI.Web/IClient.cs similarity index 99% rename from SpotifyAPI/Web/IClient.cs rename to SpotifyAPI.Web/IClient.cs index 1fcef62e..c0960a63 100644 --- a/SpotifyAPI/Web/IClient.cs +++ b/SpotifyAPI.Web/IClient.cs @@ -1,7 +1,6 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; -using System.Net.Http.Headers; using System.Threading.Tasks; using SpotifyAPI.Web.Models; diff --git a/SpotifyAPI/Web/Models/AnalysisMeta.cs b/SpotifyAPI.Web/Models/AnalysisMeta.cs similarity index 100% rename from SpotifyAPI/Web/Models/AnalysisMeta.cs rename to SpotifyAPI.Web/Models/AnalysisMeta.cs diff --git a/SpotifyAPI/Web/Models/AnalysisSection.cs b/SpotifyAPI.Web/Models/AnalysisSection.cs similarity index 100% rename from SpotifyAPI/Web/Models/AnalysisSection.cs rename to SpotifyAPI.Web/Models/AnalysisSection.cs diff --git a/SpotifyAPI/Web/Models/AnalysisSegment.cs b/SpotifyAPI.Web/Models/AnalysisSegment.cs similarity index 100% rename from SpotifyAPI/Web/Models/AnalysisSegment.cs rename to SpotifyAPI.Web/Models/AnalysisSegment.cs diff --git a/SpotifyAPI/Web/Models/AnalysisTimeSlice.cs b/SpotifyAPI.Web/Models/AnalysisTimeSlice.cs similarity index 100% rename from SpotifyAPI/Web/Models/AnalysisTimeSlice.cs rename to SpotifyAPI.Web/Models/AnalysisTimeSlice.cs diff --git a/SpotifyAPI/Web/Models/AnalysisTrack.cs b/SpotifyAPI.Web/Models/AnalysisTrack.cs similarity index 100% rename from SpotifyAPI/Web/Models/AnalysisTrack.cs rename to SpotifyAPI.Web/Models/AnalysisTrack.cs diff --git a/SpotifyAPI/Web/Models/ArrayResponse.cs b/SpotifyAPI.Web/Models/ArrayResponse.cs similarity index 100% rename from SpotifyAPI/Web/Models/ArrayResponse.cs rename to SpotifyAPI.Web/Models/ArrayResponse.cs diff --git a/SpotifyAPI/Web/Models/AudioAnalysis.cs b/SpotifyAPI.Web/Models/AudioAnalysis.cs similarity index 100% rename from SpotifyAPI/Web/Models/AudioAnalysis.cs rename to SpotifyAPI.Web/Models/AudioAnalysis.cs diff --git a/SpotifyAPI/Web/Models/AudioFeatures.cs b/SpotifyAPI.Web/Models/AudioFeatures.cs similarity index 100% rename from SpotifyAPI/Web/Models/AudioFeatures.cs rename to SpotifyAPI.Web/Models/AudioFeatures.cs diff --git a/SpotifyAPI/Web/Models/AvailabeDevices.cs b/SpotifyAPI.Web/Models/AvailabeDevices.cs similarity index 100% rename from SpotifyAPI/Web/Models/AvailabeDevices.cs rename to SpotifyAPI.Web/Models/AvailabeDevices.cs diff --git a/SpotifyAPI/Web/Models/BasicModel.cs b/SpotifyAPI.Web/Models/BasicModel.cs similarity index 100% rename from SpotifyAPI/Web/Models/BasicModel.cs rename to SpotifyAPI.Web/Models/BasicModel.cs diff --git a/SpotifyAPI/Web/Models/Category.cs b/SpotifyAPI.Web/Models/Category.cs similarity index 100% rename from SpotifyAPI/Web/Models/Category.cs rename to SpotifyAPI.Web/Models/Category.cs diff --git a/SpotifyAPI/Web/Models/CategoryList.cs b/SpotifyAPI.Web/Models/CategoryList.cs similarity index 100% rename from SpotifyAPI/Web/Models/CategoryList.cs rename to SpotifyAPI.Web/Models/CategoryList.cs diff --git a/SpotifyAPI/Web/Models/CategoryPlaylist.cs b/SpotifyAPI.Web/Models/CategoryPlaylist.cs similarity index 100% rename from SpotifyAPI/Web/Models/CategoryPlaylist.cs rename to SpotifyAPI.Web/Models/CategoryPlaylist.cs diff --git a/SpotifyAPI/Web/Models/CursorPaging.cs b/SpotifyAPI.Web/Models/CursorPaging.cs similarity index 100% rename from SpotifyAPI/Web/Models/CursorPaging.cs rename to SpotifyAPI.Web/Models/CursorPaging.cs diff --git a/SpotifyAPI/Web/Models/Device.cs b/SpotifyAPI.Web/Models/Device.cs similarity index 100% rename from SpotifyAPI/Web/Models/Device.cs rename to SpotifyAPI.Web/Models/Device.cs diff --git a/SpotifyAPI/Web/Models/FeaturedPlaylists.cs b/SpotifyAPI.Web/Models/FeaturedPlaylists.cs similarity index 100% rename from SpotifyAPI/Web/Models/FeaturedPlaylists.cs rename to SpotifyAPI.Web/Models/FeaturedPlaylists.cs diff --git a/SpotifyAPI/Web/Models/FollowedArtists.cs b/SpotifyAPI.Web/Models/FollowedArtists.cs similarity index 100% rename from SpotifyAPI/Web/Models/FollowedArtists.cs rename to SpotifyAPI.Web/Models/FollowedArtists.cs diff --git a/SpotifyAPI/Web/Models/FullAlbum.cs b/SpotifyAPI.Web/Models/FullAlbum.cs similarity index 100% rename from SpotifyAPI/Web/Models/FullAlbum.cs rename to SpotifyAPI.Web/Models/FullAlbum.cs diff --git a/SpotifyAPI/Web/Models/FullArtist.cs b/SpotifyAPI.Web/Models/FullArtist.cs similarity index 100% rename from SpotifyAPI/Web/Models/FullArtist.cs rename to SpotifyAPI.Web/Models/FullArtist.cs diff --git a/SpotifyAPI/Web/Models/FullPlaylist.cs b/SpotifyAPI.Web/Models/FullPlaylist.cs similarity index 100% rename from SpotifyAPI/Web/Models/FullPlaylist.cs rename to SpotifyAPI.Web/Models/FullPlaylist.cs diff --git a/SpotifyAPI/Web/Models/FullTrack.cs b/SpotifyAPI.Web/Models/FullTrack.cs similarity index 100% rename from SpotifyAPI/Web/Models/FullTrack.cs rename to SpotifyAPI.Web/Models/FullTrack.cs diff --git a/SpotifyAPI/Web/Models/GeneralModels.cs b/SpotifyAPI.Web/Models/GeneralModels.cs similarity index 100% rename from SpotifyAPI/Web/Models/GeneralModels.cs rename to SpotifyAPI.Web/Models/GeneralModels.cs diff --git a/SpotifyAPI/Web/Models/NewAlbumReleases.cs b/SpotifyAPI.Web/Models/NewAlbumReleases.cs similarity index 100% rename from SpotifyAPI/Web/Models/NewAlbumReleases.cs rename to SpotifyAPI.Web/Models/NewAlbumReleases.cs diff --git a/SpotifyAPI/Web/Models/Paging.cs b/SpotifyAPI.Web/Models/Paging.cs similarity index 100% rename from SpotifyAPI/Web/Models/Paging.cs rename to SpotifyAPI.Web/Models/Paging.cs diff --git a/SpotifyAPI/Web/Models/PlayHistory.cs b/SpotifyAPI.Web/Models/PlayHistory.cs similarity index 100% rename from SpotifyAPI/Web/Models/PlayHistory.cs rename to SpotifyAPI.Web/Models/PlayHistory.cs diff --git a/SpotifyAPI/Web/Models/PlaybackContext.cs b/SpotifyAPI.Web/Models/PlaybackContext.cs similarity index 100% rename from SpotifyAPI/Web/Models/PlaybackContext.cs rename to SpotifyAPI.Web/Models/PlaybackContext.cs diff --git a/SpotifyAPI/Web/Models/PrivateProfile.cs b/SpotifyAPI.Web/Models/PrivateProfile.cs similarity index 100% rename from SpotifyAPI/Web/Models/PrivateProfile.cs rename to SpotifyAPI.Web/Models/PrivateProfile.cs diff --git a/SpotifyAPI/Web/Models/PublicProfile.cs b/SpotifyAPI.Web/Models/PublicProfile.cs similarity index 100% rename from SpotifyAPI/Web/Models/PublicProfile.cs rename to SpotifyAPI.Web/Models/PublicProfile.cs diff --git a/SpotifyAPI/Web/Models/RecommendationSeed .cs b/SpotifyAPI.Web/Models/RecommendationSeed .cs similarity index 100% rename from SpotifyAPI/Web/Models/RecommendationSeed .cs rename to SpotifyAPI.Web/Models/RecommendationSeed .cs diff --git a/SpotifyAPI/Web/Models/RecommendationSeedGenres.cs b/SpotifyAPI.Web/Models/RecommendationSeedGenres.cs similarity index 100% rename from SpotifyAPI/Web/Models/RecommendationSeedGenres.cs rename to SpotifyAPI.Web/Models/RecommendationSeedGenres.cs diff --git a/SpotifyAPI/Web/Models/Recommendations.cs b/SpotifyAPI.Web/Models/Recommendations.cs similarity index 100% rename from SpotifyAPI/Web/Models/Recommendations.cs rename to SpotifyAPI.Web/Models/Recommendations.cs diff --git a/SpotifyAPI/Web/Models/ResponseInfo.cs b/SpotifyAPI.Web/Models/ResponseInfo.cs similarity index 100% rename from SpotifyAPI/Web/Models/ResponseInfo.cs rename to SpotifyAPI.Web/Models/ResponseInfo.cs diff --git a/SpotifyAPI/Web/Models/SearchItem.cs b/SpotifyAPI.Web/Models/SearchItem.cs similarity index 100% rename from SpotifyAPI/Web/Models/SearchItem.cs rename to SpotifyAPI.Web/Models/SearchItem.cs diff --git a/SpotifyAPI/Web/Models/SeveralAlbums.cs b/SpotifyAPI.Web/Models/SeveralAlbums.cs similarity index 100% rename from SpotifyAPI/Web/Models/SeveralAlbums.cs rename to SpotifyAPI.Web/Models/SeveralAlbums.cs diff --git a/SpotifyAPI/Web/Models/SeveralArtists.cs b/SpotifyAPI.Web/Models/SeveralArtists.cs similarity index 100% rename from SpotifyAPI/Web/Models/SeveralArtists.cs rename to SpotifyAPI.Web/Models/SeveralArtists.cs diff --git a/SpotifyAPI/Web/Models/SeveralAudioFeatures.cs b/SpotifyAPI.Web/Models/SeveralAudioFeatures.cs similarity index 100% rename from SpotifyAPI/Web/Models/SeveralAudioFeatures.cs rename to SpotifyAPI.Web/Models/SeveralAudioFeatures.cs diff --git a/SpotifyAPI/Web/Models/SeveralTracks.cs b/SpotifyAPI.Web/Models/SeveralTracks.cs similarity index 100% rename from SpotifyAPI/Web/Models/SeveralTracks.cs rename to SpotifyAPI.Web/Models/SeveralTracks.cs diff --git a/SpotifyAPI/Web/Models/SimpleAlbum.cs b/SpotifyAPI.Web/Models/SimpleAlbum.cs similarity index 100% rename from SpotifyAPI/Web/Models/SimpleAlbum.cs rename to SpotifyAPI.Web/Models/SimpleAlbum.cs diff --git a/SpotifyAPI/Web/Models/SimpleArtist.cs b/SpotifyAPI.Web/Models/SimpleArtist.cs similarity index 100% rename from SpotifyAPI/Web/Models/SimpleArtist.cs rename to SpotifyAPI.Web/Models/SimpleArtist.cs diff --git a/SpotifyAPI/Web/Models/SimplePlaylist.cs b/SpotifyAPI.Web/Models/SimplePlaylist.cs similarity index 100% rename from SpotifyAPI/Web/Models/SimplePlaylist.cs rename to SpotifyAPI.Web/Models/SimplePlaylist.cs diff --git a/SpotifyAPI/Web/Models/SimpleTrack.cs b/SpotifyAPI.Web/Models/SimpleTrack.cs similarity index 100% rename from SpotifyAPI/Web/Models/SimpleTrack.cs rename to SpotifyAPI.Web/Models/SimpleTrack.cs diff --git a/SpotifyAPI/Web/Models/Snapshot.cs b/SpotifyAPI.Web/Models/Snapshot.cs similarity index 100% rename from SpotifyAPI/Web/Models/Snapshot.cs rename to SpotifyAPI.Web/Models/Snapshot.cs diff --git a/SpotifyAPI/Web/Models/Token.cs b/SpotifyAPI.Web/Models/Token.cs similarity index 85% rename from SpotifyAPI/Web/Models/Token.cs rename to SpotifyAPI.Web/Models/Token.cs index d6c79d49..941d6f95 100644 --- a/SpotifyAPI/Web/Models/Token.cs +++ b/SpotifyAPI.Web/Models/Token.cs @@ -17,7 +17,7 @@ namespace SpotifyAPI.Web.Models public string TokenType { get; set; } [JsonProperty("expires_in")] - public int ExpiresIn { get; set; } + public double ExpiresIn { get; set; } [JsonProperty("refresh_token")] public string RefreshToken { get; set; } @@ -34,9 +34,14 @@ namespace SpotifyAPI.Web.Models /// Checks if the token has expired /// /// - public Boolean IsExpired() + public bool IsExpired() { return CreateDate.Add(TimeSpan.FromSeconds(ExpiresIn)) <= DateTime.Now; } + + public bool HasError() + { + return Error != null; + } } } \ No newline at end of file diff --git a/SpotifyAPI/Web/Models/TuneableTrack.cs b/SpotifyAPI.Web/Models/TuneableTrack.cs similarity index 100% rename from SpotifyAPI/Web/Models/TuneableTrack.cs rename to SpotifyAPI.Web/Models/TuneableTrack.cs diff --git a/SpotifyAPI/ProxyConfig.cs b/SpotifyAPI.Web/ProxyConfig.cs similarity index 100% rename from SpotifyAPI/ProxyConfig.cs rename to SpotifyAPI.Web/ProxyConfig.cs diff --git a/SpotifyAPI.Web/SpotifyAPI.Web.csproj b/SpotifyAPI.Web/SpotifyAPI.Web.csproj new file mode 100644 index 00000000..afada826 --- /dev/null +++ b/SpotifyAPI.Web/SpotifyAPI.Web.csproj @@ -0,0 +1,11 @@ + + + + netstandard2.0 + + + + + + + diff --git a/SpotifyAPI/Web/SpotifyWebAPI.cs b/SpotifyAPI.Web/SpotifyWebAPI.cs similarity index 99% rename from SpotifyAPI/Web/SpotifyWebAPI.cs rename to SpotifyAPI.Web/SpotifyWebAPI.cs index 6704803c..90f26e49 100644 --- a/SpotifyAPI/Web/SpotifyWebAPI.cs +++ b/SpotifyAPI.Web/SpotifyWebAPI.cs @@ -4,9 +4,7 @@ using SpotifyAPI.Web.Enums; using SpotifyAPI.Web.Models; using System; using System.Collections.Generic; -using System.Dynamic; using System.Linq; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -15,9 +13,6 @@ namespace SpotifyAPI.Web // ReSharper disable once InconsistentNaming public sealed class SpotifyWebAPI : IDisposable { - [Obsolete("This Property will be removed soon. Please use SpotifyWebBuilder.APIBase")] - public const string APIBase = SpotifyWebBuilder.APIBase; - private readonly SpotifyWebBuilder _builder; public SpotifyWebAPI() : this(null) diff --git a/SpotifyAPI/Web/SpotifyWebBuilder.cs b/SpotifyAPI.Web/SpotifyWebBuilder.cs similarity index 100% rename from SpotifyAPI/Web/SpotifyWebBuilder.cs rename to SpotifyAPI.Web/SpotifyWebBuilder.cs diff --git a/SpotifyAPI/Web/SpotifyWebClient.cs b/SpotifyAPI.Web/SpotifyWebClient.cs similarity index 99% rename from SpotifyAPI/Web/SpotifyWebClient.cs rename to SpotifyAPI.Web/SpotifyWebClient.cs index 0cd4a647..3789aa50 100644 --- a/SpotifyAPI/Web/SpotifyWebClient.cs +++ b/SpotifyAPI.Web/SpotifyWebClient.cs @@ -1,8 +1,6 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; -using System.IO; -using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; diff --git a/SpotifyAPI/Web/Util.cs b/SpotifyAPI.Web/Util.cs similarity index 100% rename from SpotifyAPI/Web/Util.cs rename to SpotifyAPI.Web/Util.cs diff --git a/SpotifyAPI.sln b/SpotifyAPI.sln index 7d231038..30424096 100644 --- a/SpotifyAPI.sln +++ b/SpotifyAPI.sln @@ -1,13 +1,15 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2009 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifyAPI", "SpotifyAPI\SpotifyAPI.csproj", "{EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpotifyAPI.Web", "SpotifyAPI.Web\SpotifyAPI.Web.csproj", "{EC8A93BA-27C4-4642-B7A0-11B809C35BE4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifyAPI.Tests", "SpotifyAPI.Tests\SpotifyAPI.Tests.csproj", "{A06CE1BA-B2C4-4C3C-9E79-D2E8D36DDF0B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpotifyAPI.Web.Tests", "SpotifyAPI.Web.Tests\SpotifyAPI.Web.Tests.csproj", "{47FD780C-47B2-4634-9BB4-83C660101FAE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifyAPI.Example", "SpotifyAPI.Example\SpotifyAPI.Example.csproj", "{C8968A03-497E-4BAB-B492-5651AE7E0C06}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpotifyAPI.Web.Example", "SpotifyAPI.Web.Example\SpotifyAPI.Web.Example.csproj", "{8D1CCA36-C7C2-4A70-B194-B23D7E03F00A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifyAPI.Web.Auth", "SpotifyAPI.Web.Auth\SpotifyAPI.Web.Auth.csproj", "{400A3787-FDBE-4A4C-9DDD-AAEB3DCE1DF5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,20 +17,27 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}.Release|Any CPU.Build.0 = Release|Any CPU - {A06CE1BA-B2C4-4C3C-9E79-D2E8D36DDF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A06CE1BA-B2C4-4C3C-9E79-D2E8D36DDF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A06CE1BA-B2C4-4C3C-9E79-D2E8D36DDF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A06CE1BA-B2C4-4C3C-9E79-D2E8D36DDF0B}.Release|Any CPU.Build.0 = Release|Any CPU - {C8968A03-497E-4BAB-B492-5651AE7E0C06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C8968A03-497E-4BAB-B492-5651AE7E0C06}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C8968A03-497E-4BAB-B492-5651AE7E0C06}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C8968A03-497E-4BAB-B492-5651AE7E0C06}.Release|Any CPU.Build.0 = Release|Any CPU + {EC8A93BA-27C4-4642-B7A0-11B809C35BE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EC8A93BA-27C4-4642-B7A0-11B809C35BE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EC8A93BA-27C4-4642-B7A0-11B809C35BE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EC8A93BA-27C4-4642-B7A0-11B809C35BE4}.Release|Any CPU.Build.0 = Release|Any CPU + {47FD780C-47B2-4634-9BB4-83C660101FAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47FD780C-47B2-4634-9BB4-83C660101FAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47FD780C-47B2-4634-9BB4-83C660101FAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47FD780C-47B2-4634-9BB4-83C660101FAE}.Release|Any CPU.Build.0 = Release|Any CPU + {8D1CCA36-C7C2-4A70-B194-B23D7E03F00A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D1CCA36-C7C2-4A70-B194-B23D7E03F00A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D1CCA36-C7C2-4A70-B194-B23D7E03F00A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D1CCA36-C7C2-4A70-B194-B23D7E03F00A}.Release|Any CPU.Build.0 = Release|Any CPU + {400A3787-FDBE-4A4C-9DDD-AAEB3DCE1DF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {400A3787-FDBE-4A4C-9DDD-AAEB3DCE1DF5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {400A3787-FDBE-4A4C-9DDD-AAEB3DCE1DF5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {400A3787-FDBE-4A4C-9DDD-AAEB3DCE1DF5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {097062B8-0E87-43C8-BD98-61843A68BE6D} + EndGlobalSection EndGlobal diff --git a/SpotifyAPI/Local/Enums/AlbumArtSize.cs b/SpotifyAPI/Local/Enums/AlbumArtSize.cs deleted file mode 100644 index a475193e..00000000 --- a/SpotifyAPI/Local/Enums/AlbumArtSize.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace SpotifyAPI.Local.Enums -{ - public enum AlbumArtSize - { - Size160, - Size320, - Size640 - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/Enums/UriType.cs b/SpotifyAPI/Local/Enums/UriType.cs deleted file mode 100644 index c5170755..00000000 --- a/SpotifyAPI/Local/Enums/UriType.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace SpotifyAPI.Local.Enums -{ - public enum UriType - { - none, - track, - album, - artist, - playlist, - user - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/ExtendedWebClient.cs b/SpotifyAPI/Local/ExtendedWebClient.cs deleted file mode 100644 index e1ca9f85..00000000 --- a/SpotifyAPI/Local/ExtendedWebClient.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Net; -using System.Text; - -namespace SpotifyAPI.Local -{ - internal class ExtendedWebClient : WebClient - { - public int Timeout { get; set; } - - public ExtendedWebClient() - { - // TODO Remove once SSL Issues are resolved #115 - ServicePointManager.ServerCertificateValidationCallback = (s, certificate, chain, sslPolicyErrors) => true; - Encoding = Encoding.UTF8; - Timeout = 2000; - Headers.Add("Origin", "https://embed.spotify.com"); - Headers.Add("Referer", "https://embed.spotify.com/?uri=spotify:track:5Zp4SWOpbuOdnsxLqwgutt"); - } - - protected override WebRequest GetWebRequest(Uri address) - { - WebRequest webRequest = base.GetWebRequest(address); - if (webRequest != null) - webRequest.Timeout = Timeout; - return webRequest; - } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/LocalEvents.cs b/SpotifyAPI/Local/LocalEvents.cs deleted file mode 100644 index b0e16d62..00000000 --- a/SpotifyAPI/Local/LocalEvents.cs +++ /dev/null @@ -1,39 +0,0 @@ -using SpotifyAPI.Local.Models; -using System; - -namespace SpotifyAPI.Local -{ - /// - /// Event gets triggered, when the Track is changed - /// - public class TrackChangeEventArgs - { - public Track OldTrack { get; set; } - public Track NewTrack { get; set; } - } - - /// - /// Event gets triggered, when the Playin-state is changed (e.g Play --> Pause) - /// - public class PlayStateEventArgs - { - public Boolean Playing { get; set; } - } - - /// - /// Event gets triggered, when the volume changes - /// - public class VolumeChangeEventArgs - { - public double OldVolume { get; set; } - public double NewVolume { get; set; } - } - - /// - /// Event gets triggered, when the tracktime changes - /// - public class TrackTimeChangeEventArgs - { - public double TrackTime { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/Models/CFID.cs b/SpotifyAPI/Local/Models/CFID.cs deleted file mode 100644 index 001a21b2..00000000 --- a/SpotifyAPI/Local/Models/CFID.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace SpotifyAPI.Local.Models -{ - /// - /// JSON Response, used internaly - /// - internal class Cfid - { - public Error Error { get; set; } - public string Token { get; set; } - public string Version { get; set; } - public string ClientVersion { get; set; } - public Boolean Running { get; set; } - } - - /// - /// JSON Response, used internaly - /// - internal class Error - { - public string Type { get; set; } - public string Message { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/Models/OpenGraphState.cs b/SpotifyAPI/Local/Models/OpenGraphState.cs deleted file mode 100644 index 8f9df2b5..00000000 --- a/SpotifyAPI/Local/Models/OpenGraphState.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Newtonsoft.Json; -using System; - -namespace SpotifyAPI.Local.Models -{ - public class OpenGraphState - { - [JsonProperty("private_session")] - public Boolean PrivateSession { get; set; } - - [JsonProperty("posting_disabled")] - public Boolean PostingDisabled { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/Models/SpotifyResource.cs b/SpotifyAPI/Local/Models/SpotifyResource.cs deleted file mode 100644 index 1dd5afda..00000000 --- a/SpotifyAPI/Local/Models/SpotifyResource.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; -using System; - -namespace SpotifyAPI.Local.Models -{ - public class SpotifyResource - { - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("uri")] - public string Uri { get; set; } - - [JsonProperty("location")] - public TrackResourceLocation Location { get; set; } - - public SpotifyUri ParseUri() - { - return SpotifyUri.Parse(Uri); - } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/Models/SpotifyUri.cs b/SpotifyAPI/Local/Models/SpotifyUri.cs deleted file mode 100644 index 16bd9122..00000000 --- a/SpotifyAPI/Local/Models/SpotifyUri.cs +++ /dev/null @@ -1,60 +0,0 @@ -using SpotifyAPI.Local.Enums; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SpotifyAPI.Local.Models -{ - public class SpotifyUri - { - private readonly Dictionary _properties = new Dictionary(); - - public string Base { get; } - public UriType Type => _properties?.LastOrDefault().Key ?? UriType.none; - public string Id => _properties?.LastOrDefault().Value; - - public SpotifyUri(string uriBase, Dictionary properties) - { - Base = uriBase; - _properties = properties; - } - - public SpotifyUri(string uriBase, UriType uriType, string uriId) - { - Base = uriBase; - _properties.Add(uriType, uriId); - } - - public string GetUriPropValue(UriType type) - { - return !_properties.ContainsKey(type) ? null : _properties[type]; - } - - public static SpotifyUri Parse(string uri) - { - if (string.IsNullOrEmpty(uri)) - throw new ArgumentNullException("Uri"); - - string[] props = uri.Split(':'); - if (props.Length < 3 || !Enum.TryParse(props[1], out UriType uriType)) - throw new ArgumentException("Unexpected Uri"); - - Dictionary properties = new Dictionary { { uriType, props[2] } }; - - for (int index = 3; index < props.Length; index += 2) - { - if (Enum.TryParse(props[index], out UriType type)) - properties.Add(type, props[index + 1]); - } - - return new SpotifyUri(props[0], properties); - } - - public override string ToString() - { - return $"{Base}:{string.Join(":", _properties.SelectMany(x => new[] { x.Key.ToString(), x.Value }))}"; - } - } -} diff --git a/SpotifyAPI/Local/Models/StatusResponse.cs b/SpotifyAPI/Local/Models/StatusResponse.cs deleted file mode 100644 index f3af9a66..00000000 --- a/SpotifyAPI/Local/Models/StatusResponse.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Local.Models -{ - public class StatusResponse - { - [JsonProperty("version")] - public int Version { get; set; } - - [JsonProperty("client_version")] - public string ClientVersion { get; set; } - - [JsonProperty("playing")] - public bool Playing { get; set; } - - [JsonProperty("shuffle")] - public bool Shuffle { get; set; } - - [JsonProperty("repeat")] - public bool Repeat { get; set; } - - [JsonProperty("play_enabled")] - public bool PlayEnabled { get; set; } - - [JsonProperty("prev_enabled")] - public bool PrevEnabled { get; set; } - - [JsonProperty("next_enabled")] - public bool NextEnabled { get; set; } - - [JsonProperty("track")] - public Track Track { get; set; } - - [JsonProperty("playing_position")] - public double PlayingPosition { get; set; } - - [JsonProperty("server_time")] - public int ServerTime { get; set; } - - [JsonProperty("volume")] - public double Volume { get; set; } - - [JsonProperty("online")] - public bool Online { get; set; } - - [JsonProperty("open_graph_state")] - public OpenGraphState OpenGraphState { get; set; } - - [JsonProperty("running")] - public bool Running { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/Models/Track.cs b/SpotifyAPI/Local/Models/Track.cs deleted file mode 100755 index 2f489276..00000000 --- a/SpotifyAPI/Local/Models/Track.cs +++ /dev/null @@ -1,181 +0,0 @@ -using Newtonsoft.Json; -using SpotifyAPI.Local.Enums; -using System; -using System.Drawing; -using System.IO; -using System.Net; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace SpotifyAPI.Local.Models -{ - public class Track - { - [JsonProperty("track_resource")] - public SpotifyResource TrackResource { get; set; } - - [JsonProperty("artist_resource")] - public SpotifyResource ArtistResource { get; set; } - - [JsonProperty("album_resource")] - public SpotifyResource AlbumResource { get; set; } - - [JsonProperty("length")] - public int Length { get; set; } - - [JsonProperty("track_type")] - public string TrackType { get; set; } - - /// - /// Checks if the track is an advert - /// - /// true if the track is an advert, false otherwise - public bool IsAd() => TrackType == "ad" || Length == 0; - - /// - /// Checks if the track id of type "other" - /// - /// true if the track is neither an advert nor a normal track, for example a podcast - public bool IsOtherTrackType() - { - return TrackType == "other"; - } - - /// - /// Returns a URL to the album cover in the provided size - /// - /// AlbumArtSize (160,320,640) - /// Optional proxy settings - /// A String, which is the URL to the Albumart - public string GetAlbumArtUrl(AlbumArtSize size, ProxyConfig proxyConfig = null) - { - return GetAlbumArtUrl(size, proxyConfig?.CreateWebProxy()); - } - - private string GetAlbumArtUrl(AlbumArtSize size, IWebProxy proxy = null) - { - if (AlbumResource.Uri == null || !AlbumResource.Uri.Contains("spotify:album:") || AlbumResource.Uri.Contains("spotify:album:0000000000000000000000")) - return ""; - - int albumsize = 0; - switch (size) - { - case AlbumArtSize.Size160: - albumsize = 160; - break; - - case AlbumArtSize.Size320: - albumsize = 320; - break; - - case AlbumArtSize.Size640: - albumsize = 640; - break; - } - string raw; - using (WebClient wc = new WebClient()) - { - wc.Proxy = proxy; - wc.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"); - raw = wc.DownloadString("http://open.spotify.com/album/" + AlbumResource.Uri.Split(new[] { ":" }, StringSplitOptions.None)[2]); - } - raw = raw.Replace("\t", ""); - - // 0) - { - string content = matches[0].Groups[1].Value; - string[] l = content.Split(new[] { "/" }, StringSplitOptions.None); - return "http://o.scdn.co/" + albumsize + @"/" + l[4]; - } - } - return ""; - } - - /// - /// Returns a Bitmap of the album cover in the provided size asynchronous - /// - /// AlbumArtSize (160,320,640) - /// Optional proxy settings - /// A Bitmap, which is the albumart - public async Task GetAlbumArtAsync(AlbumArtSize size, ProxyConfig proxyConfig = null) - { - var data = await GetAlbumArtAsByteArrayAsync(size, proxyConfig).ConfigureAwait(false); - if (data != null) - { - using (MemoryStream ms = new MemoryStream(data)) - { - return (Bitmap)Image.FromStream(ms); - } - } - - return null; - } - - /// - /// Returns a byte[] of the the album cover in the provided size asynchronous - /// - /// AlbumArtSize (160,320,640) - /// Optional proxy settings - /// A byte[], which is the albumart in binary data - public Task GetAlbumArtAsByteArrayAsync(AlbumArtSize size, ProxyConfig proxyConfig = null) - { - using (WebClient wc = new WebClient()) - { - IWebProxy proxy = proxyConfig?.CreateWebProxy(); - wc.Proxy = proxy; - - string url = GetAlbumArtUrl(size, proxy); - if (url == "") - return null; - return wc.DownloadDataTaskAsync(url); - } - } - - /// - /// Returns a Bitmap of the album cover in the provided size - /// - /// AlbumArtSize (160,320,640) - /// Optional proxy settings - /// A Bitmap, which is the albumart - public Bitmap GetAlbumArt(AlbumArtSize size, ProxyConfig proxyConfig = null) - { - var data = GetAlbumArtAsByteArray(size, proxyConfig); - if (data != null) - { - using (MemoryStream ms = new MemoryStream(data)) - { - return (Bitmap)Image.FromStream(ms); - } - } - - return null; - } - - /// - /// Returns a byte[] of the album cover in the provided size - /// - /// AlbumArtSize (160,320,640) - /// Optional proxy settings - /// A byte[], which is the albumart in binary data - public byte[] GetAlbumArtAsByteArray(AlbumArtSize size, ProxyConfig proxyConfig = null) - { - using (WebClient wc = new WebClient()) - { - IWebProxy proxy = proxyConfig?.CreateWebProxy(); - wc.Proxy = proxy; - - string url = GetAlbumArtUrl(size, proxy); - if (string.IsNullOrEmpty(url)) - return null; - return wc.DownloadData(url); - } - } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/Models/TrackResourceLocation.cs b/SpotifyAPI/Local/Models/TrackResourceLocation.cs deleted file mode 100644 index b4301866..00000000 --- a/SpotifyAPI/Local/Models/TrackResourceLocation.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Newtonsoft.Json; -using System; - -namespace SpotifyAPI.Local.Models -{ - public class TrackResourceLocation - { - [JsonProperty("og")] - public string Og { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/RemoteHandler.cs b/SpotifyAPI/Local/RemoteHandler.cs deleted file mode 100644 index d21a79b3..00000000 --- a/SpotifyAPI/Local/RemoteHandler.cs +++ /dev/null @@ -1,194 +0,0 @@ -using Newtonsoft.Json; -using SpotifyAPI.Local.Models; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Net; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using System.Web; - -[assembly: InternalsVisibleTo("SpotifyAPI.Tests")] - - -namespace SpotifyAPI.Local -{ - - internal class RemoteHandler - { - public string OauthKey { get; private set; } - public string CfidKey { get; private set; } - - private SpotifyLocalAPIConfig _config; - - public RemoteHandler(SpotifyLocalAPIConfig config) - { - _config = config; - } - - internal bool Init() - { - OauthKey = GetOAuthKey(); - CfidKey = GetCfid(); - return !string.IsNullOrEmpty(CfidKey); - } - - internal async Task SendPauseRequest() - { - NameValueCollection @params = new NameValueCollection { { "pause", "true" } }; - await QueryAsync("remote/pause.json", true, true, -1, @params).ConfigureAwait(false); - } - - internal async Task SendPlayRequest() - { - NameValueCollection @params = new NameValueCollection { { "pause", "false" } }; - await QueryAsync("remote/pause.json", true, true, -1, @params).ConfigureAwait(false); - } - - internal async Task SendPlayRequest(string url, string context = "") - { - - // TODO: instead of having an empty context, one way to fix the bug with the playback time beyond the length of a song would be to provide a 1-song context, and it would be fixed. - NameValueCollection @params = new NameValueCollection - { - {"uri", url}, - {"context", context} - }; - await QueryAsync($"remote/play.json", true, true, -1, @params).ConfigureAwait(false); - - } - - internal async Task SendQueueRequest(string url) - { - NameValueCollection @params = new NameValueCollection - { - {"uri", url}, - {"action", "queue"} - }; - await QueryAsync("remote/play.json", true, true, -1, @params).ConfigureAwait(false); - - } - - internal StatusResponse GetNewStatus() - { - string response = Query("remote/status.json", true, true, -1); - if (string.IsNullOrEmpty(response)) - return null; - response = response.Replace("\\n", ""); - List raw = JsonConvert.DeserializeObject>(response); - return raw[0]; - } - - internal string GetOAuthKey() - { - string raw; - using (WebClient wc = GetWebClientWithUserAgentHeader()) - { - raw = wc.DownloadString("http://open.spotify.com/token"); - } - Dictionary dic = JsonConvert.DeserializeObject>(raw); - return dic == null ? "" : (string)dic["t"]; - } - - internal string GetCfid() - { - string response = Query("simplecsrf/token.json", false, false, -1); - response = response.Replace(@"\", ""); - List cfidList = (List)JsonConvert.DeserializeObject(response, typeof(List)); - if (cfidList == null) - return ""; - if (cfidList.Count != 1) - throw new Exception("CFID could not be loaded"); - return cfidList[0].Error == null ? cfidList[0].Token : ""; - } - - internal string BuildQueryString(bool oauth, bool cfid, int wait, NameValueCollection @params = null) - { - if (@params == null) - { - @params = new NameValueCollection(); - } - NameValueCollection queryParameter = HttpUtility.ParseQueryString(string.Empty); - queryParameter.Add(@params); - queryParameter.Add(new NameValueCollection() { - { "ref", string.Empty}, - { "cors", string.Empty}, - { "_", GetTimestamp().ToString()} - }); - if (oauth) - { - queryParameter.Add("oauth", OauthKey); - } - if (cfid) - { - queryParameter.Add("csrf", CfidKey); - } - - if (wait != -1) - { - queryParameter.Add("returnafter", wait.ToString()); - queryParameter.Add("returnon", "login%2Clogout%2Cplay%2Cpause%2Cerror%2Cap"); - } - - return queryParameter.ToString(); - } - internal string Query(string baseUrl, bool oauth, bool cfid, int wait, NameValueCollection @params = null) - { - string parameters = BuildQueryString(oauth, cfid, wait, @params); - string address = $"{_config.HostUrl}:{_config.Port}/{baseUrl}?{parameters}"; - string response = string.Empty; - try - { - using (ExtendedWebClient wc = new ExtendedWebClient()) - { - if (SpotifyLocalAPI.IsSpotifyRunning()) - { - response = "[ " + wc.DownloadString(address) + " ]"; - } - } - } - catch - { - return string.Empty; - } - - return response; - } - - internal async Task QueryAsync(string baseUrl, bool oauth, bool cfid, int wait, NameValueCollection @params = null) - { - string parameters = BuildQueryString(oauth, cfid, wait, @params); - string address = $"{_config.HostUrl}:{_config.Port}/{baseUrl}?{parameters}"; - string response = ""; - try - { - using (ExtendedWebClient wc = new ExtendedWebClient()) - { - if (SpotifyLocalAPI.IsSpotifyRunning()) - response = "[ " + await wc.DownloadStringTaskAsync(new Uri(address)).ConfigureAwait(false) + " ]"; - } - } - catch - { - return string.Empty; - } - - return response; - } - internal int GetTimestamp() - { - return Convert.ToInt32((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); - } - - internal WebClient GetWebClientWithUserAgentHeader() - { - WebClient wc = new WebClient - { - Proxy = _config?.ProxyConfig?.CreateWebProxy() - }; - wc.Headers.Add(HttpRequestHeader.UserAgent, _config?.UserAgent); - - return wc; - } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/SpotifyLocalAPI.cs b/SpotifyAPI/Local/SpotifyLocalAPI.cs deleted file mode 100644 index 4ebba799..00000000 --- a/SpotifyAPI/Local/SpotifyLocalAPI.cs +++ /dev/null @@ -1,368 +0,0 @@ -using SpotifyAPI.Local.Models; -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using System.Threading.Tasks; -using System.Timers; - -namespace SpotifyAPI.Local -{ - public class SpotifyLocalAPI : IDisposable - { - [DllImport("user32.dll")] - private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo); - - private bool _listenForEvents; - - public bool ListenForEvents - { - get - { - return _listenForEvents; - } - set - { - _listenForEvents = value; - _eventTimer.Enabled = value; - } - } - - private ISynchronizeInvoke _synchronizingObject; - - public ISynchronizeInvoke SynchronizingObject - { - get - { - return _synchronizingObject; - } - set - { - _synchronizingObject = value; - _eventTimer.SynchronizingObject = value; - } - } - - private const int WindowsSevenMajorVersion = 6; - private const int WindowsSevenMinorVersion = 1; - private const byte VkMediaNextTrack = 0xb0; - private const byte VkMediaPrevTrack = 0xb1; - private const int KeyeventfExtendedkey = 0x1; - private const int KeyeventfKeyup = 0x2; - - private readonly RemoteHandler _rh; - private Timer _eventTimer; - private StatusResponse _eventStatusResponse; - private Track _eventStatusTrack; - - public event EventHandler OnTrackChange; - - public event EventHandler OnPlayStateChange; - - public event EventHandler OnVolumeChange; - - public event EventHandler OnTrackTimeChange; - - public SpotifyLocalAPI(int timerIntervall = 50) - { - _rh = new RemoteHandler(new SpotifyLocalAPIConfig()); - AttachTimer(timerIntervall); - } - - public SpotifyLocalAPI(SpotifyLocalAPIConfig config) - { - _rh = new RemoteHandler(config); - AttachTimer(config.TimerInterval); - } - - private void AttachTimer(int intervall) - { - _eventTimer = new Timer - { - Interval = intervall, - AutoReset = false, - Enabled = false - }; - _eventTimer.Elapsed += ElapsedTick; - } - - private void ElapsedTick(object sender, ElapsedEventArgs e) - { - if (_eventStatusResponse == null) - { - _eventStatusResponse = GetStatus(); - _eventTimer.Start(); - return; - } - StatusResponse newStatusResponse = GetStatus(); - if (newStatusResponse == null) - { - _eventTimer.Start(); - return; - } - if (!newStatusResponse.Running && newStatusResponse.Track == null) - { - _eventTimer.Start(); - return; - } - if (newStatusResponse.Track != null && _eventStatusTrack != null) - { - if (newStatusResponse.Track.TrackResource?.Uri != _eventStatusTrack.TrackResource?.Uri || - newStatusResponse.Track.IsOtherTrackType() && newStatusResponse.Track.Length != _eventStatusTrack.Length) - { - OnTrackChange?.Invoke(this, new TrackChangeEventArgs() - { - OldTrack = _eventStatusTrack, - NewTrack = newStatusResponse.Track - }); - } - } - if (newStatusResponse.Playing != _eventStatusResponse.Playing) - { - OnPlayStateChange?.Invoke(this, new PlayStateEventArgs() - { - Playing = newStatusResponse.Playing - }); - } - if (newStatusResponse.Volume != _eventStatusResponse.Volume) - { - OnVolumeChange?.Invoke(this, new VolumeChangeEventArgs() - { - OldVolume = _eventStatusResponse.Volume, - NewVolume = newStatusResponse.Volume - }); - } - if (newStatusResponse.PlayingPosition != _eventStatusResponse.PlayingPosition) - { - OnTrackTimeChange?.Invoke(this, new TrackTimeChangeEventArgs() - { - TrackTime = newStatusResponse.PlayingPosition - }); - } - _eventStatusResponse = newStatusResponse; - if (newStatusResponse.Track != null) - { - _eventStatusTrack = newStatusResponse.Track; - } - _eventTimer.Start(); - } - - private bool IsOSCompatible(int minMajor, int minMinor) - { - return Environment.OSVersion.Version.Major > minMajor || (Environment.OSVersion.Version.Major == minMajor && Environment.OSVersion.Version.Minor >= minMinor); - } - /// - /// Connects with Spotify. Needs to be called before all other SpotifyAPI functions - /// - /// Returns true, if it was successful, false if not - public Boolean Connect() - { - return _rh.Init(); - } - - /// - /// Update and returns the new StatusResponse from the Spotify-Player - /// - /// An up-to-date StatusResponse - public StatusResponse GetStatus() - { - return _rh.GetNewStatus(); - } - - /// - /// Mutes Spotify (Requires Windows 7 or newer) - /// - public void Mute() - { - if(!IsOSCompatible(WindowsSevenMajorVersion, WindowsSevenMinorVersion)) - throw new NotSupportedException("This feature is only available on Windows 7 or newer"); - VolumeMixerControl.MuteSpotify(true); - } - - /// - /// Unmutes Spotify (Requires Windows 7 or newer) - /// - public void UnMute() - { - if (!IsOSCompatible(WindowsSevenMajorVersion, WindowsSevenMinorVersion)) - throw new NotSupportedException("This feature is only available on Windows 7 or newer"); - VolumeMixerControl.MuteSpotify(false); - } - - /// - /// Checks whether Spotify is muted in the Volume Mixer control (required Windows 7 or newer) - /// - /// Null if an error occured, otherwise the muted state - public bool IsSpotifyMuted() - { - if (!IsOSCompatible(WindowsSevenMajorVersion, WindowsSevenMinorVersion)) - throw new NotSupportedException("This feature is only available on Windows 7 or newer"); - return VolumeMixerControl.IsSpotifyMuted(); - } - - /// - /// Sets the Volume Mixer volume (requires Windows 7 or newer) - /// - /// A value between 0 and 100 - public void SetSpotifyVolume(float volume = 100) - { - if (!IsOSCompatible(WindowsSevenMajorVersion, WindowsSevenMinorVersion)) - throw new NotSupportedException("This feature is only available on Windows 7 or newer"); - if (volume < 0 || volume > 100) - throw new ArgumentOutOfRangeException(nameof(volume)); - VolumeMixerControl.SetSpotifyVolume(volume); - } - - /// - /// Return the Volume Mixer volume of Spotify (requires Windows 7 or newer) - /// - /// Null if an error occured, otherwise a float between 0 and 100 - public float GetSpotifyVolume() - { - if (!IsOSCompatible(WindowsSevenMajorVersion, WindowsSevenMinorVersion)) - throw new NotSupportedException("This feature is only available on Windows 7 or newer"); - return VolumeMixerControl.GetSpotifyVolume(); - } - - /// - /// Pause function - /// - public async Task Pause() - { - await _rh.SendPauseRequest(); - } - - /// - /// Play function - /// - public async Task Play() - { - await _rh.SendPlayRequest(); - } - - /// - /// Simulates a KeyPress - /// - /// The keycode for the represented Key - internal void PressKey(byte keyCode) - { - keybd_event(keyCode, 0x45, KeyeventfExtendedkey, 0); - keybd_event(keyCode, 0x45, KeyeventfExtendedkey | KeyeventfKeyup, 0); - } - - /// - /// Plays a Spotify URI within an optional context. - /// - /// The Spotify URI - /// The context in which to play the specified . - /// - /// Contexts are basically a queue in spotify. a song can be played within a context, meaning that hitting next / previous would lead to another song. Contexts are leveraged by widgets as described in the "Multiple tracks player" section of the following documentation page: https://developer.spotify.com/technologies/widgets/spotify-play-button/ - /// - public async Task PlayURL(string uri, string context = "") - { - await _rh.SendPlayRequest(uri, context); - } - - /// - /// Adds a Spotify URI to the Queue - /// - /// The Spotify URI - [Obsolete("This method doesn't work with the current spotify version.")] - public async Task AddToQueue(string uri) - { - await _rh.SendQueueRequest(uri); - } - - /// - /// Skips the current song (Using keypress simulation) - /// - public void Skip() - { - PressKey(VkMediaNextTrack); - } - - /// - /// Emulates the "Previous" Key (Using keypress simulation) - /// - public void Previous() - { - PressKey(VkMediaPrevTrack); - } - - /// - /// Checks if Spotify is running - /// - /// True, if it's running, false if not - public static Boolean IsSpotifyRunning() - { - return Process.GetProcessesByName("spotify").Length >= 1; - } - - /// - /// Checks if Spotify's WebHelper is running (Needed for API Calls) - /// - /// True, if it's running, false if not - public static Boolean IsSpotifyWebHelperRunning() - { - return Process.GetProcessesByName("spotifywebhelper").Length >= 1; - } - - /// - /// Determines whether [spotify is installed]. - /// - /// - /// true if [spotify is installed]; otherwise, false. - /// - public static bool IsSpotifyInstalled() - { - bool isInstalled = false; - - // Checks if UWP Spotify is installed. - string uwpSpotifyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Packages\SpotifyAB.SpotifyMusic_zpdnekdrzrea0"); - - isInstalled = Directory.Exists(uwpSpotifyPath); - - // If UWP Spotify is not installed, try look for desktop version - if (!isInstalled) - { - string desktopSpotifyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Spotify\Spotify.exe"); - isInstalled = File.Exists(desktopSpotifyPath); - } - - return isInstalled; - } - - /// - /// Runs Spotify - /// - public static void RunSpotify() - { - if (!IsSpotifyRunning() && File.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"spotify\spotify.exe"))) - Process.Start(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"spotify\spotify.exe")); - } - - /// - /// Runs Spotify's WebHelper - /// - public static void RunSpotifyWebHelper() - { - if (!IsSpotifyWebHelperRunning() && File.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"spotify\data\spotifywebhelper.exe"))) - { - Process.Start(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"spotify\data\spotifywebhelper.exe")); - } - else if (!IsSpotifyWebHelperRunning() && File.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"spotify\spotifywebhelper.exe"))) - { - Process.Start(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"spotify\spotifywebhelper.exe")); - } - } - - public void Dispose() - { - if (_eventTimer == null) - return; - _eventTimer.Enabled = false; - _eventTimer.Elapsed -= ElapsedTick; - } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/SpotifyLocalAPIConfig.cs b/SpotifyAPI/Local/SpotifyLocalAPIConfig.cs deleted file mode 100644 index 19cec30b..00000000 --- a/SpotifyAPI/Local/SpotifyLocalAPIConfig.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace SpotifyAPI.Local -{ - // ReSharper disable once InconsistentNaming - public class SpotifyLocalAPIConfig - { - public int TimerInterval { get; set; } = 50; - - public string HostUrl { get; set; } = "http://127.0.0.1"; - - public int Port { get; set; } = 4381; - - public ProxyConfig ProxyConfig { get; set; } - - public string UserAgent { get; set; } = "Spotify (1.0.85.257.g0f8531bd)"; - } -} \ No newline at end of file diff --git a/SpotifyAPI/Local/VolumeMixerControl.cs b/SpotifyAPI/Local/VolumeMixerControl.cs deleted file mode 100644 index 2c0133a2..00000000 --- a/SpotifyAPI/Local/VolumeMixerControl.cs +++ /dev/null @@ -1,302 +0,0 @@ -using System; -using System.Diagnostics; -using System.Linq; -using System.Runtime.InteropServices; - -namespace SpotifyAPI.Local -{ - internal static class VolumeMixerControl - { - private const string SpotifyProcessName = "spotify"; - - internal static float GetSpotifyVolume() - { - ISimpleAudioVolume volume = GetSpotifyVolumeObject(); - - if (volume == null) - { - throw new COMException("Volume object creation failed"); - } - - volume.GetMasterVolume(out float level); - Marshal.ReleaseComObject(volume); - return level * 100; - } - - internal static bool IsSpotifyMuted() - { - ISimpleAudioVolume volume = GetSpotifyVolumeObject(); - - if (volume == null) - { - throw new COMException("Volume object creation failed"); - } - - volume.GetMute(out bool mute); - Marshal.ReleaseComObject(volume); - return mute; - } - - internal static void SetSpotifyVolume(float level) - { - ISimpleAudioVolume volume = GetSpotifyVolumeObject(); - - if (volume == null) - { - throw new COMException("Volume object creation failed"); - } - - Guid guid = Guid.Empty; - volume.SetMasterVolume(level / 100, ref guid); - Marshal.ReleaseComObject(volume); - } - - internal static void MuteSpotify(bool mute) - { - ISimpleAudioVolume volume = GetSpotifyVolumeObject(); - - if (volume == null) - { - throw new COMException("Volume object creation failed"); - } - - Guid guid = Guid.Empty; - volume.SetMute(mute, ref guid); - Marshal.ReleaseComObject(volume); - } - - private static ISimpleAudioVolume GetSpotifyVolumeObject() - { - var audioVolumeObjects = from p in Process.GetProcessesByName(SpotifyProcessName) - let vol = GetVolumeObject(p.Id) - where vol != null - select vol; - return audioVolumeObjects.FirstOrDefault(); - } - - private static ISimpleAudioVolume GetVolumeObject(int pid) - { - // get the speakers (1st render + multimedia) device - IMmDeviceEnumerator deviceEnumerator = (IMmDeviceEnumerator) new MMDeviceEnumerator(); - deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.ERender, ERole.EMultimedia, out IMmDevice speakers); - - speakers.GetId(out string defaultDeviceId); - - ISimpleAudioVolume volumeControl = GetVolumeObject(pid, speakers); - Marshal.ReleaseComObject(speakers); - - if (volumeControl == null) - { - // If volumeControl is null, then the process's volume object might be on a different device. - // This happens if the process doesn't use the default device. - // - // As far as Spotify is concerned, if using the "--enable-audio-graph" command line argument, - // a new option becomes available in the Settings that makes it possible to change the playback device. - - deviceEnumerator.EnumAudioEndpoints(EDataFlow.ERender, EDeviceState.Active, out IMmDeviceCollection deviceCollection); - - deviceCollection.GetCount(out int count); - for (int i = 0; i < count; i++) - { - deviceCollection.Item(i, out IMmDevice device); - device.GetId(out string deviceId); - - try - { - if (deviceId == defaultDeviceId) - continue; - - volumeControl = GetVolumeObject(pid, device); - if (volumeControl != null) - break; - } - finally - { - Marshal.ReleaseComObject(device); - } - } - } - - Marshal.ReleaseComObject(deviceEnumerator); - return volumeControl; - } - - private static ISimpleAudioVolume GetVolumeObject(int pid, IMmDevice device) - { - // activate the session manager. we need the enumerator - Guid iidIAudioSessionManager2 = typeof(IAudioSessionManager2).GUID; - device.Activate(ref iidIAudioSessionManager2, 0, IntPtr.Zero, out object o); - IAudioSessionManager2 mgr = (IAudioSessionManager2) o; - - // enumerate sessions for on this device - mgr.GetSessionEnumerator(out IAudioSessionEnumerator sessionEnumerator); - sessionEnumerator.GetCount(out int count); - - // search for an audio session with the required name - // NOTE: we could also use the process id instead of the app name (with IAudioSessionControl2) - ISimpleAudioVolume volumeControl = null; - for (int i = 0; i < count; i++) - { - sessionEnumerator.GetSession(i, out IAudioSessionControl2 ctl); - ctl.GetProcessId(out int cpid); - - if (cpid == pid) - { - volumeControl = (ISimpleAudioVolume) ctl; - break; - } - Marshal.ReleaseComObject(ctl); - } - Marshal.ReleaseComObject(sessionEnumerator); - Marshal.ReleaseComObject(mgr); - return volumeControl; - } - - [ComImport] - [Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] - private class MMDeviceEnumerator - { - } - - private enum EDataFlow - { - ERender, - ECapture, - EAll, - EDataFlowEnumCount - } - - private enum ERole - { - EConsole, - EMultimedia, - ECommunications, - ERoleEnumCount - } - - [Flags] - private enum EDeviceState - { - Active = 0x00000001, - Disabled = 0x00000002, - NotPresent = 0x00000004, - UnPlugged = 0x00000008, - All = 0x0000000F - } - - [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - private interface IMmDeviceEnumerator - { - [PreserveSig] - int EnumAudioEndpoints(EDataFlow dataFlow, EDeviceState stateMask, [Out] out IMmDeviceCollection deviceCollection); - - [PreserveSig] - int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMmDevice ppDevice); - } - - [Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - private interface IMmDevice - { - [PreserveSig] - int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface); - - int OpenPropertyStore_NotImpl(); - - [PreserveSig] - int GetId([Out, MarshalAs(UnmanagedType.LPWStr)] out string ppstrId); - } - - [Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - private interface IMmDeviceCollection - { - [PreserveSig] - int GetCount(out int deviceCount); - - [PreserveSig] - int Item(int deviceIndex, [Out] out IMmDevice device); - } - - [Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - private interface IAudioSessionManager2 - { - int NotImpl1(); - - int NotImpl2(); - - [PreserveSig] - int GetSessionEnumerator(out IAudioSessionEnumerator sessionEnum); - } - - [Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - private interface IAudioSessionEnumerator - { - [PreserveSig] - int GetCount(out int sessionCount); - - [PreserveSig] - int GetSession(int sessionCount, out IAudioSessionControl2 session); - } - - [Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - private interface ISimpleAudioVolume - { - [PreserveSig] - int SetMasterVolume(float fLevel, ref Guid eventContext); - - [PreserveSig] - int GetMasterVolume(out float pfLevel); - - [PreserveSig] - int SetMute(bool bMute, ref Guid eventContext); - - [PreserveSig] - int GetMute(out bool pbMute); - } - - [Guid("bfb7ff88-7239-4fc9-8fa2-07c950be9c6d"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - private interface IAudioSessionControl2 - { - [PreserveSig] - int NotImpl0(); - - [PreserveSig] - int GetDisplayName([MarshalAs(UnmanagedType.LPWStr)] out string pRetVal); - - [PreserveSig] - int SetDisplayName([MarshalAs(UnmanagedType.LPWStr)]string value, [MarshalAs(UnmanagedType.LPStruct)] Guid eventContext); - - [PreserveSig] - int GetIconPath([MarshalAs(UnmanagedType.LPWStr)] out string pRetVal); - - [PreserveSig] - int SetIconPath([MarshalAs(UnmanagedType.LPWStr)] string value, [MarshalAs(UnmanagedType.LPStruct)] Guid eventContext); - - [PreserveSig] - int GetGroupingParam(out Guid pRetVal); - - [PreserveSig] - int SetGroupingParam([MarshalAs(UnmanagedType.LPStruct)] Guid Override, [MarshalAs(UnmanagedType.LPStruct)] Guid eventContext); - - [PreserveSig] - int NotImpl1(); - - [PreserveSig] - int NotImpl2(); - - [PreserveSig] - int GetSessionIdentifier([MarshalAs(UnmanagedType.LPWStr)] out string pRetVal); - - [PreserveSig] - int GetSessionInstanceIdentifier([MarshalAs(UnmanagedType.LPWStr)] out string pRetVal); - - [PreserveSig] - int GetProcessId(out int pRetVal); - - [PreserveSig] - int IsSystemSoundsSession(); - - [PreserveSig] - int SetDuckingPreference(bool optOut); - } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Properties/AssemblyInfo.cs b/SpotifyAPI/Properties/AssemblyInfo.cs deleted file mode 100644 index 5c4ae80d..00000000 --- a/SpotifyAPI/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// Allgemeine Informationen über eine Assembly werden über die folgenden -// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, -// die mit einer Assembly verknüpft sind. -[assembly: AssemblyTitle("SpotifyLocalAPIClass")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SpotifyLocalAPIClass")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar -// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von -// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. -[assembly: ComVisible(false)] - -// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird -[assembly: Guid("3a30f0ac-4874-4d18-ba0e-d20d0f67ed32")] - -// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: -// -// Hauptversion -// Nebenversion -// Buildnummer -// Revision -// -// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern -// übernehmen, indem Sie "*" eingeben: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/SpotifyAPI/SpotifyAPI.csproj b/SpotifyAPI/SpotifyAPI.csproj deleted file mode 100644 index 4fa3577e..00000000 --- a/SpotifyAPI/SpotifyAPI.csproj +++ /dev/null @@ -1,151 +0,0 @@ - - - - - Debug - AnyCPU - {EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D} - Library - Properties - SpotifyAPI - SpotifyAPI - v4.5 - 512 - ..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\SpotifyAPI.XML - 1591 - MinimumRecommendedRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\SpotifyAPI.XML - 1591 - - - - ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - - Component - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/SpotifyAPI/SpotifyAPI.nuspec b/SpotifyAPI/SpotifyAPI.nuspec deleted file mode 100644 index 49889587..00000000 --- a/SpotifyAPI/SpotifyAPI.nuspec +++ /dev/null @@ -1,25 +0,0 @@ - - - - SpotifyAPI-NET - 1.0.0 - SpotifyAPI-NET - JohnnyCrazy - JohnnyCrazy - https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/LICENSE - https://github.com/JohnnyCrazy/SpotifyAPI-NET/ - false - An API for the Spotify-Client and Spotify's Web API, written in .NET - -For more infos, visit https://github.com/JohnnyCrazy/SpotifyAPI-NET - - spotify api music .net c# spotify-client - - - - - - - - - diff --git a/SpotifyAPI/Web/Auth/AutorizationCodeAuth.cs b/SpotifyAPI/Web/Auth/AutorizationCodeAuth.cs deleted file mode 100644 index a6785e56..00000000 --- a/SpotifyAPI/Web/Auth/AutorizationCodeAuth.cs +++ /dev/null @@ -1,160 +0,0 @@ -using Newtonsoft.Json; -using SpotifyAPI.Web.Enums; -using SpotifyAPI.Web.Models; -using System; -using System.Collections.Specialized; -using System.Diagnostics; -using System.IO; -using System.Net; -using System.Text; -using System.Threading; - -namespace SpotifyAPI.Web.Auth -{ - public class AutorizationCodeAuth - { - public delegate void OnResponseReceived(AutorizationCodeAuthResponse response); - - private SimpleHttpServer _httpServer; - private Thread _httpThread; - public string ClientId { get; set; } - public string RedirectUri { get; set; } - public string State { get; set; } - public Scope Scope { get; set; } - public Boolean ShowDialog { get; set; } - - /// - /// Will be fired once the user authenticated - /// - public event OnResponseReceived OnResponseReceivedEvent; - - /// - /// Start the auth process (Make sure the internal HTTP-Server ist started) - /// - public void DoAuth() - { - string uri = GetUri(); - Process.Start(uri); - } - - /// - /// Refreshes auth by providing the clientsecret (Don't use this if you're on a client) - /// - /// The refresh-token of the earlier gathered token - /// Your Client-Secret, don't provide it if this is running on a client! - public Token RefreshToken(string refreshToken, string clientSecret) - { - using (WebClient wc = new WebClient()) - { - wc.Headers.Add("Authorization", - "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(ClientId + ":" + clientSecret))); - NameValueCollection col = new NameValueCollection - { - {"grant_type", "refresh_token"}, - {"refresh_token", refreshToken} - }; - - string response; - try - { - byte[] data = wc.UploadValues("https://accounts.spotify.com/api/token", "POST", col); - response = Encoding.UTF8.GetString(data); - } - catch (WebException e) - { - using (StreamReader reader = new StreamReader(e.Response.GetResponseStream())) - { - response = reader.ReadToEnd(); - } - } - return JsonConvert.DeserializeObject(response); - } - } - - private string GetUri() - { - StringBuilder builder = new StringBuilder("https://accounts.spotify.com/authorize/?"); - builder.Append("client_id=" + ClientId); - builder.Append("&response_type=code"); - builder.Append("&redirect_uri=" + RedirectUri); - builder.Append("&state=" + State); - builder.Append("&scope=" + Scope.GetStringAttribute(" ")); - builder.Append("&show_dialog=" + ShowDialog); - return builder.ToString(); - } - - /// - /// Start the internal HTTP-Server - /// - public void StartHttpServer(int port = 80) - { - _httpServer = new SimpleHttpServer(port, AuthType.Authorization); - _httpServer.OnAuth += HttpServerOnOnAuth; - - _httpThread = new Thread(_httpServer.Listen); - _httpThread.Start(); - } - - private void HttpServerOnOnAuth(AuthEventArgs e) - { - OnResponseReceivedEvent?.Invoke(new AutorizationCodeAuthResponse() - { - Code = e.Code, - State = e.State, - Error = e.Error - }); - } - - /// - /// This will stop the internal HTTP-Server (Should be called after you got the Token) - /// - public void StopHttpServer() - { - _httpServer.Dispose(); - _httpServer = null; - } - - /// - /// Exchange a code for a Token (Don't use this if you're on a client) - /// - /// The gathered code from the response - /// Your Client-Secret, don't provide it if this is running on a client! - /// - public Token ExchangeAuthCode(string code, string clientSecret) - { - using (WebClient wc = new WebClient()) - { - NameValueCollection col = new NameValueCollection - { - {"grant_type", "authorization_code"}, - {"code", code}, - {"redirect_uri", RedirectUri}, - {"client_id", ClientId}, - {"client_secret", clientSecret} - }; - - string response; - try - { - byte[] data = wc.UploadValues("https://accounts.spotify.com/api/token", "POST", col); - response = Encoding.UTF8.GetString(data); - } - catch (WebException e) - { - using (StreamReader reader = new StreamReader(e.Response.GetResponseStream())) - { - response = reader.ReadToEnd(); - } - } - return JsonConvert.DeserializeObject(response); - } - } - } - - public struct AutorizationCodeAuthResponse - { - public string Code { get; set; } - public string State { get; set; } - public string Error { get; set; } - } -} diff --git a/SpotifyAPI/Web/Auth/ClientCredentialsAuth.cs b/SpotifyAPI/Web/Auth/ClientCredentialsAuth.cs deleted file mode 100644 index 9e68c2fb..00000000 --- a/SpotifyAPI/Web/Auth/ClientCredentialsAuth.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Newtonsoft.Json; -using SpotifyAPI.Web.Enums; -using SpotifyAPI.Web.Models; -using System; -using System.Collections.Specialized; -using System.IO; -using System.Net; -using System.Text; -using System.Threading.Tasks; - -namespace SpotifyAPI.Web.Auth -{ - public class ClientCredentialsAuth - { - public Scope Scope { get; set; } - public string ClientId { get; set; } - public string ClientSecret { get; set; } - - /// - /// Starts the auth process and - /// - /// A new Token - public Token DoAuth() - { - using (WebClient wc = new WebClient()) - { - wc.Headers.Add("Authorization", - "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(ClientId + ":" + ClientSecret))); - - NameValueCollection col = new NameValueCollection - { - {"grant_type", "client_credentials"}, - {"scope", Scope.GetStringAttribute(" ")} - }; - - byte[] data; - try - { - data = wc.UploadValues("https://accounts.spotify.com/api/token", "POST", col); - } - catch (WebException e) - { - using (StreamReader reader = new StreamReader(e.Response.GetResponseStream())) - { - data = Encoding.UTF8.GetBytes(reader.ReadToEnd()); - } - } - return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data)); - } - } - - /// - /// Starts the auth process async and - /// - /// A new Token - public async Task DoAuthAsync() - { - using (WebClient wc = new WebClient()) - { - wc.Headers.Add("Authorization", - "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(ClientId + ":" + ClientSecret))); - - NameValueCollection col = new NameValueCollection - { - {"grant_type", "client_credentials"}, - {"scope", Scope.GetStringAttribute(" ")} - }; - - byte[] data; - try - { - data = await wc.UploadValuesTaskAsync("https://accounts.spotify.com/api/token", "POST", col); - } - catch (WebException e) - { - using (StreamReader reader = new StreamReader(e.Response.GetResponseStream())) - { - data = Encoding.UTF8.GetBytes(await reader.ReadToEndAsync()); - } - } - return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data)); - } - } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Web/Auth/ImplicitGrantAuth.cs b/SpotifyAPI/Web/Auth/ImplicitGrantAuth.cs deleted file mode 100644 index 53a5c65c..00000000 --- a/SpotifyAPI/Web/Auth/ImplicitGrantAuth.cs +++ /dev/null @@ -1,77 +0,0 @@ -using SpotifyAPI.Web.Enums; -using SpotifyAPI.Web.Models; -using System; -using System.Diagnostics; -using System.Text; -using System.Threading; - -namespace SpotifyAPI.Web.Auth -{ - public class ImplicitGrantAuth - { - public delegate void OnResponseReceived(Token token, string state); - - private SimpleHttpServer _httpServer; - private Thread _httpThread; - public string ClientId { get; set; } - public string RedirectUri { get; set; } - public string State { get; set; } - public Scope Scope { get; set; } - public Boolean ShowDialog { get; set; } - - public event OnResponseReceived OnResponseReceivedEvent; - - /// - /// Start the auth process (Make sure the internal HTTP-Server ist started) - /// - public void DoAuth() - { - string uri = GetUri(); - Process.Start(uri); - } - - private string GetUri() - { - StringBuilder builder = new StringBuilder("https://accounts.spotify.com/authorize/?"); - builder.Append("client_id=" + ClientId); - builder.Append("&response_type=token"); - builder.Append("&redirect_uri=" + RedirectUri); - builder.Append("&state=" + State); - builder.Append("&scope=" + Scope.GetStringAttribute(" ")); - builder.Append("&show_dialog=" + ShowDialog); - return builder.ToString(); - } - - /// - /// Start the internal HTTP-Server - /// - public void StartHttpServer(int port = 80) - { - _httpServer = new SimpleHttpServer(port, AuthType.Implicit); - _httpServer.OnAuth += HttpServerOnOnAuth; - - _httpThread = new Thread(_httpServer.Listen); - _httpThread.Start(); - } - - private void HttpServerOnOnAuth(AuthEventArgs e) - { - OnResponseReceivedEvent?.Invoke(new Token - { - AccessToken = e.Code, - TokenType = e.TokenType, - ExpiresIn = e.ExpiresIn, - Error = e.Error - }, e.State); - } - - /// - /// This will stop the internal HTTP-Server (Should be called after you got the Token) - /// - public void StopHttpServer() - { - _httpServer.Dispose(); - _httpServer = null; - } - } -} \ No newline at end of file diff --git a/SpotifyAPI/Web/Auth/WebAPIFactory.cs b/SpotifyAPI/Web/Auth/WebAPIFactory.cs deleted file mode 100644 index 94e21980..00000000 --- a/SpotifyAPI/Web/Auth/WebAPIFactory.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using SpotifyAPI.Web.Enums; -using SpotifyAPI.Web.Models; - -namespace SpotifyAPI.Web.Auth -{ - public class WebAPIFactory - { - private readonly string _redirectUrl; - private readonly int _listeningPort; - private readonly string _clientId; - private readonly TimeSpan _timeout; - private readonly Scope _scope; - private readonly ProxyConfig _proxyConfig; - private readonly string _xss; - - public WebAPIFactory(string redirectUrl, int listeningPort, string clientId, Scope scope) - : this(redirectUrl, listeningPort, clientId, scope, null) - { - } - - public WebAPIFactory(string redirectUrl, int listeningPort, string clientId, Scope scope, ProxyConfig proxyConfig) - : this(redirectUrl, listeningPort, clientId, scope, TimeSpan.FromSeconds(20), proxyConfig) - { - } - - public WebAPIFactory(string redirectUrl, int listeningPort, string clientId, Scope scope, TimeSpan timeout, string xss = "XSS") - : this(redirectUrl, listeningPort, clientId, scope, timeout, null, xss) - { - } - - public WebAPIFactory(string redirectUrl, int listeningPort, string clientId, Scope scope, TimeSpan timeout, ProxyConfig proxyConfig, string xss = "XSS") - { - _redirectUrl = redirectUrl; - _listeningPort = listeningPort; - _clientId = clientId; - _scope = scope; - _timeout = timeout; - _proxyConfig = proxyConfig; - _xss = xss; - } - - public Task GetWebApi(bool showDialog = false) - { - var authentication = new ImplicitGrantAuth - { - RedirectUri = new UriBuilder(_redirectUrl) { Port = _listeningPort }.Uri.OriginalString.TrimEnd('/'), - ClientId = _clientId, - Scope = _scope, - ShowDialog = showDialog, - State = _xss - }; - - AutoResetEvent authenticationWaitFlag = new AutoResetEvent(false); - SpotifyWebAPI spotifyWebApi = null; - authentication.OnResponseReceivedEvent += (token, state) => - { - spotifyWebApi = HandleSpotifyResponse(state, token); - authenticationWaitFlag.Set(); - }; - - try - { - authentication.StartHttpServer(_listeningPort); - - authentication.DoAuth(); - - authenticationWaitFlag.WaitOne(_timeout); - if (spotifyWebApi == null) - throw new TimeoutException($"No valid response received for the last {_timeout.TotalSeconds} seconds"); - } - finally - { - authentication.StopHttpServer(); - } - - return Task.FromResult(spotifyWebApi); - } - - private SpotifyWebAPI HandleSpotifyResponse(string state, Token token) - { - if (state != _xss) - throw new SpotifyWebApiException($"Wrong state '{state}' received."); - - if (token.Error != null) - throw new SpotifyWebApiException($"Error: {token.Error}"); - - var spotifyWebApi = new SpotifyWebAPI(_proxyConfig) - { - UseAuth = true, - AccessToken = token.AccessToken, - TokenType = token.TokenType - }; - - return spotifyWebApi; - } - } - - [Serializable] - public class SpotifyWebApiException : Exception - { - public SpotifyWebApiException(string message) : base(message) - { } - } -} diff --git a/SpotifyAPI/Web/SimpleHttpServer.cs b/SpotifyAPI/Web/SimpleHttpServer.cs deleted file mode 100644 index 7c1563af..00000000 --- a/SpotifyAPI/Web/SimpleHttpServer.cs +++ /dev/null @@ -1,370 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Web; - -// offered to the public domain for any use with no restriction -// and also with no warranty of any kind, please enjoy. - David Jeske. - -// simple HTTP explanation -// http://www.jmarshall.com/easy/http/ - -namespace SpotifyAPI.Web -{ - public class HttpProcessor : IDisposable - { - private const int MaxPostSize = 10 * 1024 * 1024; // 10MB - private const int BufSize = 4096; - private readonly HttpServer _srv; - private Stream _inputStream; - private readonly Hashtable _httpHeaders = new Hashtable(); - private string _httpMethod; - public string HttpProtocolVersionstring; - public string HttpUrl; - public StreamWriter OutputStream; - - public HttpProcessor(HttpServer srv) - { - _srv = srv; - } - - private string[] GetIncomingRequest(Stream inputStream) - { - var buffer = new byte[4096]; - var read = inputStream.Read(buffer, 0, buffer.Length); - - var inputData = Encoding.ASCII.GetString(buffer.Take(read).ToArray()); - return inputData.Split('\n').Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)).ToArray(); - } - - public void Process(TcpClient socket) - { - // we can't use a StreamReader for input, because it buffers up extra data on us inside it's - // "processed" view of the world, and we want the data raw after the headers - _inputStream = new BufferedStream(socket.GetStream()); - - // we probably shouldn't be using a streamwriter for all output from handlers either - OutputStream = new StreamWriter(new BufferedStream(socket.GetStream())); - try - { - var requestLines = GetIncomingRequest(_inputStream); - - ParseRequest(requestLines.First()); - ReadHeaders(requestLines.Skip(1)); - - if (_httpMethod.Equals("GET")) - { - HandleGetRequest(); - } - else if (_httpMethod.Equals("POST")) - { - HandlePostRequest(); - } - } - catch (Exception) - { - WriteFailure(); - } - OutputStream.Flush(); - _inputStream = null; - OutputStream = null; - } - - public void ParseRequest(string request) - { - string[] tokens = request.Split(' '); - if (tokens.Length < 2) - { - throw new Exception("Invalid HTTP request line"); - } - _httpMethod = tokens[0].ToUpper(); - HttpUrl = tokens[1]; - } - - public void ReadHeaders(IEnumerable requestLines) - { - foreach(var line in requestLines) - { - if (string.IsNullOrEmpty(line)) - { - return; - } - - int separator = line.IndexOf(':'); - if (separator == -1) - { - throw new Exception("Invalid HTTP header line: " + line); - } - string name = line.Substring(0, separator); - int pos = separator + 1; - while ((pos < line.Length) && (line[pos] == ' ')) - { - pos++; // strip any spaces - } - - string value = line.Substring(pos, line.Length - pos); - _httpHeaders[name] = value; - } - } - - public void HandleGetRequest() - { - _srv.HandleGetRequest(this); - } - - public void HandlePostRequest() - { - // this post data processing just reads everything into a memory stream. - // this is fine for smallish things, but for large stuff we should really - // hand an input stream to the request processor. However, the input stream - // we hand him needs to let him see the "end of the stream" at this content - // length, because otherwise he won't know when he's seen it all! - - MemoryStream ms = new MemoryStream(); - if (_httpHeaders.ContainsKey("Content-Length")) - { - var contentLen = Convert.ToInt32(_httpHeaders["Content-Length"]); - if (contentLen > MaxPostSize) - { - throw new Exception($"POST Content-Length({contentLen}) too big for this simple server"); - } - byte[] buf = new byte[BufSize]; - int toRead = contentLen; - while (toRead > 0) - { - int numread = _inputStream.Read(buf, 0, Math.Min(BufSize, toRead)); - if (numread == 0) - { - if (toRead == 0) - { - break; - } - throw new Exception("Client disconnected during post"); - } - toRead -= numread; - ms.Write(buf, 0, numread); - } - ms.Seek(0, SeekOrigin.Begin); - } - _srv.HandlePostRequest(this, new StreamReader(ms)); - } - - public void WriteSuccess(string contentType = "text/html") - { - OutputStream.WriteLine("HTTP/1.0 200 OK"); - OutputStream.WriteLine("Content-Type: " + contentType); - OutputStream.WriteLine("Connection: close"); - OutputStream.WriteLine(""); - } - - public void WriteFailure() - { - OutputStream.WriteLine("HTTP/1.0 404 File not found"); - OutputStream.WriteLine("Connection: close"); - OutputStream.WriteLine(""); - } - - public void Dispose() - { - - } - } - - public abstract class HttpServer : IDisposable - { - private TcpListener _listener; - protected int Port; - - protected HttpServer(int port) - { - IsActive = true; - Port = port; - } - - public bool IsActive { get; set; } - - public void Dispose() - { - IsActive = false; - _listener.Stop(); - GC.SuppressFinalize(this); - } - - public void Listen() - { - try - { - _listener = new TcpListener(IPAddress.Any, Port); - _listener.Start(); - - _listener.BeginAcceptTcpClient(AcceptTcpConnection, _listener); - - } - catch (SocketException e) - { - if (e.ErrorCode != 10004) //Ignore 10004, which is thrown when the thread gets terminated - throw; - } - } - - private void AcceptTcpConnection(IAsyncResult ar) - { - TcpListener listener = (TcpListener)ar.AsyncState; - try - { - var tcpCLient = listener.EndAcceptTcpClient(ar); - using (HttpProcessor processor = new HttpProcessor(this)) - { - processor.Process(tcpCLient); - } - } - catch (ObjectDisposedException) - { - // Ignore - } - - if (!IsActive) - return; - //listener.Start(); - listener.BeginAcceptTcpClient(AcceptTcpConnection, listener); - } - - public abstract void HandleGetRequest(HttpProcessor p); - - public abstract void HandlePostRequest(HttpProcessor p, StreamReader inputData); - } - - public class AuthEventArgs - { - //Code can be an AccessToken or an Exchange Code - public string Code { get; set; } - - public string TokenType { get; set; } - public string State { get; set; } - public string Error { get; set; } - public int ExpiresIn { get; set; } - } - - public class SimpleHttpServer : HttpServer - { - private readonly AuthType _type; - - public delegate void AuthEventHandler(AuthEventArgs e); - - public event AuthEventHandler OnAuth; - - public SimpleHttpServer(int port, AuthType type) : base(port) - { - _type = type; - } - - public override void HandleGetRequest(HttpProcessor p) - { - p.WriteSuccess(); - if (p.HttpUrl == "/favicon.ico") - return; - - Thread t; - if (_type == AuthType.Authorization) - { - string url = p.HttpUrl; - url = url.Substring(2, url.Length - 2); - NameValueCollection col = HttpUtility.ParseQueryString(url); - if (col.Keys.Get(0) != "code") - { - p.OutputStream.WriteLine("

Spotify Auth canceled!

"); - t = new Thread(o => - { - OnAuth?.Invoke(new AuthEventArgs() - { - State = col.Get(1), - Error = col.Get(0), - }); - }); - } - else - { - p.OutputStream.WriteLine("

Spotify Auth successful!

"); - t = new Thread(o => - { - OnAuth?.Invoke(new AuthEventArgs() - { - Code = col.Get(0), - State = col.Get(1) - }); - }); - } - } - else - { - if (p.HttpUrl == "/") - { - p.OutputStream.WriteLine("" + - "" + - "

Spotify Auth successful!
Please copy the URL and paste it into the application

"); - p.OutputStream.Flush(); - p.OutputStream.Close(); - return; - } - string url = p.HttpUrl; - url = url.Substring(2, url.Length - 2); - NameValueCollection col = HttpUtility.ParseQueryString(url); - if (col.Keys.Get(0) != "access_token") - { - p.OutputStream.WriteLine("

Spotify Auth canceled!

"); - t = new Thread(o => - { - OnAuth?.Invoke(new AuthEventArgs() - { - Error = col.Get(0), - State = col.Get(1) - }); - }); - } - else - { - p.OutputStream.WriteLine("

Spotify Auth successful!

"); - t = new Thread(o => - { - OnAuth?.Invoke(new AuthEventArgs() - { - Code = col.Get(0), - TokenType = col.Get(1), - ExpiresIn = Convert.ToInt32(col.Get(2)), - State = col.Get(3) - }); - }); - p.OutputStream.Flush(); - p.OutputStream.Close(); - } - } - - - t.Start(); - } - - public override void HandlePostRequest(HttpProcessor p, StreamReader inputData) - { - p.WriteSuccess(); - } - } - - public enum AuthType - { - Implicit, - Authorization - } -} \ No newline at end of file diff --git a/SpotifyAPI/app.config b/SpotifyAPI/app.config deleted file mode 100644 index 49cc43e1..00000000 --- a/SpotifyAPI/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/SpotifyAPI/packages.config b/SpotifyAPI/packages.config deleted file mode 100644 index ee51c237..00000000 --- a/SpotifyAPI/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/SpotifyAPI/publish.cmd b/SpotifyAPI/publish.cmd deleted file mode 100644 index 4af64632..00000000 --- a/SpotifyAPI/publish.cmd +++ /dev/null @@ -1,12 +0,0 @@ -if "%APPVEYOR_REPO_TAG%" == "true" ( -echo Publishing... - -cd ./SpotifyAPI - -nuget pack ./SpotifyAPI.nuspec -Version %APPVEYOR_REPO_TAG_NAME% -nuget push ./SpotifyAPI-NET.%APPVEYOR_REPO_TAG_NAME%.nupkg -ApiKey %NUGET_TOKEN% -NonInteractive -Source https://www.nuget.org/api/v2/package -cd ../ - -) else ( - echo Skipping Publishing -)