Add project files.

This commit is contained in:
ahjephson
2024-04-22 14:15:07 +01:00
parent ce7b627fa9
commit f9847c60f5
166 changed files with 14345 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record BuildInfo
{
[JsonConstructor]
public BuildInfo(
string qTVersion,
string libTorrentVersion,
string boostVersion,
string openSSLVersion,
int bitness)
{
QTVersion = qTVersion;
LibTorrentVersion = libTorrentVersion;
BoostVersion = boostVersion;
OpenSSLVersion = openSSLVersion;
Bitness = bitness;
}
[JsonPropertyName("qt")]
public string QTVersion { get; }
[JsonPropertyName("libtorrent")]
public string LibTorrentVersion { get; }
[JsonPropertyName("boost")]
public string BoostVersion { get; }
[JsonPropertyName("openssl")]
public string OpenSSLVersion { get; }
[JsonPropertyName("bitness")]
public int Bitness { get; }
}
}

View File

@@ -0,0 +1,22 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record Category
{
[JsonConstructor]
public Category(
string name,
string? savePath)
{
Name = name;
SavePath = savePath;
}
[JsonPropertyName("name")]
public string Name { get; }
[JsonPropertyName("savePath")]
public string? SavePath { get; }
}
}

View File

@@ -0,0 +1,52 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record FileData
{
[JsonConstructor]
public FileData(
int index,
string name,
long size,
float progress,
Priority priority,
bool isSeed,
IReadOnlyList<int> pieceRange,
float availability)
{
Index = index;
Name = name;
Size = size;
Progress = progress;
Priority = priority;
IsSeed = isSeed;
PieceRange = pieceRange ?? [];
Availability = availability;
}
[JsonPropertyName("index")]
public int Index { get; }
[JsonPropertyName("name")]
public string Name { get; }
[JsonPropertyName("size")]
public long Size { get; }
[JsonPropertyName("progress")]
public float Progress { get; }
[JsonPropertyName("priority")]
public Priority Priority { get; }
[JsonPropertyName("is_seed")]
public bool IsSeed { get; }
[JsonPropertyName("piece_range")]
public IReadOnlyList<int> PieceRange { get; }
[JsonPropertyName("availability")]
public float Availability { get; }
}
}

View File

@@ -0,0 +1,52 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record GlobalTransferInfo
{
[JsonConstructor]
public GlobalTransferInfo(
string? connectionStatus,
int? dHTNodes,
long? downloadInfoData,
long? downloadInfoSpeed,
long? downloadRateLimit,
long? uploadInfoData,
long? uploadInfoSpeed,
long? uploadRateLimit)
{
ConnectionStatus = connectionStatus;
DHTNodes = dHTNodes;
DownloadInfoData = downloadInfoData;
DownloadInfoSpeed = downloadInfoSpeed;
DownloadRateLimit = downloadRateLimit;
UploadInfoData = uploadInfoData;
UploadInfoSpeed = uploadInfoSpeed;
UploadRateLimit = uploadRateLimit;
}
[JsonPropertyName("connection_status")]
public string? ConnectionStatus { get; }
[JsonPropertyName("dht_nodes")]
public int? DHTNodes { get; }
[JsonPropertyName("dl_info_data")]
public long? DownloadInfoData { get; }
[JsonPropertyName("dl_info_speed")]
public long? DownloadInfoSpeed { get; }
[JsonPropertyName("dl_rate_limit")]
public long? DownloadRateLimit { get; }
[JsonPropertyName("up_info_data")]
public long? UploadInfoData { get; }
[JsonPropertyName("up_info_speed")]
public long? UploadInfoSpeed { get; }
[JsonPropertyName("up_rate_limit")]
public long? UploadRateLimit { get; }
}
}

View File

@@ -0,0 +1,32 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record Log
{
[JsonConstructor]
public Log(
int id,
string message,
long timestamp,
LogType type)
{
Id = id;
Message = message;
Timestamp = timestamp;
Type = type;
}
[JsonPropertyName("id")]
public int Id { get; }
[JsonPropertyName("message")]
public string Message { get; }
[JsonPropertyName("timestamp")]
public long Timestamp { get; }
[JsonPropertyName("type")]
public LogType Type { get; }
}
}

View File

@@ -0,0 +1,10 @@
namespace Lantean.QBitTorrentClient.Models
{
public enum LogType
{
Normal = 1,
Info = 2,
Warning = 4,
Critical = 8
}
}

View File

@@ -0,0 +1,65 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record MainData
{
[JsonConstructor]
public MainData(
int responseId,
bool fullUpdate,
IReadOnlyDictionary<string, Torrent>? torrents,
IReadOnlyList<string>? torrentsRemoved,
IReadOnlyDictionary<string, Category>? categories,
IReadOnlyList<string>? categoriesRemoved,
IReadOnlyList<string>? tags,
IReadOnlyList<string>? tagsRemoved,
IReadOnlyDictionary<string, IReadOnlyList<string>> trackers,
ServerState? serverState)
{
ResponseId = responseId;
FullUpdate = fullUpdate;
Torrents = torrents;
TorrentsRemoved = torrentsRemoved;
Categories = categories;
CategoriesRemoved = categoriesRemoved;
Tags = tags;
TagsRemoved = tagsRemoved;
Trackers = trackers;
ServerState = serverState;
}
[JsonPropertyName("rid")]
public int ResponseId { get; }
[JsonPropertyName("full_update")]
public bool FullUpdate { get; }
[JsonPropertyName("torrents")]
public IReadOnlyDictionary<string, Torrent>? Torrents { get; }
[JsonPropertyName("torrents_removed")]
public IReadOnlyList<string>? TorrentsRemoved { get; }
[JsonPropertyName("categories")]
public IReadOnlyDictionary<string, Category>? Categories { get; }
[JsonPropertyName("categories_removed")]
public IReadOnlyList<string>? CategoriesRemoved { get; }
[JsonPropertyName("tags")]
public IReadOnlyList<string>? Tags { get; }
[JsonPropertyName("tags_removed")]
public IReadOnlyList<string>? TagsRemoved { get; }
[JsonPropertyName("trackers")]
public IReadOnlyDictionary<string, IReadOnlyList<string>>? Trackers { get; }
[JsonPropertyName("trackers_removed")]
public IReadOnlyList<string>? TrackersRemoved { get; }
[JsonPropertyName("server_state")]
public ServerState? ServerState { get; }
}
}

