aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Model
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2016-10-25 15:02:04 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2016-10-25 15:02:04 -0400
commitef6b90b8e6e6c317fcda85a392c79324f91250db (patch)
tree570c78c0915d3608399f003038b66d56e5e29e84 /MediaBrowser.Model
parentedbe28d9fc3091121b7e2323fe42d62a70c9e351 (diff)
make controller project portable
Diffstat (limited to 'MediaBrowser.Model')
-rw-r--r--MediaBrowser.Model/Globalization/ILocalizationManager.cs2
-rw-r--r--MediaBrowser.Model/IO/FileSystemMetadata.cs56
-rw-r--r--MediaBrowser.Model/IO/IFileSystem.cs414
-rw-r--r--MediaBrowser.Model/IO/IShortcutHandler.cs25
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj15
-rw-r--r--MediaBrowser.Model/Services/ApiMemberAttribute.cs61
-rw-r--r--MediaBrowser.Model/Services/IAsyncStreamWriter.cs11
-rw-r--r--MediaBrowser.Model/Services/IHasHeaders.cs9
-rw-r--r--MediaBrowser.Model/Services/IHasRequestFilter.cs32
-rw-r--r--MediaBrowser.Model/Services/IHttpRequest.cs46
-rw-r--r--MediaBrowser.Model/Services/IHttpResponse.cs25
-rw-r--r--MediaBrowser.Model/Services/IRequest.cs200
-rw-r--r--MediaBrowser.Model/Services/IRequiresRequestStream.cs12
-rw-r--r--MediaBrowser.Model/Services/IService.cs12
-rw-r--r--MediaBrowser.Model/Services/IStreamWriter.cs9
-rw-r--r--MediaBrowser.Model/Services/QueryParamCollection.cs164
-rw-r--r--MediaBrowser.Model/Services/RouteAttribute.cs144
17 files changed, 1237 insertions, 0 deletions
diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
index 6bac81805..b0e1d7fa6 100644
--- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs
+++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
@@ -50,5 +50,7 @@ namespace MediaBrowser.Model.Globalization
/// </summary>
/// <returns>IEnumerable{LocalizatonOption}.</returns>
IEnumerable<LocalizatonOption> GetLocalizationOptions();
+
+ string RemoveDiacritics(string text);
}
}
diff --git a/MediaBrowser.Model/IO/FileSystemMetadata.cs b/MediaBrowser.Model/IO/FileSystemMetadata.cs
new file mode 100644
index 000000000..2aae4bb54
--- /dev/null
+++ b/MediaBrowser.Model/IO/FileSystemMetadata.cs
@@ -0,0 +1,56 @@
+using System;
+
+namespace MediaBrowser.Model.IO
+{
+ public class FileSystemMetadata
+ {
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="FileSystemMetadata"/> is exists.
+ /// </summary>
+ /// <value><c>true</c> if exists; otherwise, <c>false</c>.</value>
+ public bool Exists { get; set; }
+ /// <summary>
+ /// Gets or sets the full name.
+ /// </summary>
+ /// <value>The full name.</value>
+ public string FullName { get; set; }
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public string Name { get; set; }
+ /// <summary>
+ /// Gets or sets the extension.
+ /// </summary>
+ /// <value>The extension.</value>
+ public string Extension { get; set; }
+ /// <summary>
+ /// Gets or sets the length.
+ /// </summary>
+ /// <value>The length.</value>
+ public long Length { get; set; }
+ /// <summary>
+ /// Gets or sets the name of the directory.
+ /// </summary>
+ /// <value>The name of the directory.</value>
+ public string DirectoryName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the last write time UTC.
+ /// </summary>
+ /// <value>The last write time UTC.</value>
+ public DateTime LastWriteTimeUtc { get; set; }
+ /// <summary>
+ /// Gets or sets the creation time UTC.
+ /// </summary>
+ /// <value>The creation time UTC.</value>
+ public DateTime CreationTimeUtc { get; set; }
+ /// <summary>
+ /// Gets a value indicating whether this instance is directory.
+ /// </summary>
+ /// <value><c>true</c> if this instance is directory; otherwise, <c>false</c>.</value>
+ public bool IsDirectory { get; set; }
+ public bool IsHidden { get; set; }
+ public bool IsReadOnly { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs
new file mode 100644
index 000000000..4ff4fc604
--- /dev/null
+++ b/MediaBrowser.Model/IO/IFileSystem.cs
@@ -0,0 +1,414 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace MediaBrowser.Model.IO
+{
+ /// <summary>
+ /// Interface IFileSystem
+ /// </summary>
+ public interface IFileSystem
+ {
+ /// <summary>
+ /// Determines whether the specified filename is shortcut.
+ /// </summary>
+ /// <param name="filename">The filename.</param>
+ /// <returns><c>true</c> if the specified filename is shortcut; otherwise, <c>false</c>.</returns>
+ bool IsShortcut(string filename);
+
+ /// <summary>
+ /// Resolves the shortcut.
+ /// </summary>
+ /// <param name="filename">The filename.</param>
+ /// <returns>System.String.</returns>
+ string ResolveShortcut(string filename);
+
+ /// <summary>
+ /// Creates the shortcut.
+ /// </summary>
+ /// <param name="shortcutPath">The shortcut path.</param>
+ /// <param name="target">The target.</param>
+ void CreateShortcut(string shortcutPath, string target);
+
+ /// <summary>
+ /// Returns a <see cref="FileSystemMetadata"/> object for the specified file or directory path.
+ /// </summary>
+ /// <param name="path">A path to a file or directory.</param>
+ /// <returns>A <see cref="FileSystemMetadata"/> object.</returns>
+ /// <remarks>If the specified path points to a directory, the returned <see cref="FileSystemMetadata"/> object's
+ /// <see cref="FileSystemMetadata.IsDirectory"/> property will be set to true and all other properties will reflect the properties of the directory.</remarks>
+ FileSystemMetadata GetFileSystemInfo(string path);
+
+ /// <summary>
+ /// Returns a <see cref="FileSystemMetadata"/> object for the specified file path.
+ /// </summary>
+ /// <param name="path">A path to a file.</param>
+ /// <returns>A <see cref="FileSystemMetadata"/> object.</returns>
+ /// <remarks><para>If the specified path points to a directory, the returned <see cref="FileSystemMetadata"/> object's
+ /// <see cref="FileSystemMetadata.IsDirectory"/> property and the <see cref="FileSystemMetadata.Exists"/> property will both be set to false.</para>
+ /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo"/>.</para></remarks>
+ FileSystemMetadata GetFileInfo(string path);
+
+ /// <summary>
+ /// Returns a <see cref="FileSystemMetadata"/> object for the specified directory path.
+ /// </summary>
+ /// <param name="path">A path to a directory.</param>
+ /// <returns>A <see cref="FileSystemMetadata"/> object.</returns>
+ /// <remarks><para>If the specified path points to a file, the returned <see cref="FileSystemMetadata"/> object's
+ /// <see cref="FileSystemMetadata.IsDirectory"/> property will be set to true and the <see cref="FileSystemMetadata.Exists"/> property will be set to false.</para>
+ /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo"/>.</para></remarks>
+ FileSystemMetadata GetDirectoryInfo(string path);
+
+ /// <summary>
+ /// Gets the valid filename.
+ /// </summary>
+ /// <param name="filename">The filename.</param>
+ /// <returns>System.String.</returns>
+ string GetValidFilename(string filename);
+
+ /// <summary>
+ /// Gets the creation time UTC.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <returns>DateTime.</returns>
+ DateTime GetCreationTimeUtc(FileSystemMetadata info);
+
+ /// <summary>
+ /// Gets the creation time UTC.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>DateTime.</returns>
+ DateTime GetCreationTimeUtc(string path);
+
+ /// <summary>
+ /// Gets the last write time UTC.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <returns>DateTime.</returns>
+ DateTime GetLastWriteTimeUtc(FileSystemMetadata info);
+
+ /// <summary>
+ /// Gets the last write time UTC.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>DateTime.</returns>
+ DateTime GetLastWriteTimeUtc(string path);
+
+ /// <summary>
+ /// Gets the file stream.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="mode">The mode.</param>
+ /// <param name="access">The access.</param>
+ /// <param name="share">The share.</param>
+ /// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
+ /// <returns>FileStream.</returns>
+ Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, bool isAsync = false);
+
+ /// <summary>
+ /// Opens the read.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>Stream.</returns>
+ Stream OpenRead(String path);
+
+ /// <summary>
+ /// Swaps the files.
+ /// </summary>
+ /// <param name="file1">The file1.</param>
+ /// <param name="file2">The file2.</param>
+ void SwapFiles(string file1, string file2);
+
+ /// <summary>
+ /// Determines whether [contains sub path] [the specified parent path].
+ /// </summary>
+ /// <param name="parentPath">The parent path.</param>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if [contains sub path] [the specified parent path]; otherwise, <c>false</c>.</returns>
+ bool ContainsSubPath(string parentPath, string path);
+
+ /// <summary>
+ /// Determines whether [is root path] [the specified path].
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if [is root path] [the specified path]; otherwise, <c>false</c>.</returns>
+ bool IsRootPath(string path);
+
+ /// <summary>
+ /// Normalizes the path.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>System.String.</returns>
+ string NormalizePath(string path);
+
+ /// <summary>
+ /// Gets the file name without extension.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <returns>System.String.</returns>
+ string GetFileNameWithoutExtension(FileSystemMetadata info);
+
+ /// <summary>
+ /// Gets the file name without extension.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>System.String.</returns>
+ string GetFileNameWithoutExtension(string path);
+
+ /// <summary>
+ /// Determines whether [is path file] [the specified path].
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if [is path file] [the specified path]; otherwise, <c>false</c>.</returns>
+ bool IsPathFile(string path);
+
+ /// <summary>
+ /// Deletes the file.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ void DeleteFile(string path);
+
+ /// <summary>
+ /// Deletes the directory.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+ void DeleteDirectory(string path, bool recursive);
+
+ /// <summary>
+ /// Gets the directories.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+ /// <returns>IEnumerable&lt;DirectoryInfo&gt;.</returns>
+ IEnumerable<FileSystemMetadata> GetDirectories(string path, bool recursive = false);
+
+ /// <summary>
+ /// Gets the files.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+ /// <returns>IEnumerable&lt;FileInfo&gt;.</returns>
+ IEnumerable<FileSystemMetadata> GetFiles(string path, bool recursive = false);
+
+ /// <summary>
+ /// Gets the file system entries.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+ /// <returns>IEnumerable&lt;FileSystemMetadata&gt;.</returns>
+ IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false);
+
+ /// <summary>
+ /// Creates the directory.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ void CreateDirectory(string path);
+
+ /// <summary>
+ /// Copies the file.
+ /// </summary>
+ /// <param name="source">The source.</param>
+ /// <param name="target">The target.</param>
+ /// <param name="overwrite">if set to <c>true</c> [overwrite].</param>
+ void CopyFile(string source, string target, bool overwrite);
+
+ /// <summary>
+ /// Moves the file.
+ /// </summary>
+ /// <param name="source">The source.</param>
+ /// <param name="target">The target.</param>
+ void MoveFile(string source, string target);
+
+ /// <summary>
+ /// Moves the directory.
+ /// </summary>
+ /// <param name="source">The source.</param>
+ /// <param name="target">The target.</param>
+ void MoveDirectory(string source, string target);
+
+ /// <summary>
+ /// Directories the exists.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
+ bool DirectoryExists(string path);
+
+ /// <summary>
+ /// Files the exists.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
+ bool FileExists(string path);
+
+ /// <summary>
+ /// Reads all text.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>System.String.</returns>
+ string ReadAllText(string path);
+
+ /// <summary>
+ /// Writes all text.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="text">The text.</param>
+ void WriteAllText(string path, string text);
+
+ /// <summary>
+ /// Writes all text.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="text">The text.</param>
+ /// <param name="encoding">The encoding.</param>
+ void WriteAllText(string path, string text, Encoding encoding);
+
+ /// <summary>
+ /// Reads all text.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="encoding">The encoding.</param>
+ /// <returns>System.String.</returns>
+ string ReadAllText(string path, Encoding encoding);
+
+ /// <summary>
+ /// Gets the directory paths.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+ /// <returns>IEnumerable&lt;System.String&gt;.</returns>
+ IEnumerable<string> GetDirectoryPaths(string path, bool recursive = false);
+
+ /// <summary>
+ /// Gets the file paths.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+ /// <returns>IEnumerable&lt;System.String&gt;.</returns>
+ IEnumerable<string> GetFilePaths(string path, bool recursive = false);
+
+ /// <summary>
+ /// Gets the file system entry paths.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+ /// <returns>IEnumerable&lt;System.String&gt;.</returns>
+ IEnumerable<string> GetFileSystemEntryPaths(string path, bool recursive = false);
+
+ void SetHidden(string path, bool isHidden);
+ }
+
+ public enum FileOpenMode
+ {
+ //
+ // Summary:
+ // Specifies that the operating system should create a new file. This requires System.Security.Permissions.FileIOPermissionAccess.Write
+ // permission. If the file already exists, an System.IO.IOException exception is
+ // thrown.
+ CreateNew = 1,
+ //
+ // Summary:
+ // Specifies that the operating system should create a new file. If the file already
+ // exists, it will be overwritten. This requires System.Security.Permissions.FileIOPermissionAccess.Write
+ // permission. FileMode.Create is equivalent to requesting that if the file does
+ // not exist, use System.IO.FileMode.CreateNew; otherwise, use System.IO.FileMode.Truncate.
+ // If the file already exists but is a hidden file, an System.UnauthorizedAccessException
+ // exception is thrown.
+ Create = 2,
+ //
+ // Summary:
+ // Specifies that the operating system should open an existing file. The ability
+ // to open the file is dependent on the value specified by the System.IO.FileAccess
+ // enumeration. A System.IO.FileNotFoundException exception is thrown if the file
+ // does not exist.
+ Open = 3,
+ //
+ // Summary:
+ // Specifies that the operating system should open a file if it exists; otherwise,
+ // a new file should be created. If the file is opened with FileAccess.Read, System.Security.Permissions.FileIOPermissionAccess.Read
+ // permission is required. If the file access is FileAccess.Write, System.Security.Permissions.FileIOPermissionAccess.Write
+ // permission is required. If the file is opened with FileAccess.ReadWrite, both
+ // System.Security.Permissions.FileIOPermissionAccess.Read and System.Security.Permissions.FileIOPermissionAccess.Write
+ // permissions are required.
+ OpenOrCreate = 4,
+ //
+ // Summary:
+ // Specifies that the operating system should open an existing file. When the file
+ // is opened, it should be truncated so that its size is zero bytes. This requires
+ // System.Security.Permissions.FileIOPermissionAccess.Write permission. Attempts
+ // to read from a file opened with FileMode.Truncate cause an System.ArgumentException
+ // exception.
+ Truncate = 5,
+ //
+ // Summary:
+ // Opens the file if it exists and seeks to the end of the file, or creates a new
+ // file. This requires System.Security.Permissions.FileIOPermissionAccess.Append
+ // permission. FileMode.Append can be used only in conjunction with FileAccess.Write.
+ // Trying to seek to a position before the end of the file throws an System.IO.IOException
+ // exception, and any attempt to read fails and throws a System.NotSupportedException
+ // exception.
+ Append = 6
+ }
+
+ [Flags]
+ public enum FileAccessMode
+ {
+ //
+ // Summary:
+ // Read access to the file. Data can be read from the file. Combine with Write for
+ // read/write access.
+ Read = 1,
+ //
+ // Summary:
+ // Write access to the file. Data can be written to the file. Combine with Read
+ // for read/write access.
+ Write = 2,
+ //
+ // Summary:
+ // Read and write access to the file. Data can be written to and read from the file.
+ ReadWrite = 3
+ }
+
+ [Flags]
+ public enum FileShareMode
+ {
+ //
+ // Summary:
+ // Declines sharing of the current file. Any request to open the file (by this process
+ // or another process) will fail until the file is closed.
+ None = 0,
+ //
+ // Summary:
+ // Allows subsequent opening of the file for reading. If this flag is not specified,
+ // any request to open the file for reading (by this process or another process)
+ // will fail until the file is closed. However, even if this flag is specified,
+ // additional permissions might still be needed to access the file.
+ Read = 1,
+ //
+ // Summary:
+ // Allows subsequent opening of the file for writing. If this flag is not specified,
+ // any request to open the file for writing (by this process or another process)
+ // will fail until the file is closed. However, even if this flag is specified,
+ // additional permissions might still be needed to access the file.
+ Write = 2,
+ //
+ // Summary:
+ // Allows subsequent opening of the file for reading or writing. If this flag is
+ // not specified, any request to open the file for reading or writing (by this process
+ // or another process) will fail until the file is closed. However, even if this
+ // flag is specified, additional permissions might still be needed to access the
+ // file.
+ ReadWrite = 3,
+ //
+ // Summary:
+ // Allows subsequent deleting of a file.
+ Delete = 4,
+ //
+ // Summary:
+ // Makes the file handle inheritable by child processes. This is not directly supported
+ // by Win32.
+ Inheritable = 16
+ }
+
+}
diff --git a/MediaBrowser.Model/IO/IShortcutHandler.cs b/MediaBrowser.Model/IO/IShortcutHandler.cs
new file mode 100644
index 000000000..16255e51f
--- /dev/null
+++ b/MediaBrowser.Model/IO/IShortcutHandler.cs
@@ -0,0 +1,25 @@
+
+namespace MediaBrowser.Model.IO
+{
+ public interface IShortcutHandler
+ {
+ /// <summary>
+ /// Gets the extension.
+ /// </summary>
+ /// <value>The extension.</value>
+ string Extension { get; }
+ /// <summary>
+ /// Resolves the specified shortcut path.
+ /// </summary>
+ /// <param name="shortcutPath">The shortcut path.</param>
+ /// <returns>System.String.</returns>
+ string Resolve(string shortcutPath);
+ /// <summary>
+ /// Creates the specified shortcut path.
+ /// </summary>
+ /// <param name="shortcutPath">The shortcut path.</param>
+ /// <param name="targetPath">The target path.</param>
+ /// <returns>System.String.</returns>
+ void Create(string shortcutPath, string targetPath);
+ }
+}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index d21529ddc..2d8c4263a 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -136,7 +136,10 @@
<Compile Include="Extensions\LinqExtensions.cs" />
<Compile Include="FileOrganization\SmartMatchInfo.cs" />
<Compile Include="Health\IHealthMonitor.cs" />
+ <Compile Include="IO\FileSystemMetadata.cs" />
+ <Compile Include="IO\IFileSystem.cs" />
<Compile Include="IO\IMemoryStreamProvider.cs" />
+ <Compile Include="IO\IShortcutHandler.cs" />
<Compile Include="IO\StreamDefaults.cs" />
<Compile Include="Globalization\ILocalizationManager.cs" />
<Compile Include="MediaInfo\LiveStreamRequest.cs" />
@@ -163,6 +166,15 @@
<Compile Include="MediaInfo\SubtitleTrackInfo.cs" />
<Compile Include="Net\EndPointInfo.cs" />
<Compile Include="Net\HttpResponse.cs" />
+ <Compile Include="Services\ApiMemberAttribute.cs" />
+ <Compile Include="Services\IAsyncStreamWriter.cs" />
+ <Compile Include="Services\IHasHeaders.cs" />
+ <Compile Include="Services\IHasRequestFilter.cs" />
+ <Compile Include="Services\IHttpRequest.cs" />
+ <Compile Include="Services\IHttpResponse.cs" />
+ <Compile Include="Services\IRequest.cs" />
+ <Compile Include="Services\IRequiresRequestStream.cs" />
+ <Compile Include="Services\IService.cs" />
<Compile Include="Net\MimeTypes.cs" />
<Compile Include="News\INewsService.cs" />
<Compile Include="Notifications\NotificationOption.cs" />
@@ -310,6 +322,9 @@
<Compile Include="Registration\RegistrationInfo.cs" />
<Compile Include="Search\SearchQuery.cs" />
<Compile Include="Serialization\IgnoreDataMemberAttribute.cs" />
+ <Compile Include="Services\IStreamWriter.cs" />
+ <Compile Include="Services\QueryParamCollection.cs" />
+ <Compile Include="Services\RouteAttribute.cs" />
<Compile Include="Session\BrowseRequest.cs" />
<Compile Include="Session\ClientCapabilities.cs" />
<Compile Include="Session\GeneralCommand.cs" />
diff --git a/MediaBrowser.Model/Services/ApiMemberAttribute.cs b/MediaBrowser.Model/Services/ApiMemberAttribute.cs
new file mode 100644
index 000000000..4a2831775
--- /dev/null
+++ b/MediaBrowser.Model/Services/ApiMemberAttribute.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace MediaBrowser.Model.Services
+{
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
+ public class ApiMemberAttribute : Attribute
+ {
+ /// <summary>
+ /// Gets or sets verb to which applies attribute. By default applies to all verbs.
+ /// </summary>
+ public string Verb { get; set; }
+
+ /// <summary>
+ /// Gets or sets parameter type: It can be only one of the following: path, query, body, form, or header.
+ /// </summary>
+ public string ParameterType { get; set; }
+
+ /// <summary>
+ /// Gets or sets unique name for the parameter. Each name must be unique, even if they are associated with different paramType values.
+ /// </summary>
+ /// <remarks>
+ /// <para>
+ /// Other notes on the name field:
+ /// If paramType is body, the name is used only for UI and codegeneration.
+ /// If paramType is path, the name field must correspond to the associated path segment from the path field in the api object.
+ /// If paramType is query, the name field corresponds to the query param name.
+ /// </para>
+ /// </remarks>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the human-readable description for the parameter.
+ /// </summary>
+ public string Description { get; set; }
+
+ /// <summary>
+ /// For path, query, and header paramTypes, this field must be a primitive. For body, this can be a complex or container datatype.
+ /// </summary>
+ public string DataType { get; set; }
+
+ /// <summary>
+ /// For path, this is always true. Otherwise, this field tells the client whether or not the field must be supplied.
+ /// </summary>
+ public bool IsRequired { get; set; }
+
+ /// <summary>
+ /// For query params, this specifies that a comma-separated list of values can be passed to the API. For path and body types, this field cannot be true.
+ /// </summary>
+ public bool AllowMultiple { get; set; }
+
+ /// <summary>
+ /// Gets or sets route to which applies attribute, matches using StartsWith. By default applies to all routes.
+ /// </summary>
+ public string Route { get; set; }
+
+ /// <summary>
+ /// Whether to exclude this property from being included in the ModelSchema
+ /// </summary>
+ public bool ExcludeInSchema { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Services/IAsyncStreamWriter.cs b/MediaBrowser.Model/Services/IAsyncStreamWriter.cs
new file mode 100644
index 000000000..b10e12813
--- /dev/null
+++ b/MediaBrowser.Model/Services/IAsyncStreamWriter.cs
@@ -0,0 +1,11 @@
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Model.Services
+{
+ public interface IAsyncStreamWriter
+ {
+ Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken);
+ }
+}
diff --git a/MediaBrowser.Model/Services/IHasHeaders.cs b/MediaBrowser.Model/Services/IHasHeaders.cs
new file mode 100644
index 000000000..35e652b0f
--- /dev/null
+++ b/MediaBrowser.Model/Services/IHasHeaders.cs
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.Services
+{
+ public interface IHasHeaders
+ {
+ IDictionary<string, string> Headers { get; }
+ }
+}
diff --git a/MediaBrowser.Model/Services/IHasRequestFilter.cs b/MediaBrowser.Model/Services/IHasRequestFilter.cs
new file mode 100644
index 000000000..c5c6ccf59
--- /dev/null
+++ b/MediaBrowser.Model/Services/IHasRequestFilter.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Model.Services
+{
+ public interface IHasRequestFilter
+ {
+ /// <summary>
+ /// Order in which Request Filters are executed.
+ /// &lt;0 Executed before global request filters
+ /// &gt;0 Executed after global request filters
+ /// </summary>
+ int Priority { get; }
+
+ /// <summary>
+ /// The request filter is executed before the service.
+ /// </summary>
+ /// <param name="req">The http request wrapper</param>
+ /// <param name="res">The http response wrapper</param>
+ /// <param name="requestDto">The request DTO</param>
+ void RequestFilter(IRequest req, IResponse res, object requestDto);
+
+ /// <summary>
+ /// A new shallow copy of this filter is used on every request.
+ /// </summary>
+ /// <returns></returns>
+ IHasRequestFilter Copy();
+ }
+}
diff --git a/MediaBrowser.Model/Services/IHttpRequest.cs b/MediaBrowser.Model/Services/IHttpRequest.cs
new file mode 100644
index 000000000..46c0240cd
--- /dev/null
+++ b/MediaBrowser.Model/Services/IHttpRequest.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Model.Services
+{
+ public interface IHttpRequest : IRequest
+ {
+ /// <summary>
+ /// The HttpResponse
+ /// </summary>
+ IHttpResponse HttpResponse { get; }
+
+ /// <summary>
+ /// The HTTP Verb
+ /// </summary>
+ string HttpMethod { get; }
+
+ /// <summary>
+ /// The IP Address of the X-Forwarded-For header, null if null or empty
+ /// </summary>
+ string XForwardedFor { get; }
+
+ /// <summary>
+ /// The Port number of the X-Forwarded-Port header, null if null or empty
+ /// </summary>
+ int? XForwardedPort { get; }
+
+ /// <summary>
+ /// The http or https scheme of the X-Forwarded-Proto header, null if null or empty
+ /// </summary>
+ string XForwardedProtocol { get; }
+
+ /// <summary>
+ /// The value of the X-Real-IP header, null if null or empty
+ /// </summary>
+ string XRealIp { get; }
+
+ /// <summary>
+ /// The value of the Accept HTTP Request Header
+ /// </summary>
+ string Accept { get; }
+ }
+}
diff --git a/MediaBrowser.Model/Services/IHttpResponse.cs b/MediaBrowser.Model/Services/IHttpResponse.cs
new file mode 100644
index 000000000..377f303a7
--- /dev/null
+++ b/MediaBrowser.Model/Services/IHttpResponse.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Model.Services
+{
+ public interface IHttpResponse : IResponse
+ {
+ //ICookies Cookies { get; }
+
+ /// <summary>
+ /// Adds a new Set-Cookie instruction to Response
+ /// </summary>
+ /// <param name="cookie"></param>
+ void SetCookie(Cookie cookie);
+
+ /// <summary>
+ /// Removes all pending Set-Cookie instructions
+ /// </summary>
+ void ClearCookies();
+ }
+}
diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs
new file mode 100644
index 000000000..45dc97b76
--- /dev/null
+++ b/MediaBrowser.Model/Services/IRequest.cs
@@ -0,0 +1,200 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+
+namespace MediaBrowser.Model.Services
+{
+ public interface IRequest
+ {
+ /// <summary>
+ /// The underlying ASP.NET or HttpListener HttpRequest
+ /// </summary>
+ object OriginalRequest { get; }
+
+ IResponse Response { get; }
+
+ /// <summary>
+ /// The name of the service being called (e.g. Request DTO Name)
+ /// </summary>
+ string OperationName { get; set; }
+
+ /// <summary>
+ /// The Verb / HttpMethod or Action for this request
+ /// </summary>
+ string Verb { get; }
+
+ /// <summary>
+ /// The Request DTO, after it has been deserialized.
+ /// </summary>
+ object Dto { get; set; }
+
+ /// <summary>
+ /// The request ContentType
+ /// </summary>
+ string ContentType { get; }
+
+ bool IsLocal { get; }
+
+ string UserAgent { get; }
+
+ IDictionary<string, Cookie> Cookies { get; }
+
+ /// <summary>
+ /// The expected Response ContentType for this request
+ /// </summary>
+ string ResponseContentType { get; set; }
+
+ /// <summary>
+ /// Whether the ResponseContentType has been explicitly overrided or whether it was just the default
+ /// </summary>
+ bool HasExplicitResponseContentType { get; }
+
+ /// <summary>
+ /// Attach any data to this request that all filters and services can access.
+ /// </summary>
+ Dictionary<string, object> Items { get; }
+
+ QueryParamCollection Headers { get; }
+
+ QueryParamCollection QueryString { get; }
+
+ QueryParamCollection FormData { get; }
+ /// <summary>
+ /// Buffer the Request InputStream so it can be re-read
+ /// </summary>
+ bool UseBufferedStream { get; set; }
+
+ /// <summary>
+ /// The entire string contents of Request.InputStream
+ /// </summary>
+ /// <returns></returns>
+ string GetRawBody();
+
+ string RawUrl { get; }
+
+ string AbsoluteUri { get; }
+
+ /// <summary>
+ /// The Remote Ip as reported by Request.UserHostAddress
+ /// </summary>
+ string UserHostAddress { get; }
+
+ /// <summary>
+ /// The Remote Ip as reported by X-Forwarded-For, X-Real-IP or Request.UserHostAddress
+ /// </summary>
+ string RemoteIp { get; }
+
+ /// <summary>
+ /// The value of the Authorization Header used to send the Api Key, null if not available
+ /// </summary>
+ string Authorization { get; }
+
+ /// <summary>
+ /// e.g. is https or not
+ /// </summary>
+ bool IsSecureConnection { get; }
+
+ string[] AcceptTypes { get; }
+
+ string PathInfo { get; }
+
+ Stream InputStream { get; }
+
+ long ContentLength { get; }
+
+ /// <summary>
+ /// Access to the multi-part/formdata files posted on this request
+ /// </summary>
+ IHttpFile[] Files { get; }
+
+ /// <summary>
+ /// The value of the Referrer, null if not available
+ /// </summary>
+ Uri UrlReferrer { get; }
+ }
+
+ public interface IHttpFile
+ {
+ string Name { get; }
+ string FileName { get; }
+ long ContentLength { get; }
+ string ContentType { get; }
+ Stream InputStream { get; }
+ }
+
+ public interface IRequiresRequest
+ {
+ IRequest Request { get; set; }
+ }
+
+ public interface IResponse
+ {
+ /// <summary>
+ /// The underlying ASP.NET or HttpListener HttpResponse
+ /// </summary>
+ object OriginalResponse { get; }
+
+ IRequest Request { get; }
+
+ int StatusCode { get; set; }
+
+ string StatusDescription { get; set; }
+
+ string ContentType { get; set; }
+
+ void AddHeader(string name, string value);
+
+ string GetHeader(string name);
+
+ void Redirect(string url);
+
+ Stream OutputStream { get; }
+
+ /// <summary>
+ /// The Response DTO
+ /// </summary>
+ object Dto { get; set; }
+
+ /// <summary>
+ /// Write once to the Response Stream then close it.
+ /// </summary>
+ /// <param name="text"></param>
+ void Write(string text);
+
+ /// <summary>
+ /// Buffer the Response OutputStream so it can be written in 1 batch
+ /// </summary>
+ bool UseBufferedStream { get; set; }
+
+ /// <summary>
+ /// Signal that this response has been handled and no more processing should be done.
+ /// When used in a request or response filter, no more filters or processing is done on this request.
+ /// </summary>
+ void Close();
+
+ /// <summary>
+ /// Calls Response.End() on ASP.NET HttpResponse otherwise is an alias for Close().
+ /// Useful when you want to prevent ASP.NET to provide it's own custom error page.
+ /// </summary>
+ void End();
+
+ /// <summary>
+ /// Response.Flush() and OutputStream.Flush() seem to have different behaviour in ASP.NET
+ /// </summary>
+ void Flush();
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is closed.
+ /// </summary>
+ bool IsClosed { get; }
+
+ void SetContentLength(long contentLength);
+
+ bool KeepAlive { get; set; }
+
+ //Add Metadata to Response
+ Dictionary<string, object> Items { get; }
+ }
+
+}
diff --git a/MediaBrowser.Model/Services/IRequiresRequestStream.cs b/MediaBrowser.Model/Services/IRequiresRequestStream.cs
new file mode 100644
index 000000000..0b8ac3ed3
--- /dev/null
+++ b/MediaBrowser.Model/Services/IRequiresRequestStream.cs
@@ -0,0 +1,12 @@
+using System.IO;
+
+namespace MediaBrowser.Model.Services
+{
+ public interface IRequiresRequestStream
+ {
+ /// <summary>
+ /// The raw Http Request Input Stream
+ /// </summary>
+ Stream RequestStream { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Services/IService.cs b/MediaBrowser.Model/Services/IService.cs
new file mode 100644
index 000000000..3e0ff280b
--- /dev/null
+++ b/MediaBrowser.Model/Services/IService.cs
@@ -0,0 +1,12 @@
+
+namespace MediaBrowser.Model.Services
+{
+ // marker interface
+ public interface IService
+ {
+ }
+
+ public interface IReturn { }
+ public interface IReturn<T> : IReturn { }
+ public interface IReturnVoid : IReturn { }
+}
diff --git a/MediaBrowser.Model/Services/IStreamWriter.cs b/MediaBrowser.Model/Services/IStreamWriter.cs
new file mode 100644
index 000000000..1fc11049e
--- /dev/null
+++ b/MediaBrowser.Model/Services/IStreamWriter.cs
@@ -0,0 +1,9 @@
+using System.IO;
+
+namespace MediaBrowser.Model.Services
+{
+ public interface IStreamWriter
+ {
+ void WriteTo(Stream responseStream);
+ }
+}
diff --git a/MediaBrowser.Model/Services/QueryParamCollection.cs b/MediaBrowser.Model/Services/QueryParamCollection.cs
new file mode 100644
index 000000000..6393a87fb
--- /dev/null
+++ b/MediaBrowser.Model/Services/QueryParamCollection.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Model.Services
+{
+ public class QueryParamCollection : List<NameValuePair>
+ {
+ public QueryParamCollection()
+ {
+
+ }
+
+ public QueryParamCollection(IDictionary<string, string> headers)
+ {
+ foreach (var pair in headers)
+ {
+ Add(pair.Key, pair.Value);
+ }
+ }
+
+ private StringComparison GetStringComparison()
+ {
+ return StringComparison.OrdinalIgnoreCase;
+ }
+
+ private StringComparer GetStringComparer()
+ {
+ return StringComparer.OrdinalIgnoreCase;
+ }
+
+ /// <summary>
+ /// Adds a new query parameter.
+ /// </summary>
+ public void Add(string key, string value)
+ {
+ Add(new NameValuePair(key, value));
+ }
+
+ public void Set(string key, string value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ var stringComparison = GetStringComparison();
+
+ var parameters = this.Where(p => string.Equals(key, p.Name, stringComparison)).ToArray();
+
+ foreach (var p in parameters)
+ {
+ Remove(p);
+ }
+
+ return;
+ }
+
+ foreach (var pair in this)
+ {
+ var stringComparison = GetStringComparison();
+
+ if (string.Equals(key, pair.Name, stringComparison))
+ {
+ pair.Value = value;
+ return;
+ }
+ }
+
+ Add(key, value);
+ }
+
+ /// <summary>
+ /// True if the collection contains a query parameter with the given name.
+ /// </summary>
+ public bool ContainsKey(string name)
+ {
+ return this.Any(p => p.Name == name);
+ }
+
+ /// <summary>
+ /// Removes all parameters of the given name.
+ /// </summary>
+ /// <returns>The number of parameters that were removed</returns>
+ /// <exception cref="ArgumentNullException"><paramref name="name" /> is null.</exception>
+ public int Remove(string name)
+ {
+ return RemoveAll(p => p.Name == name);
+ }
+
+ public string Get(string name)
+ {
+ return GetValues(name).FirstOrDefault();
+ }
+
+ public string[] GetValues(string name)
+ {
+ var stringComparison = GetStringComparison();
+
+ return this.Where(p => string.Equals(p.Name, name, stringComparison)).Select(p => p.Value).ToArray();
+ }
+
+ public Dictionary<string, string> ToDictionary()
+ {
+ var stringComparer = GetStringComparer();
+
+ var headers = new Dictionary<string, string>(stringComparer);
+
+ foreach (var pair in this)
+ {
+ headers[pair.Name] = pair.Value;
+ }
+
+ return headers;
+ }
+
+ public IEnumerable<string> Keys
+ {
+ get { return this.Select(i => i.Name); }
+ }
+
+ /// <summary>
+ /// Gets or sets a query parameter value by name. A query may contain multiple values of the same name
+ /// (i.e. "x=1&amp;x=2"), in which case the value is an array, which works for both getting and setting.
+ /// </summary>
+ /// <param name="name">The query parameter name</param>
+ /// <returns>The query parameter value or array of values</returns>
+ public string this[string name]
+ {
+ get { return Get(name); }
+ set
+ {
+ Set(name, value);
+ //var parameters = this.Where(p => p.Name == name).ToArray();
+ //var values = new[] { value };
+
+ //for (int i = 0; ; i++)
+ //{
+ // if (i < parameters.Length && i < values.Length)
+ // {
+ // if (values[i] == null)
+ // Remove(parameters[i]);
+ // else if (values[i] is NameValuePair)
+ // this[IndexOf(parameters[i])] = (NameValuePair)values[i];
+ // else
+ // parameters[i].Value = values[i];
+ // }
+ // else if (i < parameters.Length)
+ // Remove(parameters[i]);
+ // else if (i < values.Length)
+ // {
+ // if (values[i] != null)
+ // {
+ // if (values[i] is NameValuePair)
+ // Add((NameValuePair)values[i]);
+ // else
+ // Add(name, values[i]);
+ // }
+ // }
+ // else
+ // break;
+ //}
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Model/Services/RouteAttribute.cs b/MediaBrowser.Model/Services/RouteAttribute.cs
new file mode 100644
index 000000000..5a39688da
--- /dev/null
+++ b/MediaBrowser.Model/Services/RouteAttribute.cs
@@ -0,0 +1,144 @@
+using System;
+
+namespace MediaBrowser.Model.Services
+{
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
+ public class RouteAttribute : Attribute
+ {
+ /// <summary>
+ /// <para>Initializes an instance of the <see cref="RouteAttribute"/> class.</para>
+ /// </summary>
+ /// <param name="path">
+ /// <para>The path template to map to the request. See
+ /// <see cref="Path">RouteAttribute.Path</see>
+ /// for details on the correct format.</para>
+ /// </param>
+ public RouteAttribute(string path)
+ : this(path, null)
+ {
+ }
+
+ /// <summary>
+ /// <para>Initializes an instance of the <see cref="RouteAttribute"/> class.</para>
+ /// </summary>
+ /// <param name="path">
+ /// <para>The path template to map to the request. See
+ /// <see cref="Path">RouteAttribute.Path</see>
+ /// for details on the correct format.</para>
+ /// </param>
+ /// <param name="verbs">A comma-delimited list of HTTP verbs supported by the
+ /// service. If unspecified, all verbs are assumed to be supported.</param>
+ public RouteAttribute(string path, string verbs)
+ {
+ Path = path;
+ Verbs = verbs;
+ }
+
+ /// <summary>
+ /// Gets or sets the path template to be mapped to the request.
+ /// </summary>
+ /// <value>
+ /// A <see cref="String"/> value providing the path mapped to
+ /// the request. Never <see langword="null"/>.
+ /// </value>
+ /// <remarks>
+ /// <para>Some examples of valid paths are:</para>
+ ///
+ /// <list>
+ /// <item>"/Inventory"</item>
+ /// <item>"/Inventory/{Category}/{ItemId}"</item>
+ /// <item>"/Inventory/{ItemPath*}"</item>
+ /// </list>
+ ///
+ /// <para>Variables are specified within "{}"
+ /// brackets. Each variable in the path is mapped to the same-named property
+ /// on the request DTO. At runtime, ServiceStack will parse the
+ /// request URL, extract the variable values, instantiate the request DTO,
+ /// and assign the variable values into the corresponding request properties,
+ /// prior to passing the request DTO to the service object for processing.</para>
+ ///
+ /// <para>It is not necessary to specify all request properties as
+ /// variables in the path. For unspecified properties, callers may provide
+ /// values in the query string. For example: the URL
+ /// "http://services/Inventory?Category=Books&amp;ItemId=12345" causes the same
+ /// request DTO to be processed as "http://services/Inventory/Books/12345",
+ /// provided that the paths "/Inventory" (which supports the first URL) and
+ /// "/Inventory/{Category}/{ItemId}" (which supports the second URL)
+ /// are both mapped to the request DTO.</para>
+ ///
+ /// <para>Please note that while it is possible to specify property values
+ /// in the query string, it is generally considered to be less RESTful and
+ /// less desirable than to specify them as variables in the path. Using the
+ /// query string to specify property values may also interfere with HTTP
+ /// caching.</para>
+ ///
+ /// <para>The final variable in the path may contain a "*" suffix
+ /// to grab all remaining segments in the path portion of the request URL and assign
+ /// them to a single property on the request DTO.
+ /// For example, if the path "/Inventory/{ItemPath*}" is mapped to the request DTO,
+ /// then the request URL "http://services/Inventory/Books/12345" will result
+ /// in a request DTO whose ItemPath property contains "Books/12345".
+ /// You may only specify one such variable in the path, and it must be positioned at
+ /// the end of the path.</para>
+ /// </remarks>
+ public string Path { get; set; }
+
+ /// <summary>
+ /// Gets or sets short summary of what the route does.
+ /// </summary>
+ public string Summary { get; set; }
+
+ /// <summary>
+ /// Gets or sets longer text to explain the behaviour of the route.
+ /// </summary>
+ public string Notes { get; set; }
+
+ /// <summary>
+ /// Gets or sets a comma-delimited list of HTTP verbs supported by the service, such as
+ /// "GET,PUT,POST,DELETE".
+ /// </summary>
+ /// <value>
+ /// A <see cref="String"/> providing a comma-delimited list of HTTP verbs supported
+ /// by the service, <see langword="null"/> or empty if all verbs are supported.
+ /// </value>
+ public string Verbs { get; set; }
+
+ /// <summary>
+ /// Used to rank the precedences of route definitions in reverse routing.
+ /// i.e. Priorities below 0 are auto-generated have less precedence.
+ /// </summary>
+ public int Priority { get; set; }
+
+ protected bool Equals(RouteAttribute other)
+ {
+ return base.Equals(other)
+ && string.Equals(Path, other.Path)
+ && string.Equals(Summary, other.Summary)
+ && string.Equals(Notes, other.Notes)
+ && string.Equals(Verbs, other.Verbs)
+ && Priority == other.Priority;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((RouteAttribute)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ var hashCode = base.GetHashCode();
+ hashCode = (hashCode * 397) ^ (Path != null ? Path.GetHashCode() : 0);
+ hashCode = (hashCode * 397) ^ (Summary != null ? Summary.GetHashCode() : 0);
+ hashCode = (hashCode * 397) ^ (Notes != null ? Notes.GetHashCode() : 0);
+ hashCode = (hashCode * 397) ^ (Verbs != null ? Verbs.GetHashCode() : 0);
+ hashCode = (hashCode * 397) ^ Priority;
+ return hashCode;
+ }
+ }
+ }
+}