aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Providers')
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs17
-rw-r--r--MediaBrowser.Providers/MediaBrowser.Providers.csproj6
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Api/ListenBrainzLabsClient.cs128
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistData.cs28
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistsResponse.cs16
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/ListenBrainz_logo.svg60
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/NOTICE.md23
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/PluginConfiguration.cs65
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithm.cs37
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithmExtensions.cs23
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/config.html109
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzPlugin.cs64
-rw-r--r--MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzSimilarArtistProvider.cs89
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs5
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html15
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieSimilarProvider.cs96
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesSimilarProvider.cs96
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs48
18 files changed, 924 insertions, 1 deletions
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 65edcb2a92..73df6d03d2 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -1,17 +1,20 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Mime;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using AsyncKeyedLock;
using Jellyfin.Data.Enums;
using Jellyfin.Data.Events;
using Jellyfin.Extensions;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.BaseItemManager;
@@ -64,6 +67,7 @@ namespace MediaBrowser.Providers.Manager
private readonly PriorityQueue<(Guid ItemId, MetadataRefreshOptions RefreshOptions), RefreshPriority> _refreshQueue = new();
private readonly IMemoryCache _memoryCache;
private readonly IMediaSegmentManager _mediaSegmentManager;
+ private readonly ISimilarItemsManager _similarItemsManager;
private readonly AsyncKeyedLocker<string> _imageSaveLock = new(o =>
{
o.PoolSize = 20;
@@ -101,6 +105,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="lyricManager">The lyric manager.</param>
/// <param name="memoryCache">The memory cache.</param>
/// <param name="mediaSegmentManager">The media segment manager.</param>
+ /// <param name="similarItemsManager">The similar items manager.</param>
public ProviderManager(
IHttpClientFactory httpClientFactory,
ISubtitleManager subtitleManager,
@@ -113,7 +118,8 @@ namespace MediaBrowser.Providers.Manager
IBaseItemManager baseItemManager,
ILyricManager lyricManager,
IMemoryCache memoryCache,
- IMediaSegmentManager mediaSegmentManager)
+ IMediaSegmentManager mediaSegmentManager,
+ ISimilarItemsManager similarItemsManager)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
@@ -127,6 +133,7 @@ namespace MediaBrowser.Providers.Manager
_lyricManager = lyricManager;
_memoryCache = memoryCache;
_mediaSegmentManager = mediaSegmentManager;
+ _similarItemsManager = similarItemsManager;
CollectionFolder.LibraryOptionsUpdated += OnLibraryOptionsUpdated;
}
@@ -687,6 +694,14 @@ namespace MediaBrowser.Providers.Manager
Type = MetadataPluginType.MediaSegmentProvider
}));
+ // Similar items providers
+ var similarItemsProviders = _similarItemsManager.GetSimilarItemsProviders<T>();
+ pluginList.AddRange(similarItemsProviders.Select(i => new MetadataPlugin
+ {
+ Name = i.Name,
+ Type = i.Type
+ }));
+
summary.Plugins = pluginList.ToArray();
var supportedImageTypes = imageProviders.OfType<IRemoteImageProvider>()
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index ed0c63b97f..8b727a8cac 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -52,6 +52,12 @@
<EmbeddedResource Include="Plugins\AudioDb\Configuration\config.html" />
<None Remove="Plugins\Omdb\Configuration\config.html" />
<EmbeddedResource Include="Plugins\Omdb\Configuration\config.html" />
+ <None Remove="Plugins\ListenBrainz\Configuration\config.html" />
+ <EmbeddedResource Include="Plugins\ListenBrainz\Configuration\config.html" />
+ <None Remove="Plugins\ListenBrainz\Configuration\ListenBrainz_logo.svg" />
+ <EmbeddedResource Include="Plugins\ListenBrainz\Configuration\ListenBrainz_logo.svg" />
+ <None Remove="Plugins\ListenBrainz\Configuration\NOTICE.md" />
+ <EmbeddedResource Include="Plugins\ListenBrainz\Configuration\NOTICE.md" />
<None Remove="Plugins\MusicBrainz\Configuration\config.html" />
<EmbeddedResource Include="Plugins\MusicBrainz\Configuration\config.html" />
<None Remove="Plugins\StudioImages\Configuration\config.html" />
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Api/ListenBrainzLabsClient.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/ListenBrainzLabsClient.cs
new file mode 100644
index 0000000000..e080370b8c
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/ListenBrainzLabsClient.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Providers.Plugins.ListenBrainz.Api.Models;
+using MediaBrowser.Providers.Plugins.ListenBrainz.Configuration;
+using Microsoft.Extensions.Logging;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Api;
+
+/// <summary>
+/// Client for the ListenBrainz Labs API.
+/// </summary>
+public class ListenBrainzLabsClient : IDisposable
+{
+ private readonly IHttpClientFactory _httpClientFactory;
+ private readonly ILogger<ListenBrainzLabsClient> _logger;
+ private readonly SemaphoreSlim _rateLimitLock = new(1, 1);
+
+ private DateTime _lastRequestTime = DateTime.MinValue;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ListenBrainzLabsClient"/> class.
+ /// </summary>
+ /// <param name="httpClientFactory">The HTTP client factory.</param>
+ /// <param name="logger">The logger.</param>
+ public ListenBrainzLabsClient(
+ IHttpClientFactory httpClientFactory,
+ ILogger<ListenBrainzLabsClient> logger)
+ {
+ _httpClientFactory = httpClientFactory;
+ _logger = logger;
+ }
+
+ /// <summary>
+ /// Gets similar artists for the given MusicBrainz artist ID.
+ /// </summary>
+ /// <param name="artistMbid">The MusicBrainz artist ID.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>A list of similar artist MusicBrainz IDs ordered by similarity score.</returns>
+ public async Task<IReadOnlyList<Guid>> GetSimilarArtistsAsync(
+ Guid artistMbid,
+ CancellationToken cancellationToken)
+ {
+ var config = ListenBrainzPlugin.Instance?.Configuration;
+ var baseUrl = config?.LabsServer ?? PluginConfiguration.DefaultLabsServer;
+ var algorithm = config?.AlgorithmString ?? new PluginConfiguration().AlgorithmString;
+ var rateLimit = config?.RateLimit ?? PluginConfiguration.DefaultRateLimit;
+
+ // Enforce rate limit
+ await EnforceRateLimitAsync(rateLimit, cancellationToken).ConfigureAwait(false);
+
+ var url = $"{baseUrl}/similar-artists/json?artist_mbids={artistMbid}&algorithm={algorithm}";
+
+ _logger.LogDebug("Fetching similar artists from ListenBrainz Labs: {Url}", url);
+
+ try
+ {
+ var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
+ var response = await httpClient.GetFromJsonAsync<List<SimilarArtistData>>(url, cancellationToken).ConfigureAwait(false);
+
+ if (response is null || response.Count == 0)
+ {
+ _logger.LogDebug("No similar artists found for {ArtistMbid}", artistMbid);
+ return [];
+ }
+
+ var similarMbids = response
+ .Where(a => !a.ArtistMbid.Equals(artistMbid)) // Exclude the source artist
+ .OrderByDescending(a => a.Score)
+ .Select(a => a.ArtistMbid)
+ .ToList();
+
+ _logger.LogDebug("Found {Count} similar artists for {ArtistMbid}", similarMbids.Count, artistMbid);
+
+ return similarMbids;
+ }
+ catch (HttpRequestException ex)
+ {
+ _logger.LogWarning(ex, "Failed to fetch similar artists from ListenBrainz Labs for {ArtistMbid}", artistMbid);
+ return [];
+ }
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _rateLimitLock.Dispose();
+ }
+ }
+
+ private async Task EnforceRateLimitAsync(double rateLimitSeconds, CancellationToken cancellationToken)
+ {
+ await _rateLimitLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+ try
+ {
+ var timeSinceLastRequest = DateTime.UtcNow - _lastRequestTime;
+ var requiredDelay = TimeSpan.FromSeconds(rateLimitSeconds) - timeSinceLastRequest;
+
+ if (requiredDelay > TimeSpan.Zero)
+ {
+ await Task.Delay(requiredDelay, cancellationToken).ConfigureAwait(false);
+ }
+
+ _lastRequestTime = DateTime.UtcNow;
+ }
+ finally
+ {
+ _rateLimitLock.Release();
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistData.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistData.cs
new file mode 100644
index 0000000000..237f33ee3a
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistData.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Text.Json.Serialization;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Api.Models;
+
+/// <summary>
+/// A similar artist data entry from the ListenBrainz Labs API.
+/// </summary>
+public class SimilarArtistData
+{
+ /// <summary>
+ /// Gets or sets the MusicBrainz artist ID.
+ /// </summary>
+ [JsonPropertyName("artist_mbid")]
+ public Guid ArtistMbid { get; set; }
+
+ /// <summary>
+ /// Gets or sets the artist name.
+ /// </summary>
+ [JsonPropertyName("name")]
+ public string? Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the similarity score.
+ /// </summary>
+ [JsonPropertyName("score")]
+ public double Score { get; set; }
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistsResponse.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistsResponse.cs
new file mode 100644
index 0000000000..12e8f25dcc
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Api/Models/SimilarArtistsResponse.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Api.Models;
+
+/// <summary>
+/// Response from ListenBrainz Labs similar-artists endpoint.
+/// </summary>
+public class SimilarArtistsResponse
+{
+ /// <summary>
+ /// Gets or sets the list of similar artists.
+ /// </summary>
+ [JsonPropertyName("data")]
+ public IReadOnlyList<SimilarArtistData>? Data { get; set; }
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/ListenBrainz_logo.svg b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/ListenBrainz_logo.svg
new file mode 100644
index 0000000000..416a097f9c
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/ListenBrainz_logo.svg
@@ -0,0 +1,60 @@
+<svg version="1.2" baseProfile="tiny-ps" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 450" width="800" height="450">
+ <title>ListenBrainz_logo-svg</title>
+ <defs>
+ <image width="800" height="450" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAHCAQMAAAAtrT+LAAAAAXNSR0IB2cksfwAAAANQTFRF9tmZzxpnDgAAAENJREFUeJztwYEAAAAAw6D5U1/hAFUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALwGsYoAAQbjkYoAAAAASUVORK5CYII="/>
+ <clipPath clipPathUnits="userSpaceOnUse" id="cp1">
+ <path d="M173.35 178.24L224.79 178.24L224.79 269.03L173.35 269.03L173.35 178.24Z" />
+ </clipPath>
+ <clipPath clipPathUnits="userSpaceOnUse" id="cp2">
+ <path d="M173.35 178.24L224.79 178.24L224.79 269.03L173.35 269.03L173.35 178.24Z" />
+ </clipPath>
+ <clipPath clipPathUnits="userSpaceOnUse" id="cp3">
+ <path d="M173.35 178.24L224.79 178.24L224.79 269.03L173.35 269.03L173.35 178.24Z" />
+ </clipPath>
+ </defs>
+ <style>
+ tspan { white-space:pre }
+ .shp0 { fill: #eb743b }
+ .shp1 { fill: #353070 }
+ .shp2 { fill: #000000 }
+ .shp3 { fill: #d3562c }
+ .shp4 { fill: #fffedb }
+ .shp5 { opacity: 0.251;fill: #000000 }
+ </style>
+ <use id="Background" href="#img1" x="0" y="0" />
+ <path id="Layer" class="shp0" d="M173.35 152.82L173.35 296.82L234.35 261.82L234.35 187.82L173.35 152.82Z" />
+ <path id="Layer" class="shp1" d="M168.35 152.82L107.35 187.82L107.35 261.82L168.35 296.82L168.35 152.82Z" />
+ <g id="Layer" style="opacity: 0.071">
+ <g id="Clip-Path" clip-path="url(#cp1)">
+ <path id="Layer" class="shp2" d="M190.66 244.56C190.75 244.4 190.86 244.26 190.99 244.13C191.12 244 191.27 243.89 191.43 243.8C191.59 243.71 191.76 243.64 191.93 243.59C192.11 243.55 192.29 243.53 192.48 243.53C192.85 243.53 193.23 243.63 193.55 243.82C193.79 243.97 194 244.15 194.17 244.38C194.33 244.6 194.45 244.85 194.52 245.12C194.59 245.39 194.6 245.67 194.56 245.94C194.52 246.22 194.43 246.48 194.29 246.72C194.2 246.88 194.08 247.02 193.95 247.15C193.82 247.28 193.68 247.39 193.52 247.48C193.36 247.57 193.19 247.64 193.01 247.69C192.84 247.73 192.65 247.75 192.47 247.75C192.09 247.75 191.72 247.65 191.39 247.45C191.27 247.38 191.16 247.3 191.05 247.21C190.95 247.12 190.86 247.01 190.78 246.9C190.69 246.79 190.62 246.67 190.56 246.55C190.5 246.42 190.46 246.29 190.42 246.16C190.39 246.02 190.37 245.89 190.36 245.75C190.35 245.61 190.36 245.47 190.38 245.33C190.4 245.2 190.43 245.06 190.48 244.93C190.53 244.8 190.59 244.68 190.66 244.56M203.26 266.92C203.05 267.1 202.8 267.24 202.54 267.32C202.28 267.41 202 267.44 201.72 267.42C201.45 267.4 201.18 267.33 200.93 267.2C200.68 267.08 200.46 266.9 200.28 266.69C200.1 266.48 199.96 266.24 199.87 265.97C199.79 265.71 199.76 265.43 199.78 265.16C199.8 264.88 199.87 264.61 200 264.36C200.13 264.11 200.3 263.89 200.51 263.71C200.6 263.63 200.7 263.56 200.81 263.49C200.92 263.43 201.03 263.38 201.15 263.33C201.27 263.29 201.39 263.26 201.51 263.23C201.63 263.21 201.76 263.2 201.88 263.2C202.17 263.2 202.46 263.26 202.73 263.38C203 263.5 203.24 263.67 203.43 263.88C203.63 264.09 203.78 264.35 203.88 264.62C203.98 264.9 204.01 265.19 203.99 265.48C203.98 265.62 203.96 265.75 203.92 265.89C203.88 266.02 203.83 266.15 203.77 266.27C203.71 266.4 203.63 266.51 203.55 266.62C203.46 266.73 203.36 266.83 203.26 266.92M193.73 208.08C193.88 207.85 194.08 207.65 194.3 207.49C194.53 207.33 194.79 207.21 195.06 207.15C195.33 207.09 195.61 207.09 195.88 207.13C196.15 207.18 196.41 207.28 196.65 207.42C196.88 207.57 197.09 207.77 197.25 207.99C197.41 208.22 197.52 208.48 197.58 208.75C197.64 209.02 197.65 209.3 197.6 209.57C197.56 209.85 197.46 210.11 197.31 210.34C197.16 210.58 196.97 210.78 196.74 210.94C196.51 211.1 196.26 211.22 195.99 211.28C195.72 211.34 195.44 211.35 195.16 211.3C194.89 211.25 194.63 211.15 194.39 211C194.16 210.85 193.95 210.66 193.79 210.43C193.63 210.21 193.52 209.95 193.46 209.68C193.4 209.41 193.39 209.13 193.44 208.85C193.49 208.58 193.59 208.32 193.73 208.08ZM200.11 187.89C199.51 188.84 198.18 189.16 197.2 188.55L197.1 188.48C196.89 188.33 196.7 188.13 196.55 187.91C196.41 187.68 196.31 187.43 196.26 187.17C196.21 186.91 196.2 186.64 196.25 186.37C196.3 186.11 196.4 185.86 196.55 185.63C196.64 185.48 196.76 185.35 196.88 185.22C197.01 185.1 197.16 185 197.31 184.91C197.47 184.83 197.63 184.76 197.81 184.72C197.98 184.67 198.15 184.65 198.33 184.65C198.71 184.65 199.08 184.75 199.41 184.95C199.73 185.14 200 185.42 200.18 185.75C200.36 186.08 200.45 186.45 200.44 186.83C200.43 187.21 200.32 187.57 200.11 187.89M216.88 199.49C216.97 199.34 217.09 199.2 217.22 199.08C217.35 198.96 217.49 198.86 217.64 198.77C217.8 198.68 217.97 198.62 218.14 198.58C218.31 198.53 218.49 198.51 218.66 198.51C219.06 198.51 219.45 198.62 219.79 198.84C220.27 199.14 220.6 199.61 220.72 200.17C220.76 200.3 220.77 200.44 220.78 200.58C220.78 200.71 220.77 200.85 220.74 200.99C220.72 201.12 220.68 201.25 220.63 201.38C220.58 201.51 220.52 201.63 220.44 201.75C219.85 202.7 218.51 203.02 217.53 202.4L217.44 202.34C217.22 202.19 217.03 201.99 216.89 201.77C216.74 201.54 216.64 201.29 216.59 201.03C216.54 200.77 216.54 200.49 216.59 200.23C216.64 199.97 216.74 199.72 216.88 199.49M216.88 222.95C216.97 222.8 217.09 222.67 217.22 222.54C217.35 222.42 217.49 222.32 217.64 222.23C217.8 222.15 217.97 222.08 218.14 222.04C218.31 222 218.49 221.97 218.66 221.97C219.06 221.97 219.45 222.09 219.79 222.3C220.27 222.6 220.6 223.07 220.72 223.63C220.76 223.76 220.77 223.9 220.78 224.04C220.78 224.18 220.77 224.31 220.74 224.45C220.72 224.59 220.68 224.72 220.63 224.85C220.58 224.98 220.52 225.1 220.44 225.21C219.85 226.16 218.51 226.48 217.53 225.87L217.44 225.8C217.22 225.65 217.03 225.45 216.89 225.23C216.74 225 216.64 224.75 216.59 224.49C216.54 224.23 216.54 223.96 216.59 223.69C216.64 223.43 216.74 223.18 216.88 222.95M216.88 249.26C216.97 249.11 217.09 248.97 217.22 248.85C217.35 248.73 217.49 248.62 217.64 248.54C217.8 248.45 217.97 248.39 218.14 248.34C218.31 248.3 218.49 248.28 218.66 248.28C219.06 248.28 219.45 248.39 219.79 248.6C220.27 248.91 220.6 249.38 220.72 249.93C220.76 250.07 220.77 250.2 220.78 250.34C220.78 250.48 220.77 250.62 220.74 250.75C220.72 250.89 220.68 251.02 220.63 251.15C220.58 251.28 220.52 251.4 220.44 251.52C219.85 252.47 218.51 252.79 217.53 252.17L217.44 252.11C217.22 251.95 217.03 251.76 216.89 251.53C216.74 251.31 216.64 251.06 216.59 250.79C216.54 250.53 216.54 250.26 216.59 250C216.64 249.73 216.74 249.48 216.88 249.26" />
+ </g>
+ <g id="Clip-Path" clip-path="url(#cp2)">
+ <path id="Layer" fill-rule="evenodd" class="shp2" d="M206.53 258.93C206.79 259.23 207.02 259.56 207.22 259.91C207.42 260.26 207.58 260.63 207.71 261.01C207.83 261.39 207.92 261.78 207.96 262.18C208.01 262.58 208.02 262.98 207.99 263.38C207.96 263.78 207.89 264.17 207.78 264.56C207.67 264.95 207.53 265.32 207.35 265.68C207.17 266.04 206.95 266.38 206.7 266.69C206.45 267.01 206.17 267.3 205.87 267.56C205.59 267.79 205.3 268 204.99 268.19C204.68 268.37 204.35 268.52 204.01 268.65C203.67 268.78 203.32 268.87 202.96 268.94C202.61 269 202.25 269.03 201.89 269.03C201.49 269.03 201.1 268.99 200.71 268.92C200.32 268.84 199.94 268.73 199.57 268.58C199.21 268.43 198.85 268.24 198.52 268.02C198.19 267.81 197.88 267.56 197.6 267.28C195.75 267.98 192.69 269 190.58 269C190.48 269 190.37 269 190.27 269C188.3 268.89 187.03 268.03 186.01 267.34C184.44 266.28 182.95 265.27 177.6 266.63C175.24 267.71 173.63 267.79 173.36 267.82L173.36 263.82C173.86 263.72 174.73 263.55 175.91 263.01C175.94 263 175.97 262.98 176 262.97C176.03 262.95 176.06 262.94 176.09 262.92C176.12 262.91 176.15 262.89 176.18 262.88C176.21 262.87 176.24 262.86 176.27 262.85C179.62 261.24 184.79 257.38 188.84 248.16C188.56 247.95 188.29 247.72 188.05 247.47C187.8 247.22 187.58 246.94 187.39 246.65C187.19 246.36 187.02 246.05 186.88 245.73C186.74 245.41 186.62 245.07 186.54 244.73C186.44 244.34 186.38 243.95 186.36 243.55C186.33 243.15 186.35 242.74 186.41 242.35C186.47 241.95 186.57 241.56 186.7 241.18C186.84 240.8 187.01 240.44 187.22 240.1C187.49 239.64 187.82 239.23 188.19 238.86C188.57 238.49 188.99 238.17 189.45 237.91C189.91 237.65 190.4 237.45 190.91 237.32C191.42 237.18 191.95 237.11 192.48 237.11C192.75 237.11 193.02 237.13 193.3 237.17C193.57 237.2 193.84 237.26 194.1 237.33C194.37 237.4 194.62 237.5 194.88 237.6C195.13 237.71 195.37 237.83 195.61 237.97C198.51 239.71 199.46 243.47 197.73 246.37C197.47 246.8 197.16 247.21 196.79 247.56C196.43 247.92 196.03 248.23 195.59 248.49C195.15 248.75 194.68 248.95 194.2 249.1C193.71 249.24 193.2 249.32 192.69 249.34C190.12 255.34 187.05 259.41 184.11 262.18C185.84 262.51 187.09 263.23 188.26 264.02C189.18 264.65 189.66 264.95 190.48 264.99C191.55 265.03 193.86 264.36 195.81 263.66C195.75 263.16 195.75 262.66 195.81 262.16C195.87 261.66 196 261.17 196.18 260.7C196.36 260.23 196.6 259.79 196.89 259.38C197.18 258.97 197.52 258.59 197.9 258.26C198.51 257.74 199.22 257.34 199.98 257.09C200.74 256.84 201.55 256.74 202.35 256.8C203.15 256.87 203.94 257.08 204.65 257.45C205.37 257.81 206.01 258.32 206.53 258.93ZM190.66 242.15C190.59 242.27 190.53 242.4 190.48 242.53C190.43 242.66 190.4 242.79 190.38 242.93C190.36 243.07 190.35 243.2 190.36 243.34C190.37 243.48 190.39 243.62 190.42 243.75C190.46 243.89 190.5 244.02 190.56 244.14C190.62 244.27 190.69 244.39 190.78 244.5C190.86 244.61 190.95 244.71 191.05 244.8C191.16 244.89 191.27 244.98 191.39 245.05C191.72 245.24 192.09 245.35 192.47 245.35C192.65 245.35 192.84 245.33 193.01 245.28C193.19 245.23 193.36 245.16 193.52 245.07C193.68 244.98 193.82 244.87 193.95 244.75C194.08 244.62 194.2 244.47 194.29 244.32C194.58 243.83 194.66 243.26 194.52 242.71C194.38 242.17 194.04 241.7 193.56 241.42C193.07 241.13 192.5 241.05 191.95 241.18C191.41 241.32 190.94 241.67 190.66 242.15ZM203.26 264.51C203.36 264.42 203.46 264.32 203.55 264.22C203.63 264.11 203.71 263.99 203.77 263.87C203.83 263.74 203.88 263.62 203.92 263.48C203.96 263.35 203.98 263.21 203.99 263.07C204.01 262.78 203.98 262.49 203.88 262.22C203.78 261.94 203.63 261.69 203.43 261.47C203.24 261.26 203 261.09 202.73 260.97C202.46 260.86 202.17 260.8 201.88 260.8C201.76 260.8 201.63 260.81 201.51 260.83C201.39 260.85 201.27 260.88 201.15 260.93C201.03 260.97 200.92 261.02 200.81 261.09C200.7 261.15 200.6 261.23 200.51 261.31C200.3 261.49 200.13 261.71 200 261.96C199.87 262.2 199.8 262.47 199.78 262.75C199.76 263.03 199.79 263.31 199.87 263.57C199.96 263.83 200.1 264.08 200.28 264.29C200.46 264.5 200.68 264.67 200.93 264.8C201.18 264.92 201.45 265 201.72 265.02C202 265.04 202.28 265 202.54 264.92C202.8 264.83 203.05 264.69 203.26 264.51ZM204.3 183.03C204.39 183.42 204.44 183.82 204.45 184.22C204.46 184.62 204.43 185.02 204.36 185.41C204.3 185.8 204.19 186.19 204.04 186.56C203.9 186.94 203.72 187.29 203.5 187.63C203.23 188.07 202.9 188.47 202.52 188.82C202.15 189.17 201.73 189.48 201.28 189.72C200.83 189.97 200.35 190.16 199.85 190.29C199.36 190.42 198.84 190.48 198.33 190.48C198.18 190.48 198.03 190.47 197.88 190.46C197.73 190.45 197.58 190.43 197.43 190.41C197.29 190.39 197.14 190.36 196.99 190.33C196.85 190.29 196.7 190.26 196.56 190.21C194.18 193.04 191.3 194.53 188.78 195.31C190.8 196.86 192.59 198.72 194.12 200.88C195.7 200.52 197.41 200.76 198.79 201.63C201.65 203.44 202.5 207.23 200.7 210.08C200.42 210.52 200.09 210.92 199.72 211.27C199.34 211.63 198.93 211.93 198.47 212.18C198.02 212.43 197.54 212.62 197.04 212.74C196.54 212.87 196.03 212.94 195.52 212.93C194.36 212.93 193.23 212.61 192.25 211.98C189.4 210.18 188.55 206.39 190.34 203.54C190.37 203.49 190.4 203.45 190.43 203.4C190.46 203.36 190.49 203.31 190.53 203.27C190.56 203.22 190.59 203.18 190.62 203.13C190.66 203.09 190.69 203.04 190.72 203C188.45 199.89 185.56 197.52 182.12 195.96C182.11 195.96 182.11 195.96 182.1 195.96C178.91 194.5 175.8 193.96 173.35 193.82L173.35 189.82C176.13 189.98 179.67 190.54 183.36 192.14C184.59 192.16 189.66 191.97 193.3 187.85C192.96 187.36 192.69 186.82 192.51 186.25C192.32 185.68 192.22 185.09 192.21 184.49C192.2 183.89 192.27 183.3 192.43 182.72C192.59 182.14 192.84 181.59 193.16 181.09C193.43 180.65 193.76 180.25 194.13 179.9C194.51 179.55 194.92 179.24 195.38 178.99C195.83 178.74 196.31 178.55 196.81 178.43C197.3 178.3 197.82 178.24 198.33 178.24C198.62 178.24 198.91 178.26 199.19 178.3C199.47 178.34 199.76 178.4 200.03 178.48C200.31 178.56 200.58 178.66 200.84 178.78C201.1 178.89 201.35 179.03 201.6 179.18C201.94 179.4 202.26 179.64 202.55 179.92C202.84 180.2 203.1 180.5 203.34 180.83C203.57 181.16 203.77 181.51 203.93 181.88C204.09 182.25 204.22 182.63 204.3 183.03ZM193.73 205.67C193.59 205.91 193.49 206.17 193.44 206.45C193.39 206.72 193.4 207 193.46 207.27C193.52 207.54 193.63 207.8 193.79 208.03C193.95 208.25 194.16 208.45 194.39 208.6C194.63 208.75 194.89 208.85 195.16 208.89C195.44 208.94 195.72 208.93 195.99 208.87C196.26 208.81 196.51 208.7 196.74 208.54C196.97 208.38 197.16 208.17 197.31 207.94C197.46 207.7 197.56 207.44 197.6 207.17C197.65 206.89 197.64 206.61 197.58 206.34C197.52 206.07 197.41 205.81 197.25 205.59C197.09 205.36 196.88 205.17 196.65 205.02C196.41 204.87 196.15 204.77 195.88 204.73C195.61 204.68 195.33 204.69 195.06 204.75C194.79 204.81 194.53 204.92 194.3 205.08C194.08 205.24 193.88 205.44 193.73 205.67ZM200.11 185.49C200.32 185.17 200.43 184.8 200.44 184.42C200.45 184.05 200.36 183.67 200.18 183.34C200 183.01 199.73 182.73 199.41 182.54C199.08 182.35 198.71 182.25 198.33 182.25C198.15 182.25 197.98 182.27 197.81 182.31C197.63 182.35 197.47 182.42 197.31 182.51C197.16 182.59 197.01 182.7 196.88 182.82C196.76 182.94 196.64 183.08 196.55 183.23C196.4 183.45 196.3 183.7 196.25 183.97C196.2 184.23 196.21 184.5 196.26 184.76C196.31 185.03 196.41 185.28 196.55 185.5C196.7 185.73 196.89 185.92 197.11 186.08L197.2 186.14C198.18 186.76 199.51 186.44 200.11 185.49Z" />
+ </g>
+ <g id="Clip-Path" clip-path="url(#cp3)">
+ <path id="Layer" fill-rule="evenodd" class="shp2" d="M213 224.01C210.76 224.39 209.57 225.15 208.14 226.08C206.98 226.83 205.74 227.64 203.93 228.27C208.47 231.6 214.56 237.87 217.12 242.06C217.52 241.95 217.94 241.89 218.35 241.87C218.77 241.85 219.19 241.87 219.6 241.93C220.01 242 220.42 242.11 220.81 242.25C221.2 242.4 221.58 242.58 221.93 242.81C222.27 243.02 222.59 243.27 222.88 243.55C223.17 243.82 223.44 244.13 223.67 244.46C223.9 244.79 224.1 245.14 224.26 245.51C224.43 245.88 224.55 246.26 224.64 246.65C224.73 247.04 224.78 247.44 224.79 247.84C224.8 248.24 224.77 248.64 224.7 249.03C224.63 249.43 224.52 249.81 224.38 250.19C224.23 250.56 224.05 250.92 223.83 251.25C223.56 251.69 223.23 252.09 222.86 252.44C222.48 252.8 222.07 253.1 221.62 253.35C221.16 253.6 220.68 253.79 220.19 253.92C219.69 254.04 219.17 254.11 218.66 254.1C217.5 254.1 216.37 253.78 215.39 253.16C215.26 253.07 215.18 253.02 215.11 252.97C212.46 251.1 211.75 247.47 213.49 244.71C213.59 244.56 213.69 244.42 213.8 244.28C211.13 239.63 201.64 230.6 199.03 229.96C195.63 229.11 193.67 229.18 191.18 229.27C189.73 229.32 188.08 229.39 185.97 229.27C182.89 229.11 181.2 227.19 179.71 225.49C178.15 223.71 176.65 222.12 173.36 221.82L173.36 217.82C178.5 218.2 180.92 220.79 182.72 222.85C184.08 224.39 184.85 225.2 186.18 225.27C188.12 225.37 189.6 225.32 191.03 225.27C192.77 225.2 194.36 225.15 196.32 225.38C202 225.29 203.92 224.04 205.96 222.72C207.58 221.66 209.41 220.48 212.78 219.99C212.82 219.85 212.87 219.71 212.92 219.58C212.97 219.44 213.02 219.31 213.08 219.17C213.14 219.04 213.2 218.91 213.27 218.78C213.34 218.66 213.41 218.53 213.49 218.41C213.54 218.34 213.59 218.27 213.64 218.19C213.69 218.12 213.74 218.05 213.79 217.98C213.84 217.92 213.9 217.85 213.95 217.78C214.01 217.71 214.07 217.65 214.12 217.58C214.26 217.44 214.41 217.32 214.55 217.19C213.44 213.09 213.24 207.29 214.59 202.77C214.56 202.75 214.54 202.73 214.51 202.71C213.99 202.23 213.56 201.66 213.23 201.03C212.9 200.4 212.69 199.72 212.59 199.01C212.5 198.31 212.53 197.59 212.68 196.9C212.84 196.21 213.11 195.55 213.49 194.95C213.76 194.51 214.09 194.11 214.46 193.76C214.84 193.4 215.26 193.1 215.71 192.85C216.16 192.6 216.64 192.41 217.14 192.28C217.64 192.16 218.15 192.09 218.66 192.1C218.95 192.1 219.24 192.12 219.52 192.16C219.81 192.2 220.09 192.26 220.36 192.34C220.64 192.42 220.91 192.52 221.17 192.63C221.43 192.75 221.69 192.89 221.93 193.04C222.27 193.25 222.59 193.5 222.88 193.78C223.17 194.06 223.44 194.36 223.67 194.69C223.9 195.02 224.1 195.37 224.26 195.74C224.42 196.11 224.55 196.49 224.64 196.88C224.73 197.27 224.78 197.67 224.79 198.07C224.8 198.47 224.77 198.87 224.7 199.27C224.63 199.66 224.52 200.05 224.38 200.42C224.23 200.79 224.05 201.15 223.83 201.49C223.56 201.92 223.23 202.32 222.86 202.68C222.48 203.03 222.07 203.33 221.62 203.58C221.16 203.83 220.68 204.02 220.19 204.15C219.69 204.27 219.17 204.34 218.66 204.34C218.55 204.34 218.44 204.32 218.32 204.31C217.37 207.81 217.58 212.42 218.29 215.58C218.41 215.57 218.54 215.56 218.66 215.56C218.95 215.56 219.24 215.58 219.52 215.62C219.81 215.66 220.09 215.72 220.36 215.8C220.64 215.88 220.91 215.98 221.17 216.1C221.43 216.21 221.69 216.35 221.93 216.5C222.27 216.72 222.59 216.96 222.88 217.24C223.17 217.52 223.44 217.82 223.67 218.15C223.9 218.48 224.1 218.83 224.26 219.2C224.42 219.57 224.55 219.95 224.64 220.35C224.73 220.74 224.78 221.14 224.79 221.54C224.8 221.94 224.77 222.34 224.7 222.73C224.63 223.12 224.52 223.51 224.38 223.88C224.23 224.26 224.05 224.61 223.83 224.95C223.56 225.39 223.23 225.79 222.86 226.14C222.48 226.49 222.07 226.8 221.62 227.05C221.16 227.29 220.68 227.48 220.19 227.61C219.69 227.74 219.17 227.8 218.66 227.8C218.34 227.8 218.03 227.78 217.72 227.73C217.4 227.68 217.1 227.6 216.8 227.51C216.49 227.41 216.2 227.29 215.92 227.15C215.64 227.01 215.37 226.84 215.11 226.66C214.88 226.5 214.65 226.31 214.45 226.12C214.24 225.92 214.04 225.71 213.87 225.49C213.69 225.26 213.52 225.03 213.38 224.78C213.24 224.53 213.11 224.28 213 224.01ZM216.88 197.09C216.74 197.31 216.64 197.56 216.59 197.83C216.54 198.09 216.54 198.36 216.59 198.62C216.64 198.88 216.74 199.14 216.89 199.36C217.03 199.59 217.22 199.78 217.44 199.94L217.53 200C218.51 200.62 219.85 200.3 220.44 199.34C220.52 199.23 220.58 199.11 220.63 198.98C220.68 198.85 220.72 198.72 220.74 198.58C220.77 198.44 220.78 198.31 220.78 198.17C220.77 198.03 220.76 197.89 220.73 197.76C220.6 197.2 220.27 196.73 219.79 196.43C219.45 196.22 219.06 196.1 218.66 196.1C218.49 196.1 218.31 196.13 218.14 196.17C217.97 196.21 217.8 196.28 217.64 196.36C217.49 196.45 217.35 196.55 217.22 196.68C217.09 196.8 216.97 196.93 216.88 197.09ZM216.88 220.55C216.74 220.77 216.64 221.03 216.59 221.29C216.54 221.55 216.54 221.82 216.59 222.09C216.64 222.35 216.74 222.6 216.89 222.82C217.03 223.05 217.22 223.24 217.44 223.4L217.53 223.46C218.51 224.08 219.85 223.76 220.44 222.81C220.52 222.69 220.58 222.57 220.63 222.44C220.68 222.31 220.72 222.18 220.74 222.04C220.77 221.91 220.78 221.77 220.78 221.63C220.77 221.49 220.76 221.36 220.72 221.22C220.6 220.67 220.27 220.2 219.79 219.89C219.45 219.68 219.06 219.57 218.66 219.57C218.49 219.57 218.31 219.59 218.14 219.63C217.97 219.68 217.8 219.74 217.64 219.83C217.49 219.91 217.35 220.02 217.22 220.14C217.09 220.26 216.97 220.4 216.88 220.55ZM216.88 246.85C216.74 247.08 216.64 247.33 216.59 247.59C216.54 247.86 216.54 248.13 216.59 248.39C216.64 248.65 216.74 248.9 216.89 249.13C217.03 249.35 217.22 249.55 217.44 249.7L217.53 249.76C218.51 250.38 219.85 250.06 220.44 249.11C220.52 249 220.58 248.87 220.63 248.74C220.68 248.62 220.72 248.48 220.74 248.35C220.77 248.21 220.78 248.07 220.78 247.94C220.77 247.8 220.76 247.66 220.72 247.53C220.6 246.97 220.27 246.5 219.79 246.2C219.45 245.98 219.06 245.87 218.66 245.87C218.49 245.87 218.31 245.89 218.14 245.94C217.97 245.98 217.8 246.05 217.64 246.13C217.49 246.22 217.35 246.32 217.22 246.44C217.09 246.56 216.97 246.7 216.88 246.85Z" />
+ </g>
+ </g>
+ <path id="Layer" fill-rule="evenodd" class="shp3" d="M206.53 261.93C206.79 262.23 207.02 262.56 207.22 262.91C207.42 263.26 207.58 263.63 207.71 264.01C207.83 264.39 207.92 264.78 207.96 265.18C208.01 265.58 208.02 265.98 207.99 266.38C207.96 266.78 207.89 267.17 207.78 267.56C207.67 267.95 207.53 268.32 207.35 268.68C207.17 269.04 206.95 269.38 206.7 269.69C206.45 270.01 206.17 270.3 205.87 270.56C205.59 270.79 205.3 271 204.99 271.19C204.68 271.37 204.35 271.52 204.01 271.65C203.67 271.78 203.32 271.87 202.96 271.94C202.61 272 202.25 272.03 201.89 272.03C201.49 272.03 201.1 271.99 200.71 271.92C200.32 271.84 199.94 271.73 199.57 271.58C199.21 271.43 198.85 271.24 198.52 271.02C198.19 270.81 197.88 270.56 197.6 270.28C195.75 270.98 192.69 272 190.58 272C190.48 272 190.37 272 190.27 272C188.3 271.89 187.03 271.03 186.01 270.34C184.44 269.28 182.95 268.27 177.6 269.63C175.24 270.71 173.63 270.79 173.36 270.82L173.36 266.82C173.86 266.72 174.73 266.55 175.91 266.01C175.94 266 175.97 265.98 176 265.97C176.03 265.95 176.06 265.94 176.09 265.92C176.12 265.91 176.15 265.89 176.18 265.88C176.21 265.87 176.24 265.86 176.27 265.85C179.62 264.24 184.79 260.38 188.84 251.16C188.56 250.95 188.29 250.72 188.05 250.47C187.8 250.22 187.58 249.94 187.39 249.65C187.19 249.36 187.02 249.05 186.88 248.73C186.74 248.41 186.62 248.07 186.54 247.73C186.44 247.34 186.38 246.95 186.36 246.55C186.33 246.15 186.35 245.74 186.41 245.35C186.47 244.95 186.57 244.56 186.7 244.18C186.84 243.8 187.01 243.44 187.22 243.1C187.49 242.64 187.82 242.23 188.19 241.86C188.57 241.49 188.99 241.17 189.45 240.91C189.91 240.65 190.4 240.45 190.91 240.32C191.42 240.18 191.95 240.11 192.48 240.11C192.75 240.11 193.02 240.13 193.3 240.17C193.57 240.2 193.84 240.26 194.1 240.33C194.37 240.4 194.62 240.5 194.88 240.6C195.13 240.71 195.37 240.83 195.61 240.97C198.51 242.71 199.46 246.47 197.73 249.37C197.47 249.8 197.16 250.21 196.79 250.56C196.43 250.92 196.03 251.23 195.59 251.49C195.15 251.75 194.68 251.95 194.2 252.1C193.71 252.24 193.2 252.32 192.69 252.34C190.12 258.35 187.05 262.41 184.11 265.18C185.84 265.51 187.09 266.23 188.26 267.02C189.18 267.65 189.66 267.95 190.48 267.99C191.55 268.03 193.86 267.36 195.81 266.66C195.75 266.16 195.75 265.66 195.81 265.16C195.87 264.66 196 264.17 196.18 263.7C196.36 263.23 196.6 262.79 196.89 262.38C197.18 261.97 197.52 261.59 197.9 261.26C198.51 260.74 199.22 260.34 199.98 260.09C200.74 259.84 201.55 259.74 202.35 259.8C203.15 259.87 203.94 260.08 204.65 260.45C205.37 260.81 206.01 261.32 206.53 261.93ZM190.66 245.15C190.59 245.27 190.53 245.4 190.48 245.53C190.43 245.66 190.4 245.79 190.38 245.93C190.36 246.07 190.35 246.2 190.36 246.34C190.37 246.48 190.39 246.62 190.42 246.75C190.46 246.89 190.5 247.02 190.56 247.14C190.62 247.27 190.69 247.39 190.78 247.5C190.86 247.61 190.95 247.71 191.05 247.8C191.16 247.89 191.27 247.98 191.39 248.05C191.72 248.24 192.09 248.35 192.47 248.35C192.65 248.35 192.84 248.33 193.01 248.28C193.19 248.23 193.36 248.16 193.52 248.07C193.68 247.98 193.82 247.87 193.95 247.75C194.08 247.62 194.2 247.47 194.29 247.32C194.58 246.83 194.66 246.26 194.52 245.71C194.38 245.17 194.04 244.7 193.56 244.42C193.07 244.13 192.5 244.05 191.95 244.18C191.41 244.32 190.94 244.67 190.66 245.15ZM203.26 267.51C203.36 267.42 203.46 267.32 203.55 267.22C203.63 267.11 203.71 266.99 203.77 266.87C203.83 266.74 203.88 266.62 203.92 266.48C203.96 266.35 203.98 266.21 203.99 266.07C204.01 265.78 203.98 265.49 203.88 265.22C203.78 264.94 203.63 264.69 203.43 264.47C203.24 264.26 203 264.09 202.73 263.97C202.46 263.86 202.17 263.8 201.88 263.8C201.76 263.8 201.63 263.81 201.51 263.83C201.39 263.85 201.27 263.88 201.15 263.93C201.03 263.97 200.92 264.02 200.81 264.09C200.7 264.15 200.6 264.23 200.51 264.31C200.3 264.49 200.13 264.71 200 264.96C199.87 265.2 199.8 265.47 199.78 265.75C199.76 266.03 199.79 266.31 199.87 266.57C199.96 266.83 200.1 267.08 200.28 267.29C200.46 267.5 200.68 267.67 200.93 267.8C201.18 267.92 201.45 268 201.72 268.02C202 268.04 202.28 268 202.54 267.92C202.8 267.83 203.05 267.69 203.26 267.51Z" />
+ <path id="Layer" class="shp2" d="" />
+ <path id="Layer" fill-rule="evenodd" class="shp3" d="M204.3 185.03C204.39 185.42 204.44 185.82 204.45 186.22C204.46 186.62 204.43 187.02 204.36 187.41C204.3 187.81 204.19 188.19 204.04 188.57C203.9 188.94 203.72 189.3 203.5 189.63C203.23 190.07 202.9 190.47 202.53 190.82C202.15 191.18 201.73 191.48 201.28 191.73C200.83 191.98 200.35 192.17 199.85 192.29C199.36 192.42 198.84 192.48 198.33 192.48C198.18 192.48 198.03 192.48 197.88 192.46C197.73 192.45 197.58 192.44 197.43 192.41C197.29 192.39 197.14 192.36 196.99 192.33C196.85 192.3 196.7 192.26 196.56 192.22C194.18 195.04 191.3 196.53 188.78 197.31C190.8 198.86 192.59 200.72 194.12 202.88C195.7 202.52 197.41 202.76 198.79 203.63C201.65 205.44 202.5 209.24 200.7 212.09C200.42 212.52 200.09 212.92 199.72 213.28C199.34 213.63 198.93 213.93 198.47 214.18C198.02 214.43 197.54 214.62 197.04 214.75C196.54 214.88 196.03 214.94 195.52 214.94C194.36 214.94 193.23 214.61 192.25 213.99C189.4 212.19 188.55 208.4 190.34 205.54C190.37 205.5 190.4 205.45 190.43 205.4C190.46 205.36 190.49 205.31 190.53 205.27C190.56 205.22 190.59 205.18 190.62 205.14C190.66 205.09 190.69 205.05 190.72 205C188.45 201.89 185.56 199.53 182.12 197.96C182.11 197.96 182.11 197.96 182.1 197.96C178.91 196.51 175.8 195.97 173.35 195.82L173.35 191.83C176.13 191.98 179.67 192.54 183.36 194.14C184.59 194.16 189.66 193.97 193.3 189.85C192.96 189.36 192.69 188.82 192.51 188.25C192.32 187.68 192.22 187.09 192.21 186.49C192.2 185.9 192.27 185.3 192.43 184.72C192.59 184.15 192.84 183.6 193.16 183.09C193.43 182.66 193.76 182.26 194.13 181.9C194.51 181.55 194.92 181.25 195.38 181C195.83 180.75 196.31 180.56 196.81 180.43C197.3 180.3 197.82 180.24 198.33 180.24C198.62 180.24 198.91 180.26 199.19 180.3C199.47 180.34 199.76 180.4 200.03 180.48C200.31 180.56 200.58 180.66 200.84 180.78C201.1 180.9 201.35 181.03 201.6 181.19C201.94 181.4 202.26 181.65 202.55 181.93C202.84 182.2 203.1 182.51 203.34 182.84C203.57 183.17 203.77 183.52 203.93 183.89C204.09 184.25 204.22 184.64 204.3 185.03ZM193.73 207.68C193.59 207.91 193.49 208.18 193.44 208.45C193.39 208.72 193.4 209 193.46 209.28C193.52 209.55 193.63 209.8 193.79 210.03C193.95 210.26 194.16 210.45 194.39 210.6C194.63 210.75 194.89 210.85 195.16 210.9C195.44 210.95 195.72 210.94 195.99 210.88C196.26 210.82 196.51 210.7 196.74 210.54C196.97 210.38 197.16 210.18 197.31 209.94C197.46 209.71 197.56 209.44 197.6 209.17C197.65 208.9 197.64 208.62 197.58 208.35C197.52 208.07 197.41 207.82 197.25 207.59C197.09 207.36 196.88 207.17 196.65 207.02C196.41 206.88 196.15 206.78 195.88 206.73C195.61 206.68 195.33 206.69 195.06 206.75C194.79 206.81 194.53 206.93 194.3 207.08C194.08 207.24 193.88 207.44 193.73 207.68ZM200.11 187.49C200.32 187.17 200.43 186.8 200.44 186.43C200.45 186.05 200.36 185.68 200.18 185.34C200 185.01 199.73 184.74 199.41 184.55C199.08 184.35 198.71 184.25 198.33 184.25C198.15 184.25 197.98 184.27 197.81 184.32C197.63 184.36 197.47 184.42 197.31 184.51C197.16 184.59 197.01 184.7 196.88 184.82C196.76 184.94 196.64 185.08 196.55 185.23C196.4 185.46 196.3 185.71 196.25 185.97C196.2 186.23 196.21 186.5 196.26 186.77C196.31 187.03 196.41 187.28 196.55 187.51C196.7 187.73 196.89 187.93 197.11 188.08L197.2 188.14C198.18 188.76 199.51 188.44 200.11 187.49Z" />
+ <path id="Layer" fill-rule="evenodd" class="shp3" d="M213 227.01C210.76 227.39 209.57 228.15 208.14 229.08C206.98 229.83 205.74 230.64 203.93 231.26C208.47 234.6 214.56 240.87 217.12 245.06C217.52 244.95 217.94 244.89 218.35 244.87C218.77 244.85 219.19 244.87 219.6 244.93C220.01 245 220.42 245.1 220.81 245.25C221.2 245.4 221.58 245.58 221.93 245.81C222.27 246.02 222.59 246.27 222.88 246.55C223.17 246.82 223.44 247.13 223.67 247.46C223.9 247.79 224.1 248.14 224.26 248.51C224.43 248.87 224.55 249.26 224.64 249.65C224.73 250.04 224.78 250.44 224.79 250.84C224.8 251.24 224.77 251.64 224.7 252.03C224.63 252.43 224.52 252.81 224.38 253.19C224.23 253.56 224.05 253.92 223.83 254.25C223.56 254.69 223.23 255.09 222.86 255.44C222.48 255.8 222.07 256.1 221.62 256.35C221.16 256.6 220.68 256.79 220.19 256.91C219.69 257.04 219.17 257.1 218.66 257.1C217.5 257.1 216.37 256.78 215.39 256.15C215.26 256.07 215.18 256.02 215.11 255.96C212.46 254.1 211.75 250.47 213.49 247.71C213.59 247.56 213.69 247.42 213.8 247.28C211.13 242.63 201.64 233.6 199.03 232.96C195.63 232.11 193.67 232.18 191.18 232.27C189.73 232.32 188.08 232.39 185.97 232.27C182.89 232.1 181.2 230.18 179.71 228.49C178.15 226.71 176.65 225.12 173.36 224.82L173.36 220.82C178.5 221.2 180.92 223.79 182.72 225.84C184.08 227.39 184.85 228.2 186.18 228.27C188.12 228.37 189.6 228.32 191.03 228.27C192.77 228.2 194.36 228.15 196.32 228.38C202 228.29 203.92 227.04 205.96 225.72C207.58 224.66 209.41 223.48 212.78 222.99C212.82 222.85 212.87 222.71 212.92 222.58C212.97 222.44 213.02 222.31 213.08 222.17C213.14 222.04 213.2 221.91 213.27 221.78C213.34 221.66 213.41 221.53 213.49 221.41C213.54 221.34 213.59 221.27 213.64 221.19C213.69 221.12 213.74 221.05 213.79 220.98C213.84 220.92 213.9 220.85 213.95 220.78C214.01 220.71 214.07 220.65 214.12 220.58C214.26 220.44 214.41 220.32 214.55 220.19C213.44 216.09 213.24 210.29 214.59 205.77C214.56 205.75 214.54 205.73 214.51 205.71C213.99 205.23 213.56 204.66 213.23 204.03C212.9 203.4 212.69 202.72 212.59 202.01C212.5 201.31 212.53 200.59 212.68 199.9C212.84 199.21 213.11 198.55 213.49 197.95C213.76 197.51 214.09 197.11 214.46 196.76C214.84 196.4 215.26 196.1 215.71 195.85C216.16 195.6 216.64 195.41 217.14 195.28C217.64 195.16 218.15 195.09 218.66 195.1C218.95 195.1 219.24 195.12 219.52 195.16C219.81 195.2 220.09 195.26 220.36 195.34C220.64 195.42 220.91 195.52 221.17 195.63C221.43 195.75 221.69 195.89 221.93 196.04C222.27 196.25 222.59 196.5 222.88 196.78C223.17 197.06 223.44 197.36 223.67 197.69C223.9 198.02 224.1 198.37 224.26 198.74C224.42 199.11 224.55 199.49 224.64 199.88C224.73 200.27 224.78 200.67 224.79 201.07C224.8 201.47 224.77 201.87 224.7 202.27C224.63 202.66 224.52 203.05 224.38 203.42C224.23 203.79 224.05 204.15 223.83 204.49C223.56 204.92 223.23 205.32 222.86 205.68C222.48 206.03 222.07 206.33 221.62 206.58C221.16 206.83 220.68 207.02 220.19 207.15C219.69 207.27 219.17 207.34 218.66 207.34C218.55 207.34 218.44 207.32 218.32 207.31C217.37 210.81 217.58 215.42 218.29 218.58C218.41 218.57 218.54 218.56 218.66 218.56C218.95 218.56 219.24 218.58 219.52 218.62C219.81 218.66 220.09 218.72 220.36 218.8C220.64 218.88 220.91 218.98 221.17 219.1C221.43 219.21 221.69 219.35 221.93 219.5C222.27 219.72 222.59 219.96 222.88 220.24C223.17 220.52 223.44 220.82 223.67 221.15C223.9 221.48 224.1 221.83 224.26 222.2C224.42 222.57 224.55 222.95 224.64 223.35C224.73 223.74 224.78 224.14 224.79 224.54C224.8 224.94 224.77 225.34 224.7 225.73C224.63 226.12 224.52 226.51 224.38 226.88C224.23 227.26 224.05 227.61 223.83 227.95C223.56 228.39 223.23 228.79 222.86 229.14C222.48 229.49 222.07 229.8 221.62 230.05C221.16 230.29 220.68 230.48 220.19 230.61C219.69 230.74 219.17 230.8 218.66 230.8C218.34 230.8 218.03 230.78 217.72 230.73C217.4 230.68 217.1 230.6 216.8 230.51C216.49 230.41 216.2 230.29 215.92 230.15C215.64 230.01 215.37 229.84 215.11 229.66C214.88 229.5 214.65 229.31 214.45 229.12C214.24 228.92 214.04 228.71 213.87 228.49C213.69 228.26 213.52 228.03 213.38 227.78C213.24 227.53 213.11 227.28 213 227.01ZM216.88 200.09C216.74 200.31 216.64 200.56 216.59 200.83C216.54 201.09 216.54 201.36 216.59 201.62C216.64 201.88 216.74 202.14 216.89 202.36C217.03 202.59 217.22 202.78 217.44 202.94L217.53 203C218.51 203.62 219.85 203.3 220.44 202.34C220.52 202.23 220.58 202.11 220.63 201.98C220.68 201.85 220.72 201.72 220.74 201.58C220.77 201.44 220.78 201.31 220.78 201.17C220.77 201.03 220.76 200.89 220.73 200.76C220.6 200.2 220.27 199.73 219.79 199.43C219.45 199.22 219.06 199.1 218.66 199.1C218.49 199.1 218.31 199.13 218.14 199.17C217.97 199.21 217.8 199.28 217.64 199.36C217.49 199.45 217.35 199.55 217.22 199.68C217.09 199.8 216.97 199.93 216.88 200.09ZM216.88 223.55C216.74 223.77 216.64 224.03 216.59 224.29C216.54 224.55 216.54 224.82 216.59 225.09C216.64 225.35 216.74 225.6 216.89 225.82C217.03 226.05 217.22 226.24 217.44 226.4L217.53 226.46C218.51 227.08 219.85 226.76 220.44 225.81C220.52 225.69 220.58 225.57 220.63 225.44C220.68 225.31 220.72 225.18 220.74 225.04C220.77 224.91 220.78 224.77 220.78 224.63C220.77 224.49 220.76 224.36 220.72 224.22C220.6 223.67 220.27 223.2 219.79 222.89C219.45 222.68 219.06 222.57 218.66 222.57C218.49 222.57 218.31 222.59 218.14 222.63C217.97 222.68 217.8 222.74 217.64 222.83C217.49 222.91 217.35 223.02 217.22 223.14C217.09 223.26 216.97 223.4 216.88 223.55ZM216.88 249.85C216.74 250.08 216.64 250.33 216.59 250.59C216.54 250.86 216.54 251.13 216.59 251.39C216.64 251.65 216.74 251.9 216.89 252.13C217.03 252.35 217.22 252.55 217.44 252.7L217.53 252.76C218.51 253.38 219.85 253.06 220.44 252.11C220.52 252 220.58 251.87 220.63 251.74C220.68 251.62 220.72 251.48 220.74 251.35C220.77 251.21 220.78 251.07 220.78 250.94C220.77 250.8 220.76 250.66 220.72 250.53C220.6 249.97 220.27 249.5 219.79 249.2C219.45 248.98 219.06 248.87 218.66 248.87C218.49 248.87 218.31 248.89 218.14 248.94C217.97 248.98 217.8 249.05 217.64 249.13C217.49 249.22 217.35 249.32 217.22 249.44C217.09 249.56 216.97 249.7 216.88 249.85Z" />
+ <path id="Layer" fill-rule="evenodd" class="shp4" d="M206.53 258.93C206.79 259.23 207.02 259.56 207.22 259.91C207.42 260.26 207.58 260.63 207.71 261.01C207.83 261.39 207.92 261.78 207.96 262.18C208.01 262.58 208.02 262.98 207.99 263.38C207.96 263.78 207.89 264.17 207.78 264.56C207.67 264.95 207.53 265.32 207.35 265.68C207.17 266.04 206.95 266.38 206.7 266.69C206.45 267.01 206.17 267.3 205.87 267.56C205.59 267.79 205.3 268 204.99 268.19C204.68 268.37 204.35 268.52 204.01 268.65C203.67 268.78 203.32 268.87 202.96 268.94C202.61 269 202.25 269.03 201.89 269.03C201.49 269.03 201.1 268.99 200.71 268.92C200.32 268.84 199.94 268.73 199.57 268.58C199.21 268.43 198.85 268.24 198.52 268.02C198.19 267.81 197.88 267.56 197.6 267.28C195.75 267.98 192.69 269 190.58 269C190.48 269 190.37 269 190.27 269C188.3 268.89 187.03 268.03 186.01 267.34C184.44 266.28 182.95 265.27 177.6 266.63C175.24 267.71 173.63 267.79 173.36 267.82L173.36 263.82C173.86 263.72 174.73 263.55 175.91 263.01C175.94 263 175.97 262.98 176 262.97C176.03 262.95 176.06 262.94 176.09 262.92C176.12 262.91 176.15 262.89 176.18 262.88C176.21 262.87 176.24 262.86 176.27 262.85C179.62 261.24 184.79 257.38 188.84 248.16C188.56 247.95 188.29 247.72 188.05 247.47C187.8 247.22 187.58 246.94 187.39 246.65C187.19 246.36 187.02 246.05 186.88 245.73C186.74 245.41 186.62 245.07 186.54 244.73C186.44 244.34 186.38 243.95 186.36 243.55C186.33 243.15 186.35 242.74 186.41 242.35C186.47 241.95 186.57 241.56 186.7 241.18C186.84 240.8 187.01 240.44 187.22 240.1C187.49 239.64 187.82 239.23 188.19 238.86C188.57 238.49 188.99 238.17 189.45 237.91C189.91 237.65 190.4 237.45 190.91 237.32C191.42 237.18 191.95 237.11 192.48 237.11C192.75 237.11 193.02 237.13 193.3 237.17C193.57 237.2 193.84 237.26 194.1 237.33C194.37 237.4 194.62 237.5 194.88 237.6C195.13 237.71 195.37 237.83 195.61 237.97C198.51 239.71 199.46 243.47 197.73 246.37C197.47 246.8 197.16 247.21 196.79 247.56C196.43 247.92 196.03 248.23 195.59 248.49C195.15 248.75 194.68 248.95 194.2 249.1C193.71 249.24 193.2 249.32 192.69 249.34C190.12 255.34 187.05 259.41 184.11 262.18C185.84 262.51 187.09 263.23 188.26 264.02C189.18 264.65 189.66 264.95 190.48 264.99C191.55 265.03 193.86 264.36 195.81 263.66C195.75 263.16 195.75 262.66 195.81 262.16C195.87 261.66 196 261.17 196.18 260.7C196.36 260.23 196.6 259.79 196.89 259.38C197.18 258.97 197.52 258.59 197.9 258.26C198.51 257.74 199.22 257.34 199.98 257.09C200.74 256.84 201.55 256.74 202.35 256.8C203.15 256.87 203.94 257.08 204.65 257.45C205.37 257.81 206.01 258.32 206.53 258.93ZM190.66 242.15C190.59 242.27 190.53 242.4 190.48 242.53C190.43 242.66 190.4 242.79 190.38 242.93C190.36 243.07 190.35 243.2 190.36 243.34C190.37 243.48 190.39 243.62 190.42 243.75C190.46 243.89 190.5 244.02 190.56 244.14C190.62 244.27 190.69 244.39 190.78 244.5C190.86 244.61 190.95 244.71 191.05 244.8C191.16 244.89 191.27 244.98 191.39 245.05C191.72 245.24 192.09 245.35 192.47 245.35C192.65 245.35 192.84 245.33 193.01 245.28C193.19 245.23 193.36 245.16 193.52 245.07C193.68 244.98 193.82 244.87 193.95 244.75C194.08 244.62 194.2 244.47 194.29 244.32C194.58 243.83 194.66 243.26 194.52 242.71C194.38 242.17 194.04 241.7 193.56 241.42C193.07 241.13 192.5 241.05 191.95 241.18C191.41 241.32 190.94 241.67 190.66 242.15ZM203.26 264.51C203.36 264.42 203.46 264.32 203.55 264.22C203.63 264.11 203.71 263.99 203.77 263.87C203.83 263.74 203.88 263.62 203.92 263.48C203.96 263.35 203.98 263.21 203.99 263.07C204.01 262.78 203.98 262.49 203.88 262.22C203.78 261.94 203.63 261.69 203.43 261.47C203.24 261.26 203 261.09 202.73 260.97C202.46 260.86 202.17 260.8 201.88 260.8C201.76 260.8 201.63 260.81 201.51 260.83C201.39 260.85 201.27 260.88 201.15 260.93C201.03 260.97 200.92 261.02 200.81 261.09C200.7 261.15 200.6 261.23 200.51 261.31C200.3 261.49 200.13 261.71 200 261.96C199.87 262.2 199.8 262.47 199.78 262.75C199.76 263.03 199.79 263.31 199.87 263.57C199.96 263.83 200.1 264.08 200.28 264.29C200.46 264.5 200.68 264.67 200.93 264.8C201.18 264.92 201.45 265 201.72 265.02C202 265.04 202.28 265 202.54 264.92C202.8 264.83 203.05 264.69 203.26 264.51ZM204.3 183.03C204.39 183.42 204.44 183.82 204.45 184.22C204.46 184.62 204.43 185.02 204.36 185.41C204.3 185.8 204.19 186.19 204.04 186.56C203.9 186.94 203.72 187.29 203.5 187.63C203.23 188.07 202.9 188.47 202.52 188.82C202.15 189.17 201.73 189.48 201.28 189.72C200.83 189.97 200.35 190.16 199.85 190.29C199.36 190.42 198.84 190.48 198.33 190.48C198.18 190.48 198.03 190.47 197.88 190.46C197.73 190.45 197.58 190.43 197.43 190.41C197.29 190.39 197.14 190.36 196.99 190.33C196.85 190.29 196.7 190.26 196.56 190.21C194.18 193.04 191.3 194.53 188.78 195.31C190.8 196.86 192.59 198.72 194.12 200.88C195.7 200.52 197.41 200.76 198.79 201.63C201.65 203.44 202.5 207.23 200.7 210.08C200.42 210.52 200.09 210.92 199.72 211.27C199.34 211.63 198.93 211.93 198.47 212.18C198.02 212.43 197.54 212.62 197.04 212.74C196.54 212.87 196.03 212.94 195.52 212.93C194.36 212.93 193.23 212.61 192.25 211.98C189.4 210.18 188.55 206.39 190.34 203.54C190.37 203.49 190.4 203.45 190.43 203.4C190.46 203.36 190.49 203.31 190.53 203.27C190.56 203.22 190.59 203.18 190.62 203.13C190.66 203.09 190.69 203.04 190.72 203C188.45 199.89 185.56 197.52 182.12 195.96C182.11 195.96 182.11 195.96 182.1 195.96C178.91 194.5 175.8 193.96 173.35 193.82L173.35 189.82C176.13 189.98 179.67 190.54 183.36 192.14C184.59 192.16 189.66 191.97 193.3 187.85C192.96 187.36 192.69 186.82 192.51 186.25C192.32 185.68 192.22 185.09 192.21 184.49C192.2 183.89 192.27 183.3 192.43 182.72C192.59 182.14 192.84 181.59 193.16 181.09C193.43 180.65 193.76 180.25 194.13 179.9C194.51 179.55 194.92 179.24 195.38 178.99C195.83 178.74 196.31 178.55 196.81 178.43C197.3 178.3 197.82 178.24 198.33 178.24C198.62 178.24 198.91 178.26 199.19 178.3C199.47 178.34 199.76 178.4 200.03 178.48C200.31 178.56 200.58 178.66 200.84 178.78C201.1 178.89 201.35 179.03 201.6 179.18C201.94 179.4 202.26 179.64 202.55 179.92C202.84 180.2 203.1 180.5 203.34 180.83C203.57 181.16 203.77 181.51 203.93 181.88C204.09 182.25 204.22 182.63 204.3 183.03ZM193.73 205.67C193.59 205.91 193.49 206.17 193.44 206.45C193.39 206.72 193.4 207 193.46 207.27C193.52 207.54 193.63 207.8 193.79 208.03C193.95 208.25 194.16 208.45 194.39 208.6C194.63 208.75 194.89 208.85 195.16 208.89C195.44 208.94 195.72 208.93 195.99 208.87C196.26 208.81 196.51 208.7 196.74 208.54C196.97 208.38 197.16 208.17 197.31 207.94C197.46 207.7 197.56 207.44 197.6 207.17C197.65 206.89 197.64 206.61 197.58 206.34C197.52 206.07 197.41 205.81 197.25 205.59C197.09 205.36 196.88 205.17 196.65 205.02C196.41 204.87 196.15 204.77 195.88 204.73C195.61 204.68 195.33 204.69 195.06 204.75C194.79 204.81 194.53 204.92 194.3 205.08C194.08 205.24 193.88 205.44 193.73 205.67ZM200.11 185.49C200.32 185.17 200.43 184.8 200.44 184.42C200.45 184.05 200.36 183.67 200.18 183.34C200 183.01 199.73 182.73 199.41 182.54C199.08 182.35 198.71 182.25 198.33 182.25C198.15 182.25 197.98 182.27 197.81 182.31C197.63 182.35 197.47 182.42 197.31 182.51C197.16 182.59 197.01 182.7 196.88 182.82C196.76 182.94 196.64 183.08 196.55 183.23C196.4 183.45 196.3 183.7 196.25 183.97C196.2 184.23 196.21 184.5 196.26 184.76C196.31 185.03 196.41 185.28 196.55 185.5C196.7 185.73 196.89 185.92 197.11 186.08L197.2 186.14C198.18 186.76 199.51 186.44 200.11 185.49Z" />
+ <path id="Layer" fill-rule="evenodd" class="shp4" d="M213 224.01C210.76 224.39 209.57 225.15 208.14 226.08C206.98 226.83 205.74 227.64 203.93 228.27C208.47 231.6 214.56 237.87 217.12 242.06C217.52 241.95 217.94 241.89 218.35 241.87C218.77 241.85 219.19 241.87 219.6 241.93C220.01 242 220.42 242.11 220.81 242.25C221.2 242.4 221.58 242.58 221.93 242.81C222.27 243.02 222.59 243.27 222.88 243.55C223.17 243.82 223.44 244.13 223.67 244.46C223.9 244.79 224.1 245.14 224.26 245.51C224.43 245.88 224.55 246.26 224.64 246.65C224.73 247.04 224.78 247.44 224.79 247.84C224.8 248.24 224.77 248.64 224.7 249.03C224.63 249.43 224.52 249.81 224.38 250.19C224.23 250.56 224.05 250.92 223.83 251.25C223.56 251.69 223.23 252.09 222.86 252.44C222.48 252.8 222.07 253.1 221.62 253.35C221.16 253.6 220.68 253.79 220.19 253.92C219.69 254.04 219.17 254.11 218.66 254.1C217.5 254.1 216.37 253.78 215.39 253.16C215.26 253.07 215.18 253.02 215.11 252.97C212.46 251.1 211.75 247.47 213.49 244.71C213.59 244.56 213.69 244.42 213.8 244.28C211.13 239.63 201.64 230.6 199.03 229.96C195.63 229.11 193.67 229.18 191.18 229.27C189.73 229.32 188.08 229.39 185.97 229.27C182.89 229.11 181.2 227.19 179.71 225.49C178.15 223.71 176.65 222.12 173.36 221.82L173.36 217.82C178.5 218.2 180.92 220.79 182.72 222.85C184.08 224.39 184.85 225.2 186.18 225.27C188.12 225.37 189.6 225.32 191.03 225.27C192.77 225.2 194.36 225.15 196.32 225.38C202 225.29 203.92 224.04 205.96 222.72C207.58 221.66 209.41 220.48 212.78 219.99C212.82 219.85 212.87 219.71 212.92 219.58C212.97 219.44 213.02 219.31 213.08 219.17C213.14 219.04 213.2 218.91 213.27 218.78C213.34 218.66 213.41 218.53 213.49 218.41C213.54 218.34 213.59 218.27 213.64 218.19C213.69 218.12 213.74 218.05 213.79 217.98C213.84 217.92 213.9 217.85 213.95 217.78C214.01 217.71 214.07 217.65 214.12 217.58C214.26 217.44 214.41 217.32 214.55 217.19C213.44 213.09 213.24 207.29 214.59 202.77C214.56 202.75 214.54 202.73 214.51 202.71C213.99 202.23 213.56 201.66 213.23 201.03C212.9 200.4 212.69 199.72 212.59 199.01C212.5 198.31 212.53 197.59 212.68 196.9C212.84 196.21 213.11 195.55 213.49 194.95C213.76 194.51 214.09 194.11 214.46 193.76C214.84 193.4 215.26 193.1 215.71 192.85C216.16 192.6 216.64 192.41 217.14 192.28C217.64 192.16 218.15 192.09 218.66 192.1C218.95 192.1 219.24 192.12 219.52 192.16C219.81 192.2 220.09 192.26 220.36 192.34C220.64 192.42 220.91 192.52 221.17 192.63C221.43 192.75 221.69 192.89 221.93 193.04C222.27 193.25 222.59 193.5 222.88 193.78C223.17 194.06 223.44 194.36 223.67 194.69C223.9 195.02 224.1 195.37 224.26 195.74C224.42 196.11 224.55 196.49 224.64 196.88C224.73 197.27 224.78 197.67 224.79 198.07C224.8 198.47 224.77 198.87 224.7 199.27C224.63 199.66 224.52 200.05 224.38 200.42C224.23 200.79 224.05 201.15 223.83 201.49C223.56 201.92 223.23 202.32 222.86 202.68C222.48 203.03 222.07 203.33 221.62 203.58C221.16 203.83 220.68 204.02 220.19 204.15C219.69 204.27 219.17 204.34 218.66 204.34C218.55 204.34 218.44 204.32 218.32 204.31C217.37 207.81 217.58 212.42 218.29 215.58C218.41 215.57 218.54 215.56 218.66 215.56C218.95 215.56 219.24 215.58 219.52 215.62C219.81 215.66 220.09 215.72 220.36 215.8C220.64 215.88 220.91 215.98 221.17 216.1C221.43 216.21 221.69 216.35 221.93 216.5C222.27 216.72 222.59 216.96 222.88 217.24C223.17 217.52 223.44 217.82 223.67 218.15C223.9 218.48 224.1 218.83 224.26 219.2C224.42 219.57 224.55 219.95 224.64 220.35C224.73 220.74 224.78 221.14 224.79 221.54C224.8 221.94 224.77 222.34 224.7 222.73C224.63 223.12 224.52 223.51 224.38 223.88C224.23 224.26 224.05 224.61 223.83 224.95C223.56 225.39 223.23 225.79 222.86 226.14C222.48 226.49 222.07 226.8 221.62 227.05C221.16 227.29 220.68 227.48 220.19 227.61C219.69 227.74 219.17 227.8 218.66 227.8C218.34 227.8 218.03 227.78 217.72 227.73C217.4 227.68 217.1 227.6 216.8 227.51C216.49 227.41 216.2 227.29 215.92 227.15C215.64 227.01 215.37 226.84 215.11 226.66C214.88 226.5 214.65 226.31 214.45 226.12C214.24 225.92 214.04 225.71 213.87 225.49C213.69 225.26 213.52 225.03 213.38 224.78C213.24 224.53 213.11 224.28 213 224.01ZM216.88 197.09C216.74 197.31 216.64 197.56 216.59 197.83C216.54 198.09 216.54 198.36 216.59 198.62C216.64 198.88 216.74 199.14 216.89 199.36C217.03 199.59 217.22 199.78 217.44 199.94L217.53 200C218.51 200.62 219.85 200.3 220.44 199.34C220.52 199.23 220.58 199.11 220.63 198.98C220.68 198.85 220.72 198.72 220.74 198.58C220.77 198.44 220.78 198.31 220.78 198.17C220.77 198.03 220.76 197.89 220.73 197.76C220.6 197.2 220.27 196.73 219.79 196.43C219.45 196.22 219.06 196.1 218.66 196.1C218.49 196.1 218.31 196.13 218.14 196.17C217.97 196.21 217.8 196.28 217.64 196.36C217.49 196.45 217.35 196.55 217.22 196.68C217.09 196.8 216.97 196.93 216.88 197.09ZM216.88 220.55C216.74 220.77 216.64 221.03 216.59 221.29C216.54 221.55 216.54 221.82 216.59 222.09C216.64 222.35 216.74 222.6 216.89 222.82C217.03 223.05 217.22 223.24 217.44 223.4L217.53 223.46C218.51 224.08 219.85 223.76 220.44 222.81C220.52 222.69 220.58 222.57 220.63 222.44C220.68 222.31 220.72 222.18 220.74 222.04C220.77 221.91 220.78 221.77 220.78 221.63C220.77 221.49 220.76 221.36 220.72 221.22C220.6 220.67 220.27 220.2 219.79 219.89C219.45 219.68 219.06 219.57 218.66 219.57C218.49 219.57 218.31 219.59 218.14 219.63C217.97 219.68 217.8 219.74 217.64 219.83C217.49 219.91 217.35 220.02 217.22 220.14C217.09 220.26 216.97 220.4 216.88 220.55ZM216.88 246.85C216.74 247.08 216.64 247.33 216.59 247.59C216.54 247.86 216.54 248.13 216.59 248.39C216.64 248.65 216.74 248.9 216.89 249.13C217.03 249.35 217.22 249.55 217.44 249.7L217.53 249.76C218.51 250.38 219.85 250.06 220.44 249.11C220.52 249 220.58 248.87 220.63 248.74C220.68 248.62 220.72 248.48 220.74 248.35C220.77 248.21 220.78 248.07 220.78 247.94C220.77 247.8 220.76 247.66 220.72 247.53C220.6 246.97 220.27 246.5 219.79 246.2C219.45 245.98 219.06 245.87 218.66 245.87C218.49 245.87 218.31 245.89 218.14 245.94C217.97 245.98 217.8 246.05 217.64 246.13C217.49 246.22 217.35 246.32 217.22 246.44C217.09 246.56 216.97 246.7 216.88 246.85Z" />
+ <g id="Layer" style="opacity: 0.251">
+ <path id="Layer" class="shp2" d="M151.78 249.54C151.54 249.54 151.3 249.47 151.09 249.32C150.96 249.23 150.85 249.11 150.77 248.98C150.68 248.84 150.63 248.69 150.6 248.54C150.57 248.38 150.58 248.22 150.61 248.06C150.65 247.91 150.71 247.76 150.8 247.63C151.07 247.25 151.32 246.84 151.53 246.41C151.88 245.71 152.14 244.96 152.3 244.2C152.46 243.43 152.52 242.64 152.47 241.86C152.43 241.08 152.28 240.3 152.04 239.56C151.8 238.81 151.46 238.1 151.03 237.45C150.86 237.18 150.8 236.85 150.87 236.54C150.93 236.22 151.12 235.95 151.39 235.78C151.66 235.6 151.99 235.54 152.3 235.61C152.62 235.68 152.89 235.87 153.06 236.14C155.24 239.53 155.48 243.88 153.7 247.48C153.63 247.61 153.56 247.75 153.49 247.88C153.42 248.01 153.34 248.14 153.27 248.27C153.19 248.4 153.11 248.53 153.03 248.65C152.95 248.78 152.86 248.9 152.78 249.03C152.72 249.11 152.66 249.18 152.58 249.24C152.51 249.3 152.43 249.36 152.34 249.4C152.26 249.45 152.16 249.48 152.07 249.5C151.98 249.53 151.88 249.54 151.78 249.54M157.34 252.41C157.12 252.41 156.9 252.35 156.71 252.23C156.52 252.12 156.37 251.95 156.27 251.75C156.17 251.55 156.12 251.33 156.14 251.11C156.16 250.88 156.24 250.67 156.37 250.49C156.82 249.88 157.22 249.21 157.57 248.52C158.11 247.43 158.51 246.26 158.73 245.06C158.96 243.86 159.02 242.64 158.91 241.42C158.8 240.2 158.52 239.01 158.08 237.87C157.64 236.73 157.05 235.65 156.32 234.67C156.13 234.42 156.05 234.09 156.09 233.78C156.14 233.46 156.31 233.18 156.57 232.98C156.82 232.79 157.15 232.71 157.46 232.76C157.78 232.8 158.06 232.98 158.25 233.23C159.12 234.39 159.82 235.66 160.34 237C160.86 238.35 161.18 239.76 161.31 241.2C161.44 242.64 161.37 244.09 161.11 245.5C160.84 246.92 160.38 248.3 159.73 249.59C159.33 250.41 158.85 251.19 158.32 251.92C158.26 252 158.2 252.07 158.13 252.13C158.05 252.19 157.97 252.24 157.89 252.28C157.8 252.33 157.71 252.36 157.62 252.38C157.53 252.4 157.43 252.41 157.34 252.41ZM146.34 246.49C146.13 246.48 145.93 246.43 145.75 246.32C145.57 246.22 145.41 246.06 145.31 245.88C145.2 245.7 145.15 245.49 145.15 245.28C145.14 245.07 145.2 244.87 145.3 244.68C145.49 244.35 145.63 244 145.74 243.64C145.84 243.27 145.9 242.9 145.92 242.52C145.93 242.14 145.9 241.76 145.83 241.39C145.76 241.02 145.64 240.66 145.48 240.31C145.36 240.03 145.36 239.7 145.47 239.41C145.58 239.12 145.81 238.88 146.09 238.75C146.37 238.62 146.7 238.61 146.99 238.71C147.29 238.81 147.53 239.03 147.67 239.31C147.91 239.82 148.09 240.37 148.2 240.92C148.31 241.48 148.35 242.05 148.33 242.62C148.31 243.19 148.21 243.76 148.06 244.3C147.9 244.85 147.68 245.38 147.4 245.88C147.35 245.97 147.28 246.05 147.21 246.13C147.13 246.2 147.05 246.27 146.96 246.32C146.86 246.38 146.76 246.42 146.66 246.45C146.56 246.47 146.45 246.49 146.34 246.49" />
+ </g>
+ <g id="Layer">
+ <path id="Layer" class="shp0" d="M151.78 246.54C151.54 246.54 151.3 246.47 151.09 246.32C150.96 246.23 150.85 246.11 150.77 245.98C150.68 245.84 150.63 245.69 150.6 245.54C150.57 245.38 150.58 245.22 150.61 245.06C150.65 244.91 150.71 244.76 150.8 244.63C151.07 244.25 151.32 243.84 151.53 243.41C151.88 242.71 152.14 241.96 152.3 241.2C152.46 240.43 152.52 239.64 152.47 238.86C152.43 238.08 152.28 237.3 152.04 236.56C151.8 235.81 151.46 235.1 151.03 234.45C150.86 234.18 150.8 233.85 150.87 233.54C150.93 233.22 151.12 232.95 151.39 232.78C151.66 232.6 151.99 232.54 152.3 232.61C152.62 232.68 152.89 232.87 153.06 233.14C155.24 236.53 155.48 240.88 153.7 244.48C153.63 244.61 153.56 244.75 153.49 244.88C153.42 245.01 153.34 245.14 153.27 245.27C153.19 245.4 153.11 245.53 153.03 245.65C152.95 245.78 152.86 245.9 152.78 246.03C152.72 246.11 152.66 246.18 152.58 246.24C152.51 246.3 152.43 246.36 152.34 246.4C152.26 246.45 152.16 246.48 152.07 246.5C151.98 246.53 151.88 246.54 151.78 246.54M157.34 249.41C157.12 249.41 156.9 249.35 156.71 249.23C156.52 249.12 156.37 248.95 156.27 248.75C156.17 248.55 156.12 248.33 156.14 248.11C156.16 247.88 156.24 247.67 156.37 247.49C156.82 246.88 157.22 246.21 157.57 245.52C158.11 244.43 158.51 243.26 158.73 242.06C158.96 240.86 159.02 239.64 158.91 238.42C158.8 237.2 158.52 236.01 158.08 234.87C157.64 233.73 157.05 232.65 156.32 231.67C156.13 231.42 156.05 231.09 156.09 230.78C156.14 230.46 156.31 230.18 156.57 229.98C156.82 229.79 157.15 229.71 157.46 229.76C157.78 229.8 158.06 229.98 158.25 230.23C159.12 231.39 159.82 232.66 160.34 234C160.86 235.35 161.18 236.76 161.31 238.2C161.44 239.64 161.37 241.09 161.11 242.5C160.84 243.92 160.38 245.3 159.73 246.59C159.33 247.41 158.85 248.19 158.32 248.92C158.26 249 158.2 249.07 158.13 249.13C158.05 249.19 157.97 249.24 157.89 249.28C157.8 249.33 157.71 249.36 157.62 249.38C157.53 249.4 157.43 249.41 157.34 249.41ZM146.34 243.49C146.13 243.48 145.93 243.43 145.75 243.32C145.57 243.22 145.41 243.06 145.31 242.88C145.2 242.7 145.15 242.49 145.15 242.28C145.14 242.07 145.2 241.87 145.3 241.68C145.49 241.35 145.63 241 145.74 240.64C145.84 240.27 145.9 239.9 145.92 239.52C145.93 239.14 145.9 238.76 145.83 238.39C145.76 238.02 145.64 237.66 145.48 237.31C145.36 237.03 145.36 236.7 145.47 236.41C145.58 236.12 145.81 235.88 146.09 235.75C146.37 235.62 146.7 235.61 146.99 235.71C147.29 235.81 147.53 236.03 147.67 236.31C147.91 236.82 148.09 237.37 148.2 237.92C148.31 238.48 148.35 239.05 148.33 239.62C148.31 240.19 148.21 240.76 148.06 241.3C147.9 241.85 147.68 242.38 147.4 242.88C147.35 242.97 147.28 243.05 147.21 243.13C147.13 243.2 147.05 243.27 146.96 243.32C146.86 243.38 146.76 243.42 146.66 243.45C146.56 243.47 146.45 243.49 146.34 243.49" />
+ </g>
+ <g id="Layer">
+ <path id="Layer" fill-rule="evenodd" class="shp5" d="M164.08 192.24C165.2 192.24 167.16 192.28 168.36 192.39L168.36 195.88C167.32 195.78 165.12 195.74 164.08 195.74C154.95 195.74 145.38 199.12 139.72 204.35C135.15 208.57 132.19 214.61 131.03 221.84C130.8 223.29 130.66 225.08 130.6 226.94C130.89 225.07 132.31 223.65 134.03 223.65L135.93 223.65C137.86 223.65 139.42 225.44 139.42 227.65L139.42 257.32C139.42 259.53 137.86 261.32 135.93 261.32L134.03 261.32C132.1 261.32 130.53 259.53 130.53 257.32L130.53 255.72C130.24 255.79 129.94 255.83 129.62 255.83L127.59 255.83C127.06 255.83 126.54 255.73 126.06 255.53C125.57 255.33 125.13 255.03 124.76 254.66C124.39 254.29 124.09 253.85 123.89 253.36C123.69 252.88 123.59 252.36 123.59 251.83L123.59 233.71C123.59 233.24 123.67 232.77 123.84 232.32C124.01 231.88 124.25 231.47 124.56 231.11C124.87 230.75 125.24 230.45 125.66 230.22C126.08 229.99 126.53 229.84 127 229.77C126.82 218.03 130.46 208.14 137.35 201.78C143.72 195.9 153.96 192.24 164.08 192.24ZM129.62 251.43L130.54 251.43L130.54 234.12L129.62 234.12C129.27 234.12 128.93 234.18 128.61 234.32C128.29 234.45 127.99 234.65 127.75 234.89C127.5 235.14 127.31 235.43 127.17 235.75C127.04 236.07 126.97 236.42 126.97 236.77L126.97 248.78C126.97 249.13 127.04 249.47 127.17 249.79C127.31 250.11 127.5 250.41 127.75 250.65C128 250.9 128.29 251.09 128.61 251.23C128.93 251.36 129.27 251.43 129.62 251.43Z" />
+ <path id="Layer" fill-rule="evenodd" class="shp4" d="M164.08 189.24C165.2 189.24 167.16 189.28 168.36 189.39L168.36 192.88C167.32 192.78 165.12 192.74 164.08 192.74C154.95 192.74 145.38 196.12 139.72 201.35C135.15 205.57 132.19 211.61 131.03 218.84C130.8 220.29 130.66 222.08 130.6 223.94C130.89 222.07 132.31 220.65 134.03 220.65L135.93 220.65C137.86 220.65 139.42 222.44 139.42 224.65L139.42 254.32C139.42 256.53 137.86 258.32 135.93 258.32L134.03 258.32C132.1 258.32 130.53 256.53 130.53 254.32L130.53 252.72C130.24 252.79 129.94 252.83 129.62 252.83L127.59 252.83C127.06 252.83 126.54 252.73 126.06 252.53C125.57 252.33 125.13 252.03 124.76 251.66C124.39 251.29 124.09 250.85 123.89 250.36C123.69 249.88 123.59 249.36 123.59 248.83L123.59 230.71C123.59 230.24 123.67 229.77 123.84 229.32C124.01 228.88 124.25 228.47 124.56 228.11C124.87 227.75 125.24 227.45 125.66 227.22C126.08 226.99 126.53 226.84 127 226.77C126.82 215.03 130.46 205.14 137.35 198.78C143.72 192.9 153.96 189.24 164.08 189.24ZM129.62 248.43L130.54 248.43L130.54 231.12L129.62 231.12C129.27 231.12 128.93 231.18 128.61 231.32C128.29 231.45 127.99 231.65 127.75 231.89C127.5 232.14 127.31 232.43 127.17 232.75C127.04 233.07 126.97 233.42 126.97 233.77L126.97 245.78C126.97 246.13 127.04 246.47 127.17 246.79C127.31 247.11 127.5 247.41 127.75 247.65C128 247.9 128.29 248.09 128.61 248.23C128.93 248.36 129.27 248.43 129.62 248.43Z" />
+ </g>
+ <g id="Layer">
+ <path id="Layer" fill-rule="evenodd" class="shp1" d="M295.75 242.67L295.75 252.82L259.58 252.82L259.58 198.08L272.78 198.08L272.78 242.67L295.75 242.67ZM300.63 201.65C300.63 199.85 301.29 198.37 302.59 197.22C303.89 196.06 305.59 195.49 307.67 195.49C309.75 195.49 311.44 196.06 312.74 197.22C314.04 198.37 314.7 199.85 314.7 201.65C314.7 203.46 314.05 204.94 312.74 206.09C311.44 207.24 309.75 207.82 307.67 207.82C305.59 207.82 303.89 207.24 302.59 206.09C301.29 204.94 300.63 203.46 300.63 201.65ZM314.1 252.82L301.39 252.82L301.39 212.14L314.1 212.14L314.1 252.82ZM341.5 238.8C340.38 238.15 338.23 237.47 335.07 236.77C331.92 236.07 329.31 235.15 327.25 234.01C325.2 232.87 323.63 231.48 322.55 229.85C321.48 228.22 320.94 226.36 320.94 224.25C320.94 220.51 322.48 217.44 325.56 215.02C328.64 212.6 332.68 211.39 337.67 211.39C343.03 211.39 347.34 212.61 350.6 215.04C353.86 217.47 355.49 220.66 355.49 224.63L342.78 224.63C342.78 221.37 341.06 219.74 337.63 219.74C336.3 219.74 335.19 220.11 334.28 220.85C333.38 221.58 332.93 222.51 332.93 223.61C332.93 224.74 333.48 225.65 334.58 226.35C335.69 227.06 337.45 227.63 339.87 228.08C342.29 228.53 344.41 229.07 346.24 229.7C352.36 231.8 355.41 235.58 355.41 241.02C355.41 244.73 353.77 247.75 350.47 250.08C347.17 252.41 342.91 253.57 337.67 253.57C334.18 253.57 331.08 252.95 328.34 251.69C325.61 250.44 323.48 248.74 321.95 246.58C320.42 244.43 319.66 242.16 319.66 239.77L331.5 239.77C331.55 241.66 332.18 243.03 333.38 243.89C334.58 244.76 336.13 245.19 338.01 245.19C339.74 245.19 341.03 244.84 341.9 244.14C342.76 243.44 343.19 242.52 343.19 241.39C343.19 240.32 342.63 239.45 341.5 238.8ZM376.09 212.14L382.79 212.14L382.79 220.94L376.09 220.94L376.09 239.55C376.09 241.08 376.37 242.15 376.92 242.75C377.47 243.35 378.56 243.65 380.19 243.65C381.44 243.65 382.5 243.57 383.35 243.42L383.35 252.49C382.77 252.67 382.19 252.83 381.6 252.96C381.01 253.1 380.42 253.22 379.82 253.31C379.22 253.4 378.62 253.47 378.02 253.51C377.41 253.56 376.81 253.58 376.21 253.57C371.84 253.57 368.62 252.55 366.54 250.49C364.46 248.44 363.42 245.32 363.42 241.13L363.42 220.94L358.23 220.94L358.23 212.14L363.42 212.14L363.42 202.03L376.09 202.03L376.09 212.14ZM392.3 247.99C388.44 244.27 386.51 239.43 386.51 233.46L386.51 232.41C386.51 228.25 387.28 224.58 388.82 221.39C390.36 218.21 392.61 215.75 395.57 214C398.53 212.26 402.04 211.39 406.1 211.39C411.81 211.39 416.32 213.16 419.63 216.71C422.94 220.26 424.59 225.2 424.59 231.54L424.59 236.47L399.41 236.47C399.86 238.75 400.85 240.54 402.38 241.84C403.9 243.15 405.88 243.8 408.32 243.8C412.33 243.8 415.46 242.4 417.72 239.59L423.5 246.43C421.93 248.61 419.69 250.35 416.79 251.64C413.9 252.93 410.78 253.57 407.45 253.57C401.21 253.57 396.16 251.71 392.3 247.99ZM399.4 228.53L412.19 228.53L412.19 227.56C412.24 225.53 411.72 223.95 410.65 222.84C409.57 221.72 408.03 221.17 406.02 221.17C402.31 221.17 400.11 223.62 399.4 228.53ZM441.74 216.92C444.55 213.23 448.42 211.39 453.36 211.39C457.59 211.39 460.76 212.66 462.85 215.19C464.94 217.72 466.03 221.53 466.1 226.62L466.1 252.82L453.39 252.82L453.39 227.14C453.39 225.09 452.98 223.58 452.15 222.61C451.33 221.65 449.82 221.17 447.64 221.17C445.16 221.17 443.32 222.14 442.11 224.1L442.11 252.82L429.44 252.82L429.44 212.14L441.32 212.14L441.74 216.92Z" />
+ </g>
+ <g id="Layer">
+ <path id="Layer" fill-rule="evenodd" class="shp0" d="M473.64 198.08L493.3 198.08C500.34 198.08 505.7 199.37 509.37 201.95C513.05 204.54 514.88 208.28 514.88 213.2C514.88 216.03 514.23 218.45 512.93 220.45C511.62 222.46 509.71 223.94 507.18 224.89C510.03 225.64 512.23 227.05 513.75 229.1C515.28 231.15 516.05 233.66 516.05 236.62C516.05 241.98 514.35 246.01 510.95 248.71C507.56 251.4 502.52 252.77 495.86 252.82L473.64 252.82L473.64 198.08ZM486.83 220.9L493.72 220.9C496.6 220.88 498.65 220.35 499.88 219.32C501.11 218.29 501.72 216.77 501.72 214.76C501.72 212.44 501.06 210.78 499.73 209.76C498.4 208.74 496.26 208.23 493.3 208.23L486.83 208.23L486.83 220.9ZM486.83 229.55L486.83 242.67L495.48 242.67C497.86 242.67 499.69 242.13 500.97 241.04C502.25 239.95 502.89 238.41 502.89 236.43C502.89 231.87 500.62 229.58 496.08 229.55L486.83 229.55ZM547.33 223.61L543.15 223.31C539.17 223.31 536.61 224.56 535.48 227.07L535.48 252.82L522.81 252.82L522.81 212.14L534.69 212.14L535.11 217.37C537.24 213.38 540.21 211.39 544.02 211.39C545.37 211.39 546.55 211.54 547.55 211.84L547.33 223.61ZM573.73 252.82C573.28 252 572.88 250.78 572.53 249.18C570.2 252.11 566.94 253.57 562.76 253.57C558.92 253.57 555.66 252.42 552.98 250.1C550.3 247.78 548.96 244.87 548.96 241.36C548.96 236.94 550.59 233.61 553.85 231.35C557.11 229.1 561.84 227.97 568.06 227.97L571.97 227.97L571.97 225.82C571.97 222.06 570.35 220.19 567.12 220.19C564.11 220.19 562.61 221.67 562.61 224.65L549.94 224.65C549.94 220.72 551.61 217.52 554.96 215.07C558.3 212.62 562.57 211.39 567.76 211.39C572.95 211.39 577.04 212.66 580.05 215.19C583.06 217.72 584.6 221.19 584.68 225.6L584.68 243.61C584.73 247.34 585.3 250.2 586.41 252.18L586.41 252.82L573.73 252.82L573.73 252.82ZM569.73 243.54C570.77 242.86 571.52 242.1 571.97 241.24L571.97 234.74L568.28 234.74C563.87 234.74 561.67 236.72 561.67 240.68C561.67 241.83 562.05 242.76 562.83 243.48C563.61 244.19 564.6 244.55 565.8 244.55C567.38 244.55 568.69 244.21 569.73 243.54ZM591.59 201.65C591.59 199.85 592.25 198.37 593.55 197.22C594.85 196.06 596.54 195.49 598.63 195.49C600.7 195.49 602.4 196.06 603.7 197.22C605 198.37 605.65 199.85 605.65 201.65C605.65 203.46 605 204.94 603.7 206.09C602.4 207.24 600.7 207.82 598.63 207.82C596.54 207.82 594.85 207.24 593.55 206.09C592.25 204.94 591.59 203.46 591.59 201.65ZM605.05 252.82L592.35 252.82L592.35 212.14L605.05 212.14L605.05 252.82ZM624.49 212.14L624.91 216.92C627.71 213.23 631.58 211.39 636.52 211.39C640.76 211.39 643.92 212.66 646.02 215.19C648.11 217.72 649.19 221.53 649.27 226.62L649.27 252.82L636.56 252.82L636.56 227.14C636.56 225.09 636.15 223.58 635.32 222.61C634.49 221.65 632.99 221.17 630.81 221.17C628.33 221.17 626.48 222.14 625.28 224.1L625.28 252.82L612.61 252.82L612.61 212.14L624.49 212.14ZM689.76 243.05L689.76 252.82L655.21 252.82L655.21 245.75L673.26 221.92L656 221.92L656 212.14L689.35 212.14L689.35 218.99L671.23 243.05L689.76 243.05Z" />
+ </g>
+</svg> \ No newline at end of file
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/NOTICE.md b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/NOTICE.md
new file mode 100644
index 0000000000..774e383f8b
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/NOTICE.md
@@ -0,0 +1,23 @@
+# ListenBrainz logo attribution
+
+The file `ListenBrainz_logo.svg` shipped alongside this plugin is a derivative
+work used here under the terms of the Creative Commons Attribution-ShareAlike
+4.0 International license (CC BY-SA 4.0).
+
+## Attribution chain
+
+1. Original work: [ListenBrainz logo](https://github.com/metabrainz/metabrainz-logos/commit/10127d3e84e5bb7e1c8509f1da12223d19581e18)
+ by [MonkeyDo](https://github.com/metabrainz/metabrainz-logos/commits?author=MonkeyDo)
+ at the [MetaBrainz Foundation](https://github.com/metabrainz), licensed under
+ CC BY-SA 4.0.
+2. "ListenBrainz logo for Jellyfin plugin" — derivative by
+ [lyarenei](https://github.com/lyarenei), distributed in
+ [jellyfin-plugin-listenbrainz](https://github.com/lyarenei/jellyfin-plugin-listenbrainz/tree/main/res/listenbrainz)
+ under CC BY-SA 4.0.
+3. This redistribution within Jellyfin retains the work unmodified and remains
+ licensed under CC BY-SA 4.0 per the license's ShareAlike requirement.
+
+## License
+
+A full copy of the CC BY-SA 4.0 license is available at
+<https://creativecommons.org/licenses/by-sa/4.0/legalcode>.
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/PluginConfiguration.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/PluginConfiguration.cs
new file mode 100644
index 0000000000..6f60d18c33
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/PluginConfiguration.cs
@@ -0,0 +1,65 @@
+using MediaBrowser.Model.Plugins;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Configuration;
+
+/// <summary>
+/// ListenBrainz plugin configuration.
+/// </summary>
+public class PluginConfiguration : BasePluginConfiguration
+{
+ /// <summary>
+ /// The default Labs API server URL.
+ /// </summary>
+ public const string DefaultLabsServer = "https://labs.api.listenbrainz.org";
+
+ /// <summary>
+ /// The default rate limit in seconds.
+ /// </summary>
+ public const double DefaultRateLimit = 1.0;
+
+ private string _labsServer = DefaultLabsServer;
+ private double _rateLimit = DefaultRateLimit;
+
+ /// <summary>
+ /// Gets or sets the Labs API server URL.
+ /// </summary>
+ public string LabsServer
+ {
+ get => _labsServer;
+ set => _labsServer = string.IsNullOrWhiteSpace(value) ? DefaultLabsServer : value.TrimEnd('/');
+ }
+
+ /// <summary>
+ /// Gets or sets the similarity algorithm.
+ /// </summary>
+ public SimilarityAlgorithm Algorithm { get; set; } = SimilarityAlgorithm.SessionBased1825Days;
+
+ /// <summary>
+ /// Gets or sets the rate limit in seconds.
+ /// </summary>
+ public double RateLimit
+ {
+ get => _rateLimit;
+ set
+ {
+ if (value < DefaultRateLimit && _labsServer == DefaultLabsServer)
+ {
+ _rateLimit = DefaultRateLimit;
+ }
+ else
+ {
+ _rateLimit = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the cache duration in days for similar item results. A value of 0 disables caching.
+ /// </summary>
+ public int SimilarItemsCacheDays { get; set; } = 14;
+
+ /// <summary>
+ /// Gets the algorithm string for the API call.
+ /// </summary>
+ public string AlgorithmString => Algorithm.ToApiString();
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithm.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithm.cs
new file mode 100644
index 0000000000..f297d99f6d
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithm.cs
@@ -0,0 +1,37 @@
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Configuration;
+
+/// <summary>
+/// Available similarity algorithms for ListenBrainz Labs API.
+/// </summary>
+public enum SimilarityAlgorithm
+{
+ /// <summary>
+ /// Session-based algorithm analyzing ~5 years of listening data.
+ /// </summary>
+ SessionBased1825Days = 0,
+
+ /// <summary>
+ /// Session-based algorithm analyzing ~5 years of listening data (alternate).
+ /// </summary>
+ SessionBased1800Days = 1,
+
+ /// <summary>
+ /// Session-based algorithm analyzing ~20 years of listening data.
+ /// </summary>
+ SessionBased7500Days = 2,
+
+ /// <summary>
+ /// Session-based algorithm analyzing ~20 years with higher contribution threshold.
+ /// </summary>
+ SessionBased7500DaysHighContribution = 3,
+
+ /// <summary>
+ /// Session-based algorithm analyzing ~25 years of listening data.
+ /// </summary>
+ SessionBased9000Days = 4,
+
+ /// <summary>
+ /// Session-based algorithm analyzing ~75 days of recent listening data.
+ /// </summary>
+ SessionBased75Days = 5
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithmExtensions.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithmExtensions.cs
new file mode 100644
index 0000000000..f7874dbae8
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/SimilarityAlgorithmExtensions.cs
@@ -0,0 +1,23 @@
+namespace MediaBrowser.Providers.Plugins.ListenBrainz.Configuration;
+
+/// <summary>
+/// Extension methods for <see cref="SimilarityAlgorithm"/>.
+/// </summary>
+public static class SimilarityAlgorithmExtensions
+{
+ /// <summary>
+ /// Gets the API string value for the algorithm.
+ /// </summary>
+ /// <param name="algorithm">The algorithm.</param>
+ /// <returns>The API string value.</returns>
+ public static string ToApiString(this SimilarityAlgorithm algorithm) => algorithm switch
+ {
+ SimilarityAlgorithm.SessionBased1825Days => "session_based_days_1825_session_300_contribution_3_threshold_10_limit_100_filter_True_skip_30",
+ SimilarityAlgorithm.SessionBased1800Days => "session_based_days_1800_session_300_contribution_3_threshold_10_limit_100_filter_True_skip_30",
+ SimilarityAlgorithm.SessionBased7500Days => "session_based_days_7500_session_300_contribution_3_threshold_10_limit_100_filter_True_skip_30",
+ SimilarityAlgorithm.SessionBased7500DaysHighContribution => "session_based_days_7500_session_300_contribution_5_threshold_10_limit_100_filter_True_skip_30",
+ SimilarityAlgorithm.SessionBased9000Days => "session_based_days_9000_session_300_contribution_5_threshold_15_limit_50_skip_30",
+ SimilarityAlgorithm.SessionBased75Days => "session_based_days_75_session_300_contribution_5_threshold_10_limit_100_filter_True_skip_30",
+ _ => "session_based_days_1825_session_300_contribution_3_threshold_10_limit_100_filter_True_skip_30"
+ };
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/config.html b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/config.html
new file mode 100644
index 0000000000..dec21d1b42
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/Configuration/config.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>ListenBrainz</title>
+</head>
+<body>
+ <div id="configPage" data-role="page" class="page type-interior pluginConfigurationPage configPage" data-require="emby-input,emby-button,emby-select">
+ <div data-role="content">
+ <div class="content-primary">
+ <img id="listenBrainzLogo" alt="ListenBrainz" style="max-width:240px;display:block;margin:0 auto 1em;" />
+ <h1>ListenBrainz</h1>
+ <p>Get similar artist recommendations from ListenBrainz Labs.</p>
+ <form class="configForm">
+ <div class="inputContainer">
+ <input is="emby-input" type="text" id="labsServer" required label="Labs API Server" />
+ <div class="fieldDescription">The ListenBrainz Labs API server URL. Default: https://labs.api.listenbrainz.org</div>
+ </div>
+ <div class="selectContainer">
+ <label class="selectLabel" for="algorithm">Similarity Algorithm</label>
+ <select is="emby-select" id="algorithm" class="emby-select-withcolor">
+ <option value="0" selected>~5 years / 1825 days (Recommended)</option>
+ <option value="1">~5 years / 1800 days</option>
+ <option value="2">~20 years / 7500 days</option>
+ <option value="3">~20 years / 7500 days (high contribution)</option>
+ <option value="4">~25 years / 9000 days</option>
+ <option value="5">~75 days (recent)</option>
+ </select>
+ <div class="fieldDescription">The algorithm used for artist similarity calculation.</div>
+ </div>
+ <div class="inputContainer">
+ <input is="emby-input" type="number" id="rateLimit" required pattern="[0-9]*" min="0" max="10" step=".01" label="Rate Limit (seconds)" />
+ <div class="fieldDescription">Span of time between requests in seconds. The official server is rate limited to one request per second.</div>
+ </div>
+ <div class="inputContainer">
+ <input is="emby-input" type="number" id="similarItemsCacheDays" required pattern="[0-9]*" min="0" max="365" label="Cache duration (days)" />
+ <div class="fieldDescription">Number of days to cache similar artist results from ListenBrainz. Set to 0 to disable caching.</div>
+ </div>
+ <br />
+ <div>
+ <button is="emby-button" type="submit" class="raised button-submit block"><span>Save</span></button>
+ </div>
+ </form>
+ <div class="verticalSection" style="margin-top:2em;font-size:0.85em;opacity:0.8;">
+ <p>The ListenBrainz logo is &copy; the MetaBrainz Foundation (by MonkeyDo),
+ adapted for Jellyfin plugin use by
+ <a href="https://github.com/lyarenei" target="_blank" rel="noopener">lyarenei</a>,
+ and redistributed here under
+ <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank" rel="noopener">CC BY-SA 4.0</a>.
+ Full attribution notice is shipped alongside the plugin in <code>NOTICE.md</code>.</p>
+ </div>
+ </div>
+ </div>
+ <script type="text/javascript">
+ var ListenBrainzPluginConfig = {
+ uniquePluginId: "a5b2e8c1-9d4f-4a3b-8c7e-6f1a2b3c4d5e"
+ };
+
+ document.querySelector('.configPage')
+ .addEventListener('pageshow', function () {
+ Dashboard.showLoadingMsg();
+ document.querySelector('#listenBrainzLogo').src = ApiClient.getUrl('web/ConfigurationPage', { name: 'ListenBrainzLogo' });
+ ApiClient.getPluginConfiguration(ListenBrainzPluginConfig.uniquePluginId).then(function (config) {
+ var labsServer = document.querySelector('#labsServer');
+ labsServer.value = config.LabsServer;
+ labsServer.dispatchEvent(new Event('change', {
+ bubbles: true,
+ cancelable: false
+ }));
+
+ document.querySelector('#algorithm').value = config.Algorithm;
+
+ var rateLimit = document.querySelector('#rateLimit');
+ rateLimit.value = config.RateLimit;
+ rateLimit.dispatchEvent(new Event('change', {
+ bubbles: true,
+ cancelable: false
+ }));
+
+ var similarItemsCacheDays = document.querySelector('#similarItemsCacheDays');
+ similarItemsCacheDays.value = config.SimilarItemsCacheDays;
+ similarItemsCacheDays.dispatchEvent(new Event('change', {
+ bubbles: true,
+ cancelable: false
+ }));
+
+ Dashboard.hideLoadingMsg();
+ });
+ });
+
+ document.querySelector('.configForm')
+ .addEventListener('submit', function (e) {
+ Dashboard.showLoadingMsg();
+
+ ApiClient.getPluginConfiguration(ListenBrainzPluginConfig.uniquePluginId).then(function (config) {
+ config.LabsServer = document.querySelector('#labsServer').value;
+ config.Algorithm = parseInt(document.querySelector('#algorithm').value, 10);
+ config.RateLimit = document.querySelector('#rateLimit').value;
+ config.SimilarItemsCacheDays = parseInt(document.querySelector('#similarItemsCacheDays').value, 10);
+
+ ApiClient.updatePluginConfiguration(ListenBrainzPluginConfig.uniquePluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
+ });
+
+ e.preventDefault();
+ return false;
+ });
+ </script>
+ </div>
+</body>
+</html>
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzPlugin.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzPlugin.cs
new file mode 100644
index 0000000000..efac93f94e
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzPlugin.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Plugins;
+using MediaBrowser.Model.Plugins;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Providers.Plugins.ListenBrainz.Configuration;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz;
+
+/// <summary>
+/// ListenBrainz plugin instance.
+/// </summary>
+public class ListenBrainzPlugin : BasePlugin<PluginConfiguration>, IHasWebPages
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ListenBrainzPlugin"/> class.
+ /// </summary>
+ /// <param name="applicationPaths">Instance of the <see cref="IApplicationPaths"/> interface.</param>
+ /// <param name="xmlSerializer">Instance of the <see cref="IXmlSerializer"/> interface.</param>
+ public ListenBrainzPlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
+ : base(applicationPaths, xmlSerializer)
+ {
+ Instance = this;
+ }
+
+ /// <summary>
+ /// Gets the current plugin instance.
+ /// </summary>
+ public static ListenBrainzPlugin? Instance { get; private set; }
+
+ /// <inheritdoc />
+ public override Guid Id => new("a5b2e8c1-9d4f-4a3b-8c7e-6f1a2b3c4d5e");
+
+ /// <inheritdoc />
+ public override string Name => "ListenBrainz Similarity Provider";
+
+ /// <inheritdoc />
+ public override string Description => "Get similar artist recommendations from ListenBrainz Labs.";
+
+ /// <inheritdoc />
+ public override string ConfigurationFileName => "Jellyfin.Plugin.ListenBrainz.xml";
+
+ /// <inheritdoc />
+ public IEnumerable<PluginPageInfo> GetPages()
+ {
+ var resourcePrefix = GetType().Namespace + ".Configuration.";
+ yield return new PluginPageInfo
+ {
+ Name = Name,
+ EmbeddedResourcePath = resourcePrefix + "config.html"
+ };
+ yield return new PluginPageInfo
+ {
+ Name = Name + "Logo",
+ EmbeddedResourcePath = resourcePrefix + "ListenBrainz_logo.svg"
+ };
+ yield return new PluginPageInfo
+ {
+ Name = Name + "Notice",
+ EmbeddedResourcePath = resourcePrefix + "NOTICE.md"
+ };
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzSimilarArtistProvider.cs b/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzSimilarArtistProvider.cs
new file mode 100644
index 0000000000..3dca748d06
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/ListenBrainz/ListenBrainzSimilarArtistProvider.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Providers.Plugins.ListenBrainz.Api;
+using Microsoft.Extensions.Logging;
+
+namespace MediaBrowser.Providers.Plugins.ListenBrainz;
+
+/// <summary>
+/// ListenBrainz-based similar items provider for music artists.
+/// </summary>
+public class ListenBrainzSimilarArtistProvider : IRemoteSimilarItemsProvider<MusicArtist>
+{
+ private readonly ListenBrainzLabsClient _labsClient;
+ private readonly ILogger<ListenBrainzSimilarArtistProvider> _logger;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ListenBrainzSimilarArtistProvider"/> class.
+ /// </summary>
+ /// <param name="labsClient">The ListenBrainz Labs API client.</param>
+ /// <param name="logger">The logger.</param>
+ public ListenBrainzSimilarArtistProvider(
+ ListenBrainzLabsClient labsClient,
+ ILogger<ListenBrainzSimilarArtistProvider> logger)
+ {
+ _labsClient = labsClient;
+ _logger = logger;
+ }
+
+ /// <inheritdoc/>
+ public string Name => "ListenBrainz";
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.SimilarityProvider;
+
+ /// <inheritdoc/>
+ public TimeSpan? CacheDuration
+ {
+ get
+ {
+ var days = ListenBrainzPlugin.Instance?.Configuration.SimilarItemsCacheDays ?? 0;
+ return days > 0 ? TimeSpan.FromDays(days) : null;
+ }
+ }
+
+ /// <inheritdoc/>
+ public async IAsyncEnumerable<SimilarItemReference> GetSimilarItemsAsync(
+ MusicArtist item,
+ SimilarItemsQuery query,
+ [EnumeratorCancellation] CancellationToken cancellationToken)
+ {
+ ArgumentNullException.ThrowIfNull(item);
+ ArgumentNullException.ThrowIfNull(query);
+
+ if (!item.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out var mbidStr) || !Guid.TryParse(mbidStr, out var mbid))
+ {
+ _logger.LogDebug("No MusicBrainz Artist ID found for {ArtistName}", item.Name);
+ yield break;
+ }
+
+ IReadOnlyList<Guid> similarMbids;
+ try
+ {
+ similarMbids = await _labsClient.GetSimilarArtistsAsync(mbid, cancellationToken).ConfigureAwait(false);
+ }
+ catch (HttpRequestException ex)
+ {
+ _logger.LogWarning(ex, "Failed to fetch similar artists from ListenBrainz for {ArtistMbid}", mbid);
+ yield break;
+ }
+
+ var providerName = MetadataProvider.MusicBrainzArtist.ToString();
+
+ foreach (var similarMbid in similarMbids)
+ {
+ yield return new SimilarItemReference
+ {
+ ProviderName = providerName,
+ ProviderId = similarMbid.ToString()
+ };
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
index f11b1d95aa..78405c21fc 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
@@ -77,5 +77,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
/// Gets or sets a value indicating the still image size to fetch.
/// </summary>
public string? StillSize { get; set; }
+
+ /// <summary>
+ /// Gets or sets the cache duration in days for similar item results. A value of 0 disables caching.
+ /// </summary>
+ public int SimilarItemsCacheDays { get; set; } = 7;
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
index 89d380ec1f..4048fc1655 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
@@ -44,6 +44,13 @@
<span>Hide crew members without profile images.</span>
</label>
</div>
+ <div class="verticalSection">
+ <h2>Similar Items</h2>
+ <div class="inputContainer">
+ <input is="emby-input" type="number" id="similarItemsCacheDays" pattern="[0-9]*" required min="0" max="365" label="Cache duration (days)" />
+ <div class="fieldDescription">Number of days to cache similar item results from TMDb. Set to 0 to disable caching.</div>
+ </div>
+ </div>
<div class="verticalSection verticalSection-extrabottompadding">
<h2>Image Scaling</h2>
<div class="selectContainer">
@@ -161,6 +168,13 @@
cancelable: false
}));
+ var similarItemsCacheDays = document.querySelector('#similarItemsCacheDays');
+ similarItemsCacheDays.value = config.SimilarItemsCacheDays;
+ similarItemsCacheDays.dispatchEvent(new Event('change', {
+ bubbles: true,
+ cancelable: false
+ }));
+
pluginConfig = config;
configureImageScaling();
});
@@ -179,6 +193,7 @@
config.MaxCrewMembers = document.querySelector('#maxCrewMembers').value;
config.HideMissingCastMembers = document.querySelector('#hideMissingCastMembers').checked;
config.HideMissingCrewMembers = document.querySelector('#hideMissingCrewMembers').checked;
+ config.SimilarItemsCacheDays = parseInt(document.querySelector('#similarItemsCacheDays').value, 10);
config.PosterSize = document.querySelector('#selectPosterSize').value;
config.BackdropSize = document.querySelector('#selectBackdropSize').value;
config.LogoSize = document.querySelector('#selectLogoSize').value;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieSimilarProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieSimilarProvider.cs
new file mode 100644
index 0000000000..5206de78ce
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieSimilarProvider.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Entities;
+using Microsoft.Extensions.Logging;
+using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
+
+namespace MediaBrowser.Providers.Plugins.Tmdb.Movies;
+
+/// <summary>
+/// TMDb-based similar items provider for movies.
+/// </summary>
+public class TmdbMovieSimilarProvider : IRemoteSimilarItemsProvider<Movie>
+{
+ private readonly TmdbClientManager _tmdbClientManager;
+ private readonly ILogger<TmdbMovieSimilarProvider> _logger;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TmdbMovieSimilarProvider"/> class.
+ /// </summary>
+ /// <param name="tmdbClientManager">The TMDb client manager.</param>
+ /// <param name="logger">The logger.</param>
+ public TmdbMovieSimilarProvider(TmdbClientManager tmdbClientManager, ILogger<TmdbMovieSimilarProvider> logger)
+ {
+ _tmdbClientManager = tmdbClientManager;
+ _logger = logger;
+ }
+
+ /// <inheritdoc/>
+ public string Name => TmdbUtils.ProviderName;
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.SimilarityProvider;
+
+ /// <inheritdoc/>
+ public TimeSpan? CacheDuration
+ {
+ get
+ {
+ var days = Plugin.Instance?.Configuration.SimilarItemsCacheDays ?? 0;
+ return days > 0 ? TimeSpan.FromDays(days) : null;
+ }
+ }
+
+ /// <inheritdoc/>
+ public async IAsyncEnumerable<SimilarItemReference> GetSimilarItemsAsync(
+ Movie item,
+ SimilarItemsQuery query,
+ [EnumeratorCancellation] CancellationToken cancellationToken)
+ {
+ if (!item.TryGetProviderId(MetadataProvider.Tmdb, out var tmdbIdStr) || !int.TryParse(tmdbIdStr, CultureInfo.InvariantCulture, out var tmdbId))
+ {
+ yield break;
+ }
+
+ var providerName = MetadataProvider.Tmdb.ToString();
+ var page = 0;
+ var totalPages = 1;
+
+ while (page <= totalPages && !cancellationToken.IsCancellationRequested)
+ {
+ IReadOnlyList<TMDbLib.Objects.Search.SearchMovie> pageResults;
+ try
+ {
+ (pageResults, totalPages) = await _tmdbClientManager
+ .GetMovieSimilarPageAsync(tmdbId, page, TmdbUtils.GetImageLanguagesParam(string.Empty), cancellationToken)
+ .ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Failed to get similar movies from TMDb for {TmdbId} page {Page}", tmdbId, page);
+ yield break;
+ }
+
+ if (pageResults.Count == 0)
+ {
+ yield break;
+ }
+
+ foreach (var similar in pageResults)
+ {
+ yield return new SimilarItemReference
+ {
+ ProviderName = providerName,
+ ProviderId = similar.Id.ToString(CultureInfo.InvariantCulture)
+ };
+ }
+
+ page++;
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesSimilarProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesSimilarProvider.cs
new file mode 100644
index 0000000000..c85718b993
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesSimilarProvider.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Entities;
+using Microsoft.Extensions.Logging;
+
+namespace MediaBrowser.Providers.Plugins.Tmdb.TV;
+
+/// <summary>
+/// TMDb-based similar items provider for TV series.
+/// </summary>
+public class TmdbSeriesSimilarProvider : IRemoteSimilarItemsProvider<Series>
+{
+ private readonly TmdbClientManager _tmdbClientManager;
+ private readonly ILogger<TmdbSeriesSimilarProvider> _logger;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TmdbSeriesSimilarProvider"/> class.
+ /// </summary>
+ /// <param name="tmdbClientManager">The TMDb client manager.</param>
+ /// <param name="logger">The logger.</param>
+ public TmdbSeriesSimilarProvider(TmdbClientManager tmdbClientManager, ILogger<TmdbSeriesSimilarProvider> logger)
+ {
+ _tmdbClientManager = tmdbClientManager;
+ _logger = logger;
+ }
+
+ /// <inheritdoc/>
+ public string Name => TmdbUtils.ProviderName;
+
+ /// <inheritdoc/>
+ public MetadataPluginType Type => MetadataPluginType.SimilarityProvider;
+
+ /// <inheritdoc/>
+ public TimeSpan? CacheDuration
+ {
+ get
+ {
+ var days = Plugin.Instance?.Configuration.SimilarItemsCacheDays ?? 0;
+ return days > 0 ? TimeSpan.FromDays(days) : null;
+ }
+ }
+
+ /// <inheritdoc/>
+ public async IAsyncEnumerable<SimilarItemReference> GetSimilarItemsAsync(
+ Series item,
+ SimilarItemsQuery query,
+ [EnumeratorCancellation] CancellationToken cancellationToken)
+ {
+ if (!item.TryGetProviderId(MetadataProvider.Tmdb, out var tmdbIdStr) || !int.TryParse(tmdbIdStr, CultureInfo.InvariantCulture, out var tmdbId))
+ {
+ yield break;
+ }
+
+ var providerName = MetadataProvider.Tmdb.ToString();
+ var page = 1;
+ var totalPages = 1;
+
+ while (page <= totalPages && !cancellationToken.IsCancellationRequested)
+ {
+ IReadOnlyList<TMDbLib.Objects.Search.SearchTv> pageResults;
+ try
+ {
+ (pageResults, totalPages) = await _tmdbClientManager
+ .GetSeriesSimilarPageAsync(tmdbId, page, TmdbUtils.GetImageLanguagesParam(string.Empty), cancellationToken)
+ .ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Failed to get similar TV shows from TMDb for {TmdbId} page {Page}", tmdbId, page);
+ yield break;
+ }
+
+ if (pageResults.Count == 0)
+ {
+ yield break;
+ }
+
+ foreach (var similar in pageResults)
+ {
+ yield return new SimilarItemReference
+ {
+ ProviderName = providerName,
+ ProviderId = similar.Id.ToString(CultureInfo.InvariantCulture)
+ };
+ }
+
+ page++;
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
index 274db347ba..174f1546a7 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
@@ -505,6 +505,54 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
}
/// <summary>
+ /// Gets a single page of similar movies for a movie from the TMDb API.
+ /// </summary>
+ /// <param name="tmdbId">The TMDb id of the movie.</param>
+ /// <param name="page">The page number to fetch (1-based).</param>
+ /// <param name="language">The language for results.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>A tuple containing the list of similar movies and the total number of pages available.</returns>
+ public async Task<(IReadOnlyList<SearchMovie> Results, int TotalPages)> GetMovieSimilarPageAsync(int tmdbId, int page, string? language, CancellationToken cancellationToken)
+ {
+ await EnsureClientConfigAsync().ConfigureAwait(false);
+
+ var searchResults = await _tmDbClient
+ .GetMovieSimilarAsync(tmdbId, language, page, cancellationToken)
+ .ConfigureAwait(false);
+
+ if (searchResults?.Results is null || searchResults.Results.Count == 0)
+ {
+ return ([], 0);
+ }
+
+ return (searchResults.Results, searchResults.TotalPages);
+ }
+
+ /// <summary>
+ /// Gets a single page of similar TV shows for a series from the TMDb API.
+ /// </summary>
+ /// <param name="tmdbId">The TMDb id of the TV show.</param>
+ /// <param name="page">The page number to fetch (1-based).</param>
+ /// <param name="language">The language for results.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>A tuple containing the list of similar TV shows and the total number of pages available.</returns>
+ public async Task<(IReadOnlyList<SearchTv> Results, int TotalPages)> GetSeriesSimilarPageAsync(int tmdbId, int page, string? language, CancellationToken cancellationToken)
+ {
+ await EnsureClientConfigAsync().ConfigureAwait(false);
+
+ var searchResults = await _tmDbClient
+ .GetTvShowSimilarAsync(tmdbId, language, page, cancellationToken)
+ .ConfigureAwait(false);
+
+ if (searchResults?.Results is null || searchResults.Results.Count == 0)
+ {
+ return ([], 0);
+ }
+
+ return (searchResults.Results, searchResults.TotalPages);
+ }
+
+ /// <summary>
/// Handles bad path checking and builds the absolute url.
/// </summary>
/// <param name="size">The image size to fetch.</param>