View File

@@ -0,0 +1,92 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record Peer
{
[JsonConstructor]
public Peer(
string? client,
string? connection,
string? country,
string? countryCode,
long? downloadSpeed,
long? downloaded,
string? files,
string? flags,
string? flagsDescription,
string? iPAddress,
string? clientId,
int? port,
float? progress,
float? relevance,
long? uploadSpeed,
long? uploaded)
{
Client = client;
Connection = connection;
Country = country;
CountryCode = countryCode;
DownloadSpeed = downloadSpeed;
Downloaded = downloaded;
Files = files;
Flags = flags;
FlagsDescription = flagsDescription;
IPAddress = iPAddress;
ClientId = clientId;
Port = port;
Progress = progress;
Relevance = relevance;
UploadSpeed = uploadSpeed;
Uploaded = uploaded;
}
[JsonPropertyName("client")]
public string? Client { get; }
[JsonPropertyName("connection")]
public string? Connection { get; }
[JsonPropertyName("country")]
public string? Country { get; }
[JsonPropertyName("country_code")]
public string? CountryCode { get; }
[JsonPropertyName("dl_speed")]
public long? DownloadSpeed { get; }
[JsonPropertyName("downloaded")]
public long? Downloaded { get; }
[JsonPropertyName("files")]
public string? Files { get; }
[JsonPropertyName("flags")]
public string? Flags { get; }
[JsonPropertyName("flags_desc")]
public string? FlagsDescription { get; }
[JsonPropertyName("ip")]
public string? IPAddress { get; }
[JsonPropertyName("peer_id_client")]
public string? ClientId { get; }
[JsonPropertyName("port")]
public int? Port { get; }
[JsonPropertyName("progress")]
public float? Progress { get; }
[JsonPropertyName("relevance")]
public float? Relevance { get; }
[JsonPropertyName("up_speed")]
public long? UploadSpeed { get; }
[JsonPropertyName("uploaded")]
public long? Uploaded { get; }
}
}

View File

@@ -0,0 +1,14 @@
namespace Lantean.QBitTorrentClient.Models
{
public readonly struct PeerId(string host, int port)
{
public string Host { get; } = host;
public int Port { get; } = port;
public override string ToString()
{
return $"{Host}:{Port}";
}
}
}

View File

@@ -0,0 +1,37 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record PeerLog
{
[JsonConstructor]
public PeerLog(
int id,
string iPAddress,
long timestamp,
bool blocked,
string reason)
{
Id = id;
IPAddress = iPAddress;
Timestamp = timestamp;
Blocked = blocked;
Reason = reason;
}
[JsonPropertyName("id")]
public int Id { get; }
[JsonPropertyName("ip")]
public string IPAddress { get; }
[JsonPropertyName("timestamp")]
public long Timestamp { get; }
[JsonPropertyName("blocked")]
public bool Blocked { get; }
[JsonPropertyName("reason")]
public string Reason { get; }
}
}

View File

@@ -0,0 +1,9 @@
namespace Lantean.QBitTorrentClient.Models
{
public enum PieceState
{
NotDownloaded = 0,
Downloading = 1,
Downloaded = 2,
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
namespace Lantean.QBitTorrentClient.Models
{
public enum Priority
{
DoNotDownload = 0,
Normal = 1,
High = 6,
Maximum = 7
}
}

View File

@@ -0,0 +1,82 @@

namespace Lantean.QBitTorrentClient.Models
{
public class SaveLocation
{
public bool IsWatchedFolder { get; set; }
public bool IsDefaltFolder { get; set; }
public string? SavePath { get; set; }
public static SaveLocation Create(object? value)
{
if (value is int intValue)
{
if (intValue == 0)
{
return new SaveLocation
{
IsWatchedFolder = true
};
}
else if (intValue == 1)
{
return new SaveLocation
{
IsDefaltFolder = true
};
}
}
else if (value is string stringValue)
{
if (stringValue == "0")
{
return new SaveLocation
{
IsWatchedFolder = true
};
}
else if (stringValue == "1")
{
return new SaveLocation
{
IsDefaltFolder = true
};
}
else
{
return new SaveLocation
{
SavePath = stringValue
};
}
}
throw new ArgumentOutOfRangeException(nameof(value));
}
public object ToValue()
{
if (IsWatchedFolder)
{
return 0;
}
else if (IsDefaltFolder)
{
return 1;
}
else if (SavePath is not null)
{
return SavePath;
}
throw new InvalidOperationException("Invalid value.");
}
public override string? ToString()
{
return ToValue().ToString();
}
}
}

View File

@@ -0,0 +1,105 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record ServerState : GlobalTransferInfo
{
[JsonConstructor]
public ServerState(
long? allTimeDownloaded,
long? allTimeUploaded,
int? averageTimeQueue,
string? connectionStatus,
int? dHTNodes,
long? downloadInfoData,
long? downloadInfoSpeed,
long? downloadRateLimit,
long? freeSpaceOnDisk,
float? globalRatio,
int? queuedIOJobs,
bool? queuing,
float? readCacheHits,
float? readCacheOverload,
int? refreshInterval,
int? totalBuffersSize,
int? totalPeerConnections,
int? totalQueuedSize,
long? totalWastedSession,
long? uploadInfoData,
long? uploadInfoSpeed,
long? uploadRateLimit,
bool? useAltSpeedLimits,
bool? useSubcategories,
float? writeCacheOverload) : base(connectionStatus, dHTNodes, downloadInfoData, downloadInfoSpeed, downloadRateLimit, uploadInfoData, uploadInfoSpeed, uploadRateLimit)
{
AllTimeDownloaded = allTimeDownloaded;
AllTimeUploaded = allTimeUploaded;
AverageTimeQueue = averageTimeQueue;
FreeSpaceOnDisk = freeSpaceOnDisk;
GlobalRatio = globalRatio;
QueuedIOJobs = queuedIOJobs;
Queuing = queuing;
ReadCacheHits = readCacheHits;
ReadCacheOverload = readCacheOverload;
RefreshInterval = refreshInterval;
TotalBuffersSize = totalBuffersSize;
TotalPeerConnections = totalPeerConnections;
TotalQueuedSize = totalQueuedSize;
TotalWastedSession = totalWastedSession;
UseAltSpeedLimits = useAltSpeedLimits;
UseSubcategories = useSubcategories;
WriteCacheOverload = writeCacheOverload;
}
[JsonPropertyName("alltime_dl")]
public long? AllTimeDownloaded { get; }
[JsonPropertyName("alltime_ul")]
public long? AllTimeUploaded { get; }
[JsonPropertyName("average_time_queue")]
public int? AverageTimeQueue { get; }
[JsonPropertyName("free_space_on_disk")]
public long? FreeSpaceOnDisk { get; }
[JsonPropertyName("global_ratio")]
public float? GlobalRatio { get; }
[JsonPropertyName("queued_io_jobs")]
public int? QueuedIOJobs { get; }
[JsonPropertyName("queueing")]
public bool? Queuing { get; }
[JsonPropertyName("read_cache_hits")]
public float? ReadCacheHits { get; }
[JsonPropertyName("read_cache_overload")]
public float? ReadCacheOverload { get; }
[JsonPropertyName("refresh_interval")]
public int? RefreshInterval { get; }
[JsonPropertyName("total_buffers_size")]
public int? TotalBuffersSize { get; }
[JsonPropertyName("total_peer_connections")]
public int? TotalPeerConnections { get; }
[JsonPropertyName("total_queued_size")]
public int? TotalQueuedSize { get; }
[JsonPropertyName("total_wasted_session")]
public long? TotalWastedSession { get; }
[JsonPropertyName("use_alt_speed_limits")]
public bool? UseAltSpeedLimits { get; }
[JsonPropertyName("use_subcategories")]
public bool? UseSubcategories { get; }
[JsonPropertyName("write_cache_overload")]
public float? WriteCacheOverload { get; }
}
}

View File

@@ -0,0 +1,249 @@
using Lantean.QBitTorrentClient.Converters;
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record Torrent
{
[JsonConstructor]
public Torrent(
long? addedOn,
long? amountLeft,
bool? automaticTorrentManagement,
float? availability,
string? category,
long? completed,
long? completionOn,
string? contentPath,
long? downloadLimit,
long? downloadSpeed,
long? downloaded,
long? downloadedSession,
long? estimatedTimeOfArrival,
bool? firstLastPiecePriority,
bool? forceStart,
string? infoHashV1,
string? infoHashV2,
long? lastActivity,
string? magnetUri,
float? maxRatio,
int? maxSeedingTime,
string? name,
int? numberComplete,
int? numberIncomplete,
int? numberLeeches,
int? numberSeeds,
int? priority,
float? progress,
float? ratio,
float? ratioLimit,
string? savePath,
long? seedingTime,
int? seedingTimeLimit,
long? seenComplete,
bool? sequentialDownload,
long? size,
string? state,
bool? superSeeding,
IReadOnlyList<string>? tags,
int? timeActive,
long? totalSize,
string? tracker,
long? uploadLimit,
long? uploaded,
long? uploadedSession,
long? uploadSpeed,
long? reannounce)
{
AddedOn = addedOn;
AmountLeft = amountLeft;
AutomaticTorrentManagement = automaticTorrentManagement;
Availability = availability;
Category = category;
Completed = completed;
CompletionOn = completionOn;
ContentPath = contentPath;
DownloadLimit = downloadLimit;
DownloadSpeed = downloadSpeed;
Downloaded = downloaded;
DownloadedSession = downloadedSession;
EstimatedTimeOfArrival = estimatedTimeOfArrival;
FirstLastPiecePriority = firstLastPiecePriority;
ForceStart = forceStart;
InfoHashV1 = infoHashV1;
InfoHashV2 = infoHashV2;
LastActivity = lastActivity;
MagnetUri = magnetUri;
MaxRatio = maxRatio;
MaxSeedingTime = maxSeedingTime;
Name = name;
NumberComplete = numberComplete;
NumberIncomplete = numberIncomplete;
NumberLeeches = numberLeeches;
NumberSeeds = numberSeeds;
Priority = priority;
Progress = progress;
Ratio = ratio;
RatioLimit = ratioLimit;
SavePath = savePath;
SeedingTime = seedingTime;
SeedingTimeLimit = seedingTimeLimit;
SeenComplete = seenComplete;
SequentialDownload = sequentialDownload;
Size = size;
State = state;
SuperSeeding = superSeeding;
Tags = tags ?? [];
TimeActive = timeActive;
TotalSize = totalSize;
Tracker = tracker;
UploadLimit = uploadLimit;
Uploaded = uploaded;
UploadedSession = uploadedSession;
UploadSpeed = uploadSpeed;
Reannounce = reannounce;
}
[JsonPropertyName("added_on")]
public long? AddedOn { get; }
[JsonPropertyName("amount_left")]
public long? AmountLeft { get; }
[JsonPropertyName("auto_tmm")]
public bool? AutomaticTorrentManagement { get; }
[JsonPropertyName("availability")]
public float? Availability { get; }
[JsonPropertyName("category")]
public string? Category { get; }
[JsonPropertyName("completed")]
public long? Completed { get; }
[JsonPropertyName("completion_on")]
public long? CompletionOn { get; }
[JsonPropertyName("content_path")]
public string? ContentPath { get; }
[JsonPropertyName("dl_limit")]
public long? DownloadLimit { get; }
[JsonPropertyName("dlspeed")]
public long? DownloadSpeed { get; }
[JsonPropertyName("downloaded")]
public long? Downloaded { get; }
[JsonPropertyName("downloaded_session")]
public long? DownloadedSession { get; }
[JsonPropertyName("eta")]
public long? EstimatedTimeOfArrival { get; }
[JsonPropertyName("f_l_piece_prio")]
public bool? FirstLastPiecePriority { get; }
[JsonPropertyName("force_start")]
public bool? ForceStart { get; }
[JsonPropertyName("infohash_v1")]
public string? InfoHashV1 { get; }
[JsonPropertyName("infohash_v2")]
public string? InfoHashV2 { get; }
[JsonPropertyName("last_activity")]
public long? LastActivity { get; }
[JsonPropertyName("magnet_uri")]
public string? MagnetUri { get; }
[JsonPropertyName("max_ratio")]
public float? MaxRatio { get; }
[JsonPropertyName("max_seeding_time")]
public int? MaxSeedingTime { get; }
[JsonPropertyName("name")]
public string? Name { get; }
[JsonPropertyName("num_complete")]
public int? NumberComplete { get; }
[JsonPropertyName("num_incomplete")]
public int? NumberIncomplete { get; }
[JsonPropertyName("num_leechs")]
public int? NumberLeeches { get; }
[JsonPropertyName("num_seeds")]
public int? NumberSeeds { get; }
[JsonPropertyName("priority")]
public int? Priority { get; }
[JsonPropertyName("progress")]
public float? Progress { get; }
[JsonPropertyName("ratio")]
public float? Ratio { get; }
[JsonPropertyName("ratio_limit")]
public float? RatioLimit { get; }
[JsonPropertyName("save_path")]
public string? SavePath { get; }
[JsonPropertyName("seeding_time")]
public long? SeedingTime { get; }
[JsonPropertyName("seeding_time_limit")]
public int? SeedingTimeLimit { get; }
[JsonPropertyName("seen_complete")]
public long? SeenComplete { get; }
[JsonPropertyName("seq_dl")]
public bool? SequentialDownload { get; }
[JsonPropertyName("size")]
public long? Size { get; }
[JsonPropertyName("state")]
public string? State { get; }
[JsonPropertyName("super_seeding")]
public bool? SuperSeeding { get; }
[JsonPropertyName("tags")]
[JsonConverter(typeof(CommaSeparatedJsonConverter))]
public IReadOnlyList<string>? Tags { get; }
[JsonPropertyName("time_active")]
public int? TimeActive { get; }
[JsonPropertyName("total_size")]
public long? TotalSize { get; }
[JsonPropertyName("tracker")]
public string? Tracker { get; }
[JsonPropertyName("up_limit")]
public long? UploadLimit { get; }
[JsonPropertyName("uploaded")]
public long? Uploaded { get; }
[JsonPropertyName("uploaded_session")]
public long? UploadedSession { get; }
[JsonPropertyName("upspeed")]
public long? UploadSpeed { get; }
[JsonPropertyName("reannounce")]
public long? Reannounce { get; }
}
}

View File

@@ -0,0 +1,37 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record TorrentPeers
{
[JsonConstructor]
public TorrentPeers(
bool fullUpdate,
IReadOnlyDictionary<string, Peer>? peers,
IReadOnlyList<string>? peersRemoved,
int requestId,
bool? showFlags)
{
FullUpdate = fullUpdate;
Peers = peers;
PeersRemoved = peersRemoved;
RequestId = requestId;
ShowFlags = showFlags;
}
[JsonPropertyName("full_update")]
public bool FullUpdate { get; }
[JsonPropertyName("peers")]
public IReadOnlyDictionary<string, Peer>? Peers { get; }
[JsonPropertyName("peers_removed")]
public IReadOnlyList<string>? PeersRemoved { get; }
[JsonPropertyName("rid")]
public int RequestId { get; }
[JsonPropertyName("show_flags")]
public bool? ShowFlags { get; }
}
}

View File

@@ -0,0 +1,187 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record TorrentProperties
{
[JsonConstructor]
public TorrentProperties(
long additionDate,
string comment,
long completionDate,
string createdBy,
long creationDate,
long downloadLimit,
long downloadSpeed,
long downloadSpeedAverage,
int estimatedTimeOfArrival,
long lastSeen,
int connections,
int connectionsLimit,
int peers,
int peersTotal,
int pieceSize,
int piecesHave,
int piecesNum,
int reannounce,
string savePath,
int seedingTime,
int seeds,
int seedsTotal,
float shareRatio,
int timeElapsed,
long totalDownloaded,
long totalDownloadedSession,
long totalSize,
long totalUploaded,
long totalUploadedSession,
long totalWasted,
long uploadLimit,
long uploadSpeed,
long uploadSpeedAverage,
string infoHashV1,
string infoHashV2)
{
AdditionDate = additionDate;
Comment = comment;
CompletionDate = completionDate;
CreatedBy = createdBy;
CreationDate = creationDate;
DownloadLimit = downloadLimit;
DownloadSpeed = downloadSpeed;
DownloadSpeedAverage = downloadSpeedAverage;
EstimatedTimeOfArrival = estimatedTimeOfArrival;
LastSeen = lastSeen;
Connections = connections;
ConnectionsLimit = connectionsLimit;
Peers = peers;
PeersTotal = peersTotal;
PieceSize = pieceSize;
PiecesHave = piecesHave;
PiecesNum = piecesNum;
Reannounce = reannounce;
SavePath = savePath;
SeedingTime = seedingTime;
Seeds = seeds;
SeedsTotal = seedsTotal;
ShareRatio = shareRatio;
TimeElapsed = timeElapsed;
TotalDownloaded = totalDownloaded;
TotalDownloadedSession = totalDownloadedSession;
TotalSize = totalSize;
TotalUploaded = totalUploaded;
TotalUploadedSession = totalUploadedSession;
TotalWasted = totalWasted;
UploadLimit = uploadLimit;
UploadSpeed = uploadSpeed;
UploadSpeedAverage = uploadSpeedAverage;
InfoHashV1 = infoHashV1;
InfoHashV2 = infoHashV2;
}
[JsonPropertyName("addition_date")]
public long AdditionDate { get; }
[JsonPropertyName("comment")]
public string Comment { get; }
[JsonPropertyName("completion_date")]
public long CompletionDate { get; }
[JsonPropertyName("created_by")]
public string CreatedBy { get; }
[JsonPropertyName("creation_date")]
public long CreationDate { get; }
[JsonPropertyName("dl_limit")]
public long DownloadLimit { get; }
[JsonPropertyName("dl_speed")]
public long DownloadSpeed { get; }
[JsonPropertyName("dl_speed_avg")]
public long DownloadSpeedAverage { get; }
[JsonPropertyName("eta")]
public int EstimatedTimeOfArrival { get; }
[JsonPropertyName("last_seen")]
public long LastSeen { get; }
[JsonPropertyName("nb_connections")]
public int Connections { get; }
[JsonPropertyName("nb_connections_limit")]
public int ConnectionsLimit { get; }
[JsonPropertyName("peers")]
public int Peers { get; }
[JsonPropertyName("peers_total")]
public int PeersTotal { get; }
[JsonPropertyName("piece_size")]
public int PieceSize { get; }
[JsonPropertyName("pieces_have")]
public int PiecesHave { get; }
[JsonPropertyName("pieces_num")]
public int PiecesNum { get; }
[JsonPropertyName("reannounce")]
public int Reannounce { get; }
[JsonPropertyName("save_path")]
public string SavePath { get; }
[JsonPropertyName("seeding_time")]
public int SeedingTime { get; }
[JsonPropertyName("seeds")]
public int Seeds { get; }
[JsonPropertyName("seeds_total")]
public int SeedsTotal { get; }
[JsonPropertyName("share_ratio")]
public float ShareRatio { get; }
[JsonPropertyName("time_elapsed")]
public int TimeElapsed { get; }
[JsonPropertyName("total_downloaded")]
public long TotalDownloaded { get; }
[JsonPropertyName("total_downloaded_session")]
public long TotalDownloadedSession { get; }
[JsonPropertyName("total_size")]
public long TotalSize { get; }
[JsonPropertyName("total_uploaded")]
public long TotalUploaded { get; }
[JsonPropertyName("total_uploaded_session")]
public long TotalUploadedSession { get; }
[JsonPropertyName("total_wasted")]
public long TotalWasted { get; }
[JsonPropertyName("up_limit")]
public long UploadLimit { get; }
[JsonPropertyName("up_speed")]
public long UploadSpeed { get; }
[JsonPropertyName("up_speed_avg")]
public long UploadSpeedAverage { get; }
[JsonPropertyName("infohash_v1")]
public string InfoHashV1 { get; }
[JsonPropertyName("infohash_v2")]
public string InfoHashV2 { get; }
}
}

View File

@@ -0,0 +1,52 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record TorrentTrackers
{
[JsonConstructor]
public TorrentTrackers(
string url,
TrackerStatus status,
int tier,
int peers,
int seeds,
int leeches,
int downloads,
string message)
{
Url = url;
Status = status;
Tier = tier;
Peers = peers;
Seeds = seeds;
Leeches = leeches;
Downloads = downloads;
Message = message;
}
[JsonPropertyName("url")]
public string Url { get; }
[JsonPropertyName("status")]
public TrackerStatus Status { get; }
[JsonPropertyName("tier")]
public int Tier { get; }
[JsonPropertyName("num_peers")]
public int Peers { get; }
[JsonPropertyName("num_seeds")]
public int Seeds { get; }
[JsonPropertyName("num_leeches")]
public int Leeches { get; }
[JsonPropertyName("num_downloaded")]
public int Downloads { get; }
[JsonPropertyName("msg")]
public string Message { get; }
}
}

View File

@@ -0,0 +1,11 @@
namespace Lantean.QBitTorrentClient.Models
{
public enum TrackerStatus
{
Disabled = 0,
Uncontacted = 1,
Working = 2,
Updating = 3,
NotWorking = 4,
}
}

View File

@@ -0,0 +1,613 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record UpdatePreferences
{
[JsonPropertyName("add_to_top_of_queue")]
public bool? AddToTopOfQueue { get; set; }
[JsonPropertyName("add_trackers")]
public string? AddTrackers { get; set; }
[JsonPropertyName("add_trackers_enabled")]
public bool? AddTrackersEnabled { get; set; }
[JsonPropertyName("alt_dl_limit")]
public int? AltDlLimit { get; set; }
[JsonPropertyName("alt_up_limit")]
public int? AltUpLimit { get; set; }
[JsonPropertyName("alternative_webui_enabled")]
public bool? AlternativeWebuiEnabled { get; set; }
[JsonPropertyName("alternative_webui_path")]
public string? AlternativeWebuiPath { get; set; }
[JsonPropertyName("announce_ip")]
public string? AnnounceIp { get; set; }
[JsonPropertyName("announce_to_all_tiers")]
public bool? AnnounceToAllTiers { get; set; }
[JsonPropertyName("announce_to_all_trackers")]
public bool? AnnounceToAllTrackers { get; set; }
[JsonPropertyName("anonymous_mode")]
public bool? AnonymousMode { get; set; }
[JsonPropertyName("async_io_threads")]
public int? AsyncIoThreads { get; set; }
[JsonPropertyName("auto_delete_mode")]
public int? AutoDeleteMode { get; set; }
[JsonPropertyName("auto_tmm_enabled")]
public bool? AutoTmmEnabled { get; set; }
[JsonPropertyName("autorun_enabled")]
public bool? AutorunEnabled { get; set; }
[JsonPropertyName("autorun_on_torrent_added_enabled")]
public bool? AutorunOnTorrentAddedEnabled { get; set; }
[JsonPropertyName("autorun_on_torrent_added_program")]
public string? AutorunOnTorrentAddedProgram { get; set; }
[JsonPropertyName("autorun_program")]
public string? AutorunProgram { get; set; }
[JsonPropertyName("banned_IPs")]
public string? BannedIPs { get; set; }
[JsonPropertyName("bdecode_depth_limit")]
public int? BdecodeDepthLimit { get; set; }
[JsonPropertyName("bdecode_token_limit")]
public int? BdecodeTokenLimit { get; set; }
[JsonPropertyName("bittorrent_protocol")]
public int? BittorrentProtocol { get; set; }
[JsonPropertyName("block_peers_on_privileged_ports")]
public bool? BlockPeersOnPrivilegedPorts { get; set; }
[JsonPropertyName("bypass_auth_subnet_whitelist")]
public string? BypassAuthSubnetWhitelist { get; set; }
[JsonPropertyName("bypass_auth_subnet_whitelist_enabled")]
public bool? BypassAuthSubnetWhitelistEnabled { get; set; }
[JsonPropertyName("bypass_local_auth")]
public bool? BypassLocalAuth { get; set; }
[JsonPropertyName("category_changed_tmm_enabled")]
public bool? CategoryChangedTmmEnabled { get; set; }
[JsonPropertyName("checking_memory_use")]
public int? CheckingMemoryUse { get; set; }
[JsonPropertyName("connection_speed")]
public int? ConnectionSpeed { get; set; }
[JsonPropertyName("current_interface_address")]
public string? CurrentInterfaceAddress { get; set; }
[JsonPropertyName("current_interface_name")]
public string? CurrentInterfaceName { get; set; }
[JsonPropertyName("current_network_interface")]
public string? CurrentNetworkInterface { get; set; }
[JsonPropertyName("dht")]
public bool? Dht { get; set; }
[JsonPropertyName("disk_cache")]
public int? DiskCache { get; set; }
[JsonPropertyName("disk_cache_ttl")]
public int? DiskCacheTtl { get; set; }
[JsonPropertyName("disk_io_read_mode")]
public int? DiskIoReadMode { get; set; }
[JsonPropertyName("disk_io_type")]
public int? DiskIoType { get; set; }
[JsonPropertyName("disk_io_write_mode")]
public int? DiskIoWriteMode { get; set; }
[JsonPropertyName("disk_queue_size")]
public int? DiskQueueSize { get; set; }
[JsonPropertyName("dl_limit")]
public int? DlLimit { get; set; }
[JsonPropertyName("dont_count_slow_torrents")]
public bool? DontCountSlowTorrents { get; set; }
[JsonPropertyName("dyndns_domain")]
public string? DyndnsDomain { get; set; }
[JsonPropertyName("dyndns_enabled")]
public bool? DyndnsEnabled { get; set; }
[JsonPropertyName("dyndns_password")]
public string? DyndnsPassword { get; set; }
[JsonPropertyName("dyndns_service")]
public int? DyndnsService { get; set; }
[JsonPropertyName("dyndns_username")]
public string? DyndnsUsername { get; set; }
[JsonPropertyName("embedded_tracker_port")]
public int? EmbeddedTrackerPort { get; set; }
[JsonPropertyName("embedded_tracker_port_forwarding")]
public bool? EmbeddedTrackerPortForwarding { get; set; }
[JsonPropertyName("enable_coalesce_read_write")]
public bool? EnableCoalesceReadWrite { get; set; }
[JsonPropertyName("enable_embedded_tracker")]
public bool? EnableEmbeddedTracker { get; set; }
[JsonPropertyName("enable_multi_connections_from_same_ip")]
public bool? EnableMultiConnectionsFromSameIp { get; set; }
[JsonPropertyName("enable_piece_extent_affinity")]
public bool? EnablePieceExtentAffinity { get; set; }
[JsonPropertyName("enable_upload_suggestions")]
public bool? EnableUploadSuggestions { get; set; }
[JsonPropertyName("encryption")]
public int? Encryption { get; set; }
[JsonPropertyName("excluded_file_names")]
public string? ExcludedFileNames { get; set; }
[JsonPropertyName("excluded_file_names_enabled")]
public bool? ExcludedFileNamesEnabled { get; set; }
[JsonPropertyName("export_dir")]
public string? ExportDir { get; set; }
[JsonPropertyName("export_dir_fin")]
public string? ExportDirFin { get; set; }
[JsonPropertyName("file_log_age")]
public int? FileLogAge { get; set; }
[JsonPropertyName("file_log_age_type")]
public int? FileLogAgeType { get; set; }
[JsonPropertyName("file_log_backup_enabled")]
public bool? FileLogBackupEnabled { get; set; }
[JsonPropertyName("file_log_delete_old")]
public bool? FileLogDeleteOld { get; set; }
[JsonPropertyName("file_log_enabled")]
public bool? FileLogEnabled { get; set; }
[JsonPropertyName("file_log_max_size")]
public int? FileLogMaxSize { get; set; }
[JsonPropertyName("file_log_path")]
public string? FileLogPath { get; set; }
[JsonPropertyName("file_pool_size")]
public int? FilePoolSize { get; set; }
[JsonPropertyName("hashing_threads")]
public int? HashingThreads { get; set; }
[JsonPropertyName("i2p_address")]
public string? I2pAddress { get; set; }
[JsonPropertyName("i2p_enabled")]
public bool? I2pEnabled { get; set; }
[JsonPropertyName("i2p_inbound_length")]
public int? I2pInboundLength { get; set; }
[JsonPropertyName("i2p_inbound_quantity")]
public int? I2pInboundQuantity { get; set; }
[JsonPropertyName("i2p_mixed_mode")]
public bool? I2pMixedMode { get; set; }
[JsonPropertyName("i2p_outbound_length")]
public int? I2pOutboundLength { get; set; }
[JsonPropertyName("i2p_outbound_quantity")]
public int? I2pOutboundQuantity { get; set; }
[JsonPropertyName("i2p_port")]
public int? I2pPort { get; set; }
[JsonPropertyName("idn_support_enabled")]
public bool? IdnSupportEnabled { get; set; }
[JsonPropertyName("incomplete_files_ext")]
public bool? IncompleteFilesExt { get; set; }
[JsonPropertyName("ip_filter_enabled")]
public bool? IpFilterEnabled { get; set; }
[JsonPropertyName("ip_filter_path")]
public string? IpFilterPath { get; set; }
[JsonPropertyName("ip_filter_trackers")]
public bool? IpFilterTrackers { get; set; }
[JsonPropertyName("limit_lan_peers")]
public bool? LimitLanPeers { get; set; }
[JsonPropertyName("limit_tcp_overhead")]
public bool? LimitTcpOverhead { get; set; }
[JsonPropertyName("limit_utp_rate")]
public bool? LimitUtpRate { get; set; }
[JsonPropertyName("listen_port")]
public int? ListenPort { get; set; }
[JsonPropertyName("locale")]
public string? Locale { get; set; }
[JsonPropertyName("lsd")]
public bool? Lsd { get; set; }
[JsonPropertyName("mail_notification_auth_enabled")]
public bool? MailNotificationAuthEnabled { get; set; }
[JsonPropertyName("mail_notification_email")]
public string? MailNotificationEmail { get; set; }
[JsonPropertyName("mail_notification_enabled")]
public bool? MailNotificationEnabled { get; set; }
[JsonPropertyName("mail_notification_password")]
public string? MailNotificationPassword { get; set; }
[JsonPropertyName("mail_notification_sender")]
public string? MailNotificationSender { get; set; }
[JsonPropertyName("mail_notification_smtp")]
public string? MailNotificationSmtp { get; set; }
[JsonPropertyName("mail_notification_ssl_enabled")]
public bool? MailNotificationSslEnabled { get; set; }
[JsonPropertyName("mail_notification_username")]
public string? MailNotificationUsername { get; set; }
[JsonPropertyName("max_active_checking_torrents")]
public int? MaxActiveCheckingTorrents { get; set; }
[JsonPropertyName("max_active_downloads")]
public int? MaxActiveDownloads { get; set; }
[JsonPropertyName("max_active_torrents")]
public int? MaxActiveTorrents { get; set; }
[JsonPropertyName("max_active_uploads")]
public int? MaxActiveUploads { get; set; }
[JsonPropertyName("max_concurrent_http_announces")]
public int? MaxConcurrentHttpAnnounces { get; set; }
[JsonPropertyName("max_connec")]
public int? MaxConnec { get; set; }
[JsonPropertyName("max_connec_per_torrent")]
public int? MaxConnecPerTorrent { get; set; }
[JsonPropertyName("max_inactive_seeding_time")]
public int? MaxInactiveSeedingTime { get; set; }
[JsonPropertyName("max_inactive_seeding_time_enabled")]
public bool? MaxInactiveSeedingTimeEnabled { get; set; }
[JsonPropertyName("max_ratio")]
public int? MaxRatio { get; set; }
[JsonPropertyName("max_ratio_act")]
public int? MaxRatioAct { get; set; }
[JsonPropertyName("max_ratio_enabled")]
public bool? MaxRatioEnabled { get; set; }
[JsonPropertyName("max_seeding_time")]
public int? MaxSeedingTime { get; set; }
[JsonPropertyName("max_seeding_time_enabled")]
public bool? MaxSeedingTimeEnabled { get; set; }
[JsonPropertyName("max_uploads")]
public int? MaxUploads { get; set; }
[JsonPropertyName("max_uploads_per_torrent")]
public int? MaxUploadsPerTorrent { get; set; }
[JsonPropertyName("memory_working_set_limit")]
public int? MemoryWorkingSetLimit { get; set; }
[JsonPropertyName("merge_trackers")]
public bool? MergeTrackers { get; set; }
[JsonPropertyName("outgoing_ports_max")]
public int? OutgoingPortsMax { get; set; }
[JsonPropertyName("outgoing_ports_min")]
public int? OutgoingPortsMin { get; set; }
[JsonPropertyName("peer_tos")]
public int? PeerTos { get; set; }
[JsonPropertyName("peer_turnover")]
public int? PeerTurnover { get; set; }
[JsonPropertyName("peer_turnover_cutoff")]
public int? PeerTurnoverCutoff { get; set; }
[JsonPropertyName("peer_turnover_interval")]
public int? PeerTurnoverInterval { get; set; }
[JsonPropertyName("performance_warning")]
public bool? PerformanceWarning { get; set; }
[JsonPropertyName("pex")]
public bool? Pex { get; set; }
[JsonPropertyName("preallocate_all")]
public bool? PreallocateAll { get; set; }
[JsonPropertyName("proxy_auth_enabled")]
public bool? ProxyAuthEnabled { get; set; }
[JsonPropertyName("proxy_bittorrent")]
public bool? ProxyBittorrent { get; set; }
[JsonPropertyName("proxy_hostname_lookup")]
public bool? ProxyHostnameLookup { get; set; }
[JsonPropertyName("proxy_ip")]
public string? ProxyIp { get; set; }
[JsonPropertyName("proxy_misc")]
public bool? ProxyMisc { get; set; }
[JsonPropertyName("proxy_password")]
public string? ProxyPassword { get; set; }
[JsonPropertyName("proxy_peer_connections")]
public bool? ProxyPeerConnections { get; set; }
[JsonPropertyName("proxy_port")]
public int? ProxyPort { get; set; }
[JsonPropertyName("proxy_rss")]
public bool? ProxyRss { get; set; }
[JsonPropertyName("proxy_type")]
public string? ProxyType { get; set; }
[JsonPropertyName("proxy_username")]
public string? ProxyUsername { get; set; }
[JsonPropertyName("queueing_enabled")]
public bool? QueueingEnabled { get; set; }
[JsonPropertyName("random_port")]
public bool? RandomPort { get; set; }
[JsonPropertyName("reannounce_when_address_changed")]
public bool? ReannounceWhenAddressChanged { get; set; }
[JsonPropertyName("recheck_completed_torrents")]
public bool? RecheckCompletedTorrents { get; set; }
[JsonPropertyName("refresh_interval")]
public int? RefreshInterval { get; set; }
[JsonPropertyName("request_queue_size")]
public int? RequestQueueSize { get; set; }
[JsonPropertyName("resolve_peer_countries")]
public bool? ResolvePeerCountries { get; set; }
[JsonPropertyName("resume_data_storage_type")]
public string? ResumeDataStorageType { get; set; }
[JsonPropertyName("rss_auto_downloading_enabled")]
public bool? RssAutoDownloadingEnabled { get; set; }
[JsonPropertyName("rss_download_repack_proper_episodes")]
public bool? RssDownloadRepackProperEpisodes { get; set; }
[JsonPropertyName("rss_max_articles_per_feed")]
public int? RssMaxArticlesPerFeed { get; set; }
[JsonPropertyName("rss_processing_enabled")]
public bool? RssProcessingEnabled { get; set; }
[JsonPropertyName("rss_refresh_interval")]
public int? RssRefreshInterval { get; set; }
[JsonPropertyName("rss_smart_episode_filters")]
public string? RssSmartEpisodeFilters { get; set; }
[JsonPropertyName("save_path")]
public string? SavePath { get; set; }
[JsonPropertyName("save_path_changed_tmm_enabled")]
public bool? SavePathChangedTmmEnabled { get; set; }
[JsonPropertyName("save_resume_data_interval")]
public int? SaveResumeDataInterval { get; set; }
[JsonPropertyName("scan_dirs")]
public Dictionary<string, SaveLocation>? ScanDirs { get; set; }
[JsonPropertyName("schedule_from_hour")]
public int? ScheduleFromHour { get; set; }
[JsonPropertyName("schedule_from_min")]
public int? ScheduleFromMin { get; set; }
[JsonPropertyName("schedule_to_hour")]
public int? ScheduleToHour { get; set; }
[JsonPropertyName("schedule_to_min")]
public int? ScheduleToMin { get; set; }
[JsonPropertyName("scheduler_days")]
public int? SchedulerDays { get; set; }
[JsonPropertyName("scheduler_enabled")]
public bool? SchedulerEnabled { get; set; }
[JsonPropertyName("send_buffer_low_watermark")]
public int? SendBufferLowWatermark { get; set; }
[JsonPropertyName("send_buffer_watermark")]
public int? SendBufferWatermark { get; set; }
[JsonPropertyName("send_buffer_watermark_factor")]
public int? SendBufferWatermarkFactor { get; set; }
[JsonPropertyName("slow_torrent_dl_rate_threshold")]
public int? SlowTorrentDlRateThreshold { get; set; }
[JsonPropertyName("slow_torrent_inactive_timer")]
public int? SlowTorrentInactiveTimer { get; set; }
[JsonPropertyName("slow_torrent_ul_rate_threshold")]
public int? SlowTorrentUlRateThreshold { get; set; }
[JsonPropertyName("socket_backlog_size")]
public int? SocketBacklogSize { get; set; }
[JsonPropertyName("socket_receive_buffer_size")]
public int? SocketReceiveBufferSize { get; set; }
[JsonPropertyName("socket_send_buffer_size")]
public int? SocketSendBufferSize { get; set; }
[JsonPropertyName("ssrf_mitigation")]
public bool? SsrfMitigation { get; set; }
[JsonPropertyName("start_paused_enabled")]
public bool? StartPausedEnabled { get; set; }
[JsonPropertyName("stop_tracker_timeout")]
public int? StopTrackerTimeout { get; set; }
[JsonPropertyName("temp_path")]
public string? TempPath { get; set; }
[JsonPropertyName("temp_path_enabled")]
public bool? TempPathEnabled { get; set; }
[JsonPropertyName("torrent_changed_tmm_enabled")]
public bool? TorrentChangedTmmEnabled { get; set; }
[JsonPropertyName("torrent_content_layout")]
public string? TorrentContentLayout { get; set; }
[JsonPropertyName("torrent_file_size_limit")]
public int? TorrentFileSizeLimit { get; set; }
[JsonPropertyName("torrent_stop_condition")]
public string? TorrentStopCondition { get; set; }
[JsonPropertyName("up_limit")]
public int? UpLimit { get; set; }
[JsonPropertyName("upload_choking_algorithm")]
public int? UploadChokingAlgorithm { get; set; }
[JsonPropertyName("upload_slots_behavior")]
public int? UploadSlotsBehavior { get; set; }
[JsonPropertyName("upnp")]
public bool? Upnp { get; set; }
[JsonPropertyName("upnp_lease_duration")]
public int? UpnpLeaseDuration { get; set; }
[JsonPropertyName("use_category_paths_in_manual_mode")]
public bool? UseCategoryPathsInManualMode { get; set; }
[JsonPropertyName("use_https")]
public bool? UseHttps { get; set; }
[JsonPropertyName("use_subcategories")]
public bool? UseSubcategories { get; set; }
[JsonPropertyName("utp_tcp_mixed_mode")]
public int? UtpTcpMixedMode { get; set; }
[JsonPropertyName("validate_https_tracker_certificate")]
public bool? ValidateHttpsTrackerCertificate { get; set; }
[JsonPropertyName("web_ui_address")]
public string? WebUiAddress { get; set; }
[JsonPropertyName("web_ui_ban_duration")]
public int? WebUiBanDuration { get; set; }
[JsonPropertyName("web_ui_clickjacking_protection_enabled")]
public bool? WebUiClickjackingProtectionEnabled { get; set; }
[JsonPropertyName("web_ui_csrf_protection_enabled")]
public bool? WebUiCsrfProtectionEnabled { get; set; }
[JsonPropertyName("web_ui_custom_http_headers")]
public string? WebUiCustomHttpHeaders { get; set; }
[JsonPropertyName("web_ui_domain_list")]
public string? WebUiDomainList { get; set; }
[JsonPropertyName("web_ui_host_header_validation_enabled")]
public bool? WebUiHostHeaderValidationEnabled { get; set; }
[JsonPropertyName("web_ui_https_cert_path")]
public string? WebUiHttpsCertPath { get; set; }
[JsonPropertyName("web_ui_https_key_path")]
public string? WebUiHttpsKeyPath { get; set; }
[JsonPropertyName("web_ui_max_auth_fail_count")]
public int? WebUiMaxAuthFailCount { get; set; }
[JsonPropertyName("web_ui_port")]
public int? WebUiPort { get; set; }
[JsonPropertyName("web_ui_reverse_proxies_list")]
public string? WebUiReverseProxiesList { get; set; }
[JsonPropertyName("web_ui_reverse_proxy_enabled")]
public bool? WebUiReverseProxyEnabled { get; set; }
[JsonPropertyName("web_ui_secure_cookie_enabled")]
public bool? WebUiSecureCookieEnabled { get; set; }
[JsonPropertyName("web_ui_session_timeout")]
public int? WebUiSessionTimeout { get; set; }
[JsonPropertyName("web_ui_upnp")]
public bool? WebUiUpnp { get; set; }
[JsonPropertyName("web_ui_use_custom_http_headers_enabled")]
public bool? WebUiUseCustomHttpHeadersEnabled { get; set; }
[JsonPropertyName("web_ui_username")]
public string? WebUiUsername { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using System.Text.Json.Serialization;
namespace Lantean.QBitTorrentClient.Models
{
public record WebSeed
{
[JsonConstructor]
public WebSeed(string url)
{
Url = url;
}
[JsonPropertyName("url")]
public string Url { get; }
}
}