diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..1ff0c423 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index 01c68b74..1686a7fa 100644 --- a/.gitignore +++ b/.gitignore @@ -52,5 +52,7 @@ AndroidRemote.dll.mdb /ClientServerLib/AndroidRemote/bin/AndroidRemote.dll /ClientServerLib/ClientTest/bin/Debug/Newtonsoft.Json.dll *.apk +/Output/ClientServerLib.dll Installer/VocaluxeSetup_0.3.0Beta.exe Output/Vocaluxe_x64.exe +/WebserverInitalConfig/bin/Release diff --git a/ClientServerLib/ClientServerLib/CClient.cs b/ClientServerLib/ClientServerLib/CClient.cs deleted file mode 100644 index 6dc64669..00000000 --- a/ClientServerLib/ClientServerLib/CClient.cs +++ /dev/null @@ -1,405 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading; - - -namespace ClientServerLib -{ - public class CClient - { - private bool doConnect; - private bool connected; - private bool running; - private int bufferLength = 8192; - - private Thread clientThread; - private IPEndPoint serverEndPoint; - private string ip; - private int port; - - private CConnection connection; - private List requests; - private List responses; - private Object mutexRequests = new Object(); - private OnConnectionChanged onConnectionChanged; - private OnSend onSend; - private OnReceived onReceived; - - private byte[] data; - - public bool Connected - { - get { return connected; } - } - - public CClient() - { - doConnect = false; - connected = false; - running = true; - requests = new List(); - responses = new List(); - data = new byte[bufferLength]; - - connection = new CConnection(new TcpClient(), -1); - } - - public void Connect(string IP = "127.0.0.1", int Port = 3000, string Password = null, - OnConnectionChanged OnConnectionChanged = null, - OnSend OnSend = null, - OnReceived OnReceived = null) - { - if (!doConnect) - { - onConnectionChanged = OnConnectionChanged; - onSend = OnSend; - onReceived = OnReceived; - - ip = IP; - port = Port; - connection.Password = Password; - doConnect = true; - - if (clientThread == null) - { - running = true; - clientThread = new Thread(new ThreadStart(Runner)); - clientThread.Start(); - } - } - } - - public void Disconnect() - { - if (doConnect) - { - doConnect = false; - - lock (mutexRequests) - { - requests.Clear(); - } - - lock (responses) - { - responses.Clear(); - } - } - } - - public void Close() - { - running = false; - - if (clientThread != null) - clientThread.Join(100); - - clientThread = null; - DoDisconnect(); - } - - public void SendMessage(byte[] Message, ResponseCallback Callback) - { - SRequest req = new SRequest(); - req.Command = Message; - req.Callback = Callback; - req.Response = null; - - lock (mutexRequests) - { - requests.Add(req); - } - } - - private void Runner() - { - while (running) - { - if (!connected && doConnect) - { - try - { - IPAddress resolvedIP; - if (TryResolveIPAddress(ip, out resolvedIP)) - { - serverEndPoint = new IPEndPoint(resolvedIP, port); - connection.TcpClient.Connect(serverEndPoint); - connected = true; - RaiseOnConnectionChanged(); - } - } - catch - { - DoDisconnect(); - - for (int i = 0; i < 500; i++) - { - if (running && doConnect) - Thread.Sleep(10); - else - break; - } - - } - } - - if (connected && !doConnect) - { - DoDisconnect(); - } - - if (doConnect && connected) - { - try - { - Communicate(); - Thread.Sleep(10); - } - catch - { - DoDisconnect(); - } - - } - - if (!doConnect && !connected) - { - for (int i = 0; i < 500; i++) - { - if (running && !doConnect) - Thread.Sleep(10); - else - break; - } - } - } - } - - public bool TryResolveIPAddress(string serverNameOrURL, out IPAddress resolvedIPAddress) - { - bool isResolved = false; - IPHostEntry hostEntry = null; - IPAddress resolvIP = null; - try - { - if (!IPAddress.TryParse(serverNameOrURL, out resolvIP)) - { - hostEntry = Dns.GetHostEntry(serverNameOrURL); - if (hostEntry != null && hostEntry.AddressList != null && hostEntry.AddressList.Length > 0) - { - if (hostEntry.AddressList.Length == 1) - { - resolvIP = hostEntry.AddressList[0]; - isResolved = true; - } - else - { - foreach (IPAddress var in hostEntry.AddressList) - { - if (var.AddressFamily == AddressFamily.InterNetwork) - { - resolvIP = var; - isResolved = true; - break; - } - } - } - } - } - else - isResolved = true; - } - catch (Exception) {} - finally - { - resolvedIPAddress = resolvIP; - } - return isResolved; - } - - private void DoDisconnect() - { - try - { - connection.TcpClient.Close(); - } - catch { } - - connection = new CConnection(new TcpClient(), -1); - connected = false; - doConnect = false; - RaiseOnConnectionChanged(); - } - - private void Communicate() - { - if (connection.TcpClient == null || !connection.TcpClient.Connected) - DoDisconnect(); - - NetworkStream clientStream = connection.TcpClient.GetStream(); - - int bytesRead; - - if (!connection.KeySet) - { - bytesRead = 0; - - try - { - bytesRead = clientStream.Read(data, 0, bufferLength); - } - catch - { - return; - } - - if (bytesRead == 0) - return; - - byte[] serverParam = new byte[bytesRead]; - Array.Copy(data, serverParam, bytesRead); - RaiseOnReceived(serverParam); - - byte[] clientResponse = connection.CreateClientKey(serverParam); - RaiseOnSend(clientResponse); - clientStream.Write(clientResponse, 0, clientResponse.Length); - clientStream.Flush(); - } - else - { - try - { - while (requests.Count > 0) - { - SRequest res = HandleRequest(requests[0]); - lock (responses) - { - responses.Add(res); - } - - lock (mutexRequests) - { - requests.RemoveAt(0); - } - } - } - catch { }; - - lock (responses) - { - while (responses.Count > 0) - { - try - { - if (responses[0].Callback != null) - responses[0].Callback(responses[0].Response); - } - finally - { - responses.RemoveAt(0); - } - } - } - - } - } - - private SRequest HandleRequest(SRequest request) - { - SRequest response = new SRequest(); - response.Command = request.Command; - response.Callback = request.Callback; - response.Response = null; - - NetworkStream clientStream = connection.TcpClient.GetStream(); - - RaiseOnSend(request.Command); - byte[] encrypted = connection.Encrypt(request.Command); - - int sendBytes = 0; - while(sendBytes < encrypted.Length) - { - int bytesToSend = encrypted.Length - sendBytes; - if (bytesToSend > bufferLength) - bytesToSend = bufferLength; - - clientStream.Write(encrypted, sendBytes, bytesToSend); - sendBytes += bytesToSend; - } - clientStream.Flush(); - - byte[] data = new byte[bufferLength]; - int bytesRead = 0; - - try - { - bytesRead = clientStream.Read(data, 0, bufferLength); - } - catch - { - return response; - } - - if (bytesRead == 0) - return response; - - int messageLength = BitConverter.ToInt32(data, 0); - while (messageLength > bytesRead) - { - if (data.Length < messageLength + bufferLength) - Array.Resize(ref data, messageLength + bufferLength); - bytesRead += clientStream.Read(data, bytesRead, bufferLength); - } - - encrypted = new byte[bytesRead]; - Array.Copy(data, encrypted, bytesRead); - response.Response = connection.Decrypt(encrypted); - RaiseOnReceived(response.Response); - - return response; - } - - private void RaiseOnConnectionChanged() - { - if (onConnectionChanged == null) - return; - - try - { - onConnectionChanged(connected); - } - catch (Exception e) - { - Console.WriteLine (e.Message); - } - } - - private void RaiseOnSend(byte[] Message) - { - if (onSend == null) - return; - - try - { - onSend(Message); - } - catch { } - } - - private void RaiseOnReceived(byte[] Message) - { - if (onReceived == null) - return; - - try - { - onReceived(Message); - } - catch { } - } - } -} diff --git a/ClientServerLib/ClientServerLib/CConnection.cs b/ClientServerLib/ClientServerLib/CConnection.cs deleted file mode 100644 index d6bb8bdb..00000000 --- a/ClientServerLib/ClientServerLib/CConnection.cs +++ /dev/null @@ -1,307 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Sockets; -using System.IO; -using System.IO.Compression; -using System.Security.Cryptography; -using System.Text; - -using DiffieHellman; - -namespace ClientServerLib -{ - internal class CConnection - { - private bool keySet; - private byte[] key; - private bool encryption; - private string password; - private CDiffieHellman dh; - private UTF8Encoding encoder; - private int connectionID; - private static SHA256Managed SHA256 = new SHA256Managed(); - - public TcpClient TcpClient; - - public bool KeySet - { - get { return keySet; } - } - - public int ConnectionID - { - get { return connectionID; } - } - - public string Password - { - set - { - password = value; - encryption = value != null; - keySet = false; - } - } - - public CConnection(TcpClient client, int ConnectionID, string Password = null) - { - TcpClient = client; - client.NoDelay = true; - keySet = false; - encryption = Password != null; - password = Password; - connectionID = ConnectionID; - encoder = new UTF8Encoding(); - key = null; - } - - public byte[] GetKeyParams() - { - if (!encryption) - { - return encoder.GetBytes("NO ENCRYPTION"); - } - - if (dh == null) - dh = new CDiffieHellman(256).GenerateRequest(); - - return encoder.GetBytes(dh.ToString()); - } - - public byte[] CreateClientKey(byte[] serverParam) - { - if (serverParam == null) - return null; - - string response = encoder.GetString(serverParam, 0, serverParam.Length); - if (response == "NO ENCRYPTION") - { - encryption = false; - keySet = true; - key = null; - return encoder.GetBytes(response); - } - - dh = new CDiffieHellman(256).GenerateResponse(response); - key = _BuildHash(dh.Key, password); - keySet = true; - encryption = true; - return encoder.GetBytes(dh.ToString()); - } - - public void CreateServerKey(byte[] clientResponse) - { - string response = encoder.GetString(clientResponse, 0, clientResponse.Length); - - if (response == "NO ENCRYPTION") - { - keySet = true; - key = null; - return; - } - - if (dh == null) - return; - - dh.HandleResponse(response); - key = _BuildHash(dh.Key, password); - keySet = true; - } - - public byte[] Encrypt(byte[] Data) - { - return _Encrypt(_Compress(Data)); - } - - public byte[] Decrypt(byte[] Data) - { - return _Decompress(_Decrypt(Data)); - } - - private byte[] _BuildHash(byte[] Key, string Password) - { - if (Key == null || Password == null) - return null; - - byte[] hash = SHA256.ComputeHash(encoder.GetBytes(Password)); - byte[] serial = new byte[Key.Length + hash.Length]; - Array.Copy(Key, serial, Key.Length); - Array.Copy(hash, 0, serial, Key.Length, hash.Length); - - return SHA256.ComputeHash(serial); - } - - private byte[] _Encrypt(byte[] Data) - { - if (Data == null || (!keySet && encryption)) - return Data; - - byte[] dataLength = BitConverter.GetBytes(Data.Length); - - if (!encryption) - { - int len = 4 + dataLength.Length + Data.Length; - byte[] messageLength = BitConverter.GetBytes(len); - - using (var stream = new MemoryStream()) - { - stream.Write(messageLength, 0, messageLength.Length); - stream.Write(dataLength, 0, dataLength.Length); - stream.Write(Data, 0, Data.Length); - - return stream.ToArray(); - } - } - - using (Aes aes = new AesManaged()) - { - aes.Key = key; - aes.GenerateIV(); - - using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV)) - using (var memoryStream = new MemoryStream()) - using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) - { - cryptoStream.Write(Data, 0, Data.Length); - cryptoStream.FlushFinalBlock(); - - byte[] encrypted = memoryStream.ToArray(); - - int len = 4 + aes.IV.Length + dataLength.Length + encrypted.Length; - byte[] messageLength = BitConverter.GetBytes(len); - - using (var stream = new MemoryStream()) - { - stream.Write(messageLength, 0, messageLength.Length); - stream.Write(aes.IV, 0, aes.IV.Length); - stream.Write(dataLength, 0, dataLength.Length); - stream.Write(encrypted, 0, encrypted.Length); - - return stream.ToArray(); - } - } - } - } - - private byte[] _Decrypt(byte[] Data) - { - if (Data == null || (!keySet && encryption)) - return Data; - - - int messageLength = BitConverter.ToInt32(Data, 0); - if (messageLength > Data.Length) - return null; - - int dataLength; - - if (!encryption) - { - dataLength = BitConverter.ToInt32(Data, 4); - - byte[] message = new byte[dataLength]; - Array.Copy(Data, 8, message, 0, dataLength); - return message; - } - - if (Data.Length < 25) - return null; - - byte[] IV = new byte[16]; - Array.Copy(Data, 4, IV, 0, 16); - - dataLength = BitConverter.ToInt32(Data, 20); - - using (Aes aes = new AesManaged()) - { - aes.Key = key; - aes.IV = IV; - - byte[] encrypted = new byte[messageLength - 24]; - Array.Copy(Data, 24, encrypted, 0, encrypted.Length); - - try - { - using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV)) - using (var memoryStream = new MemoryStream()) - using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write)) - { - cryptoStream.Write(encrypted, 0, encrypted.Length); - cryptoStream.FlushFinalBlock(); - cryptoStream.Close(); - - byte[] decrypted = memoryStream.ToArray(); - byte[] message = new byte[dataLength]; - Array.Copy(decrypted, message, dataLength); - - return message; - } - } - catch - { - return null; - } - } - } - - private byte[] _Compress(byte[] Data) - { - if (Data == null) - return Data; - - using (var compressed = new MemoryStream()) - { - using (var gz = new GZipStream(compressed, CompressionMode.Compress, true)) - { - gz.Write(Data, 0, Data.Length); - } - - byte[] result = null; - - if (compressed.Length < Data.Length) - { - result = new byte[compressed.Length + 1]; - result[0] = 1; //data stream is compressed - compressed.Position = 0; - compressed.Read(result, 1, (int)compressed.Length); - } - else - { - result = new byte[Data.Length + 1]; - result[0] = 0; //data stream is not compressed - Array.Copy(Data, 0, result, 1, Data.Length); - } - - return result; - } - } - - private byte[] _Decompress(byte[] Data) - { - if (Data == null) - return Data; - - if (Data[0] == 0) //not compressed - { - byte[] result = new byte[Data.Length - 1]; - Array.Copy(Data, 1, result, 0, result.Length); - return result; - } - - using (var inStream = new MemoryStream()) - { - inStream.Write(Data, 1, Data.Length - 1); - inStream.Position = 0; - - using (var outStream = new MemoryStream()) - { - using (var gz = new GZipStream(inStream, CompressionMode.Decompress, true)) - gz.CopyTo(outStream); - - return outStream.ToArray(); - } - } - } - } -} diff --git a/ClientServerLib/ClientServerLib/CDiscover.cs b/ClientServerLib/ClientServerLib/CDiscover.cs index 75df21bf..ba327e2d 100644 --- a/ClientServerLib/ClientServerLib/CDiscover.cs +++ b/ClientServerLib/ClientServerLib/CDiscover.cs @@ -1,125 +1,125 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Timers; - -namespace ClientServerLib -{ - public delegate void OnServerDiscovered(string IPAddress, string Hostname); - - public class CDiscover - { - public static readonly string sTimeout = "Timeout"; - public static readonly string sFinished = "Finished"; - - private string _Keyword; - private string _BroadcastAddress; - private int _Port; - - private Thread _DiscoverThread; - private bool _DiscoverRunning; - private OnServerDiscovered _OnDiscovered; - - - private System.Timers.Timer _BroadcastTimer; - - public CDiscover(int Port, string Keyword, string BroadcastAddress = "255.255.255.255") - { - _BroadcastAddress = BroadcastAddress; - _Port = Port; - _Keyword = Keyword; - - _DiscoverRunning = false; - _BroadcastTimer = new System.Timers.Timer(); - _BroadcastTimer.Elapsed += new ElapsedEventHandler(OnBroadcastEvent); - _BroadcastTimer.Interval = 2500; - } - - public void StartBroadcasting() - { - _BroadcastTimer.Start(); - } - - public void Stop() - { - _BroadcastTimer.Stop(); - _DiscoverRunning = false; - } - - public void Discover(OnServerDiscovered OnDiscovered, int Timeout = 5000) - { - if (_DiscoverRunning) - return; - - _DiscoverRunning = true; - _DiscoverThread = new Thread(() => _Discover(Timeout)); - _OnDiscovered = OnDiscovered; - _DiscoverThread.Start(); - } - - private void OnBroadcastEvent(object source, ElapsedEventArgs e) - { - Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - s.EnableBroadcast = true; - IPAddress broadcast = IPAddress.Parse(_BroadcastAddress); - byte[] sendbuf = Encoding.UTF8.GetBytes(_Keyword); - IPEndPoint ep = new IPEndPoint(broadcast, _Port); - - s.SendTo(sendbuf, ep); - s.Close(); - } - - private void _Discover(int Timeout) - { - UdpClient listener = null; - Stopwatch timer = new Stopwatch(); - - List knownServer = new List(); - bool foundSomething = false; - timer.Start(); - while (_DiscoverRunning && timer.ElapsedMilliseconds < Timeout * 2) - { - try - { - listener = new UdpClient(_Port); - IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, _Port); - listener.Client.ReceiveTimeout = Timeout; - - byte[] bytes = listener.Receive(ref groupEP); - string message = Encoding.UTF8.GetString(bytes, 0, bytes.Length); - - foundSomething = true; - if (!knownServer.Contains(groupEP.Address.ToString())) - { - knownServer.Add(groupEP.Address.ToString()); - if (_OnDiscovered != null) - { - IPHostEntry e = Dns.GetHostEntry(groupEP.Address); - string hostname = e.HostName; - - _OnDiscovered(groupEP.Address.ToString(), hostname); - } - } - - listener.Close(); - } - catch (Exception) - { - if (listener != null) - listener.Close(); - } - } - _DiscoverRunning = false; - - if (!foundSomething) - _OnDiscovered(sTimeout, String.Empty); - else - _OnDiscovered(sFinished, String.Empty); - } - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Timers; + +namespace ServerLib +{ + public delegate void OnServerDiscovered(string IPAddress, string Hostname); + + public class CDiscover + { + public static readonly string sTimeout = "Timeout"; + public static readonly string sFinished = "Finished"; + + private string _Keyword; + private string _BroadcastAddress; + private int _Port; + + private Thread _DiscoverThread; + private bool _DiscoverRunning; + private OnServerDiscovered _OnDiscovered; + + + private System.Timers.Timer _BroadcastTimer; + + public CDiscover(int Port, string Keyword, string BroadcastAddress = "255.255.255.255") + { + _BroadcastAddress = BroadcastAddress; + _Port = Port; + _Keyword = Keyword; + + _DiscoverRunning = false; + _BroadcastTimer = new System.Timers.Timer(); + _BroadcastTimer.Elapsed += new ElapsedEventHandler(OnBroadcastEvent); + _BroadcastTimer.Interval = 2500; + } + + public void StartBroadcasting() + { + _BroadcastTimer.Start(); + } + + public void Stop() + { + _BroadcastTimer.Stop(); + _DiscoverRunning = false; + } + + public void Discover(OnServerDiscovered OnDiscovered, int Timeout = 5000) + { + if (_DiscoverRunning) + return; + + _DiscoverRunning = true; + _DiscoverThread = new Thread(() => _Discover(Timeout)); + _OnDiscovered = OnDiscovered; + _DiscoverThread.Start(); + } + + private void OnBroadcastEvent(object source, ElapsedEventArgs e) + { + Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + s.EnableBroadcast = true; + IPAddress broadcast = IPAddress.Parse(_BroadcastAddress); + byte[] sendbuf = Encoding.UTF8.GetBytes(_Keyword); + IPEndPoint ep = new IPEndPoint(broadcast, _Port); + + s.SendTo(sendbuf, ep); + s.Close(); + } + + private void _Discover(int Timeout) + { + UdpClient listener = null; + Stopwatch timer = new Stopwatch(); + + List knownServer = new List(); + bool foundSomething = false; + timer.Start(); + while (_DiscoverRunning && timer.ElapsedMilliseconds < Timeout * 2) + { + try + { + listener = new UdpClient(_Port); + IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, _Port); + listener.Client.ReceiveTimeout = Timeout; + + byte[] bytes = listener.Receive(ref groupEP); + string message = Encoding.UTF8.GetString(bytes, 0, bytes.Length); + + foundSomething = true; + if (!knownServer.Contains(groupEP.Address.ToString())) + { + knownServer.Add(groupEP.Address.ToString()); + if (_OnDiscovered != null) + { + IPHostEntry e = Dns.GetHostEntry(groupEP.Address); + string hostname = e.HostName; + + _OnDiscovered(groupEP.Address.ToString(), hostname); + } + } + + listener.Close(); + } + catch (Exception) + { + if (listener != null) + listener.Close(); + } + } + _DiscoverRunning = false; + + if (!foundSomething) + _OnDiscovered(sTimeout, String.Empty); + else + _OnDiscovered(sFinished, String.Empty); + } + } +} diff --git a/ClientServerLib/ClientServerLib/CServer.cs b/ClientServerLib/ClientServerLib/CServer.cs index d8cba3f2..c6435566 100644 --- a/ClientServerLib/ClientServerLib/CServer.cs +++ b/ClientServerLib/ClientServerLib/CServer.cs @@ -1,194 +1,313 @@ using System; -using System.Collections.Generic; -using System.Linq; +using System.ServiceModel; +using System.ServiceModel.Web; +using System.Diagnostics; using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading; -namespace ClientServerLib +namespace ServerLib { public class CServer { - private TcpListener tcpListener; - private Thread listenThread; - private int port; - private bool encryption; - private string password; - private int bufferLength = 8192; - private bool running; + private ServiceHost _Host; + private Uri _BaseAddress; + private bool _Encrypted = false; - private HandleRequest requestCallback; - - private Dictionary clients; - private Queue ids; - - public CServer(HandleRequest RequestCallback, int Port = 3000, string Password = null) + private static SendKeyEventDelegate _SendKeyEvent; + public static SendKeyEventDelegate SendKeyEvent { - port = Port; - running = false; - requestCallback = RequestCallback; - encryption = Password != null; - password = Password; + internal get { return CServer._SendKeyEvent; } + set { CServer._SendKeyEvent = value; } + } - clients = new Dictionary(); - ids = new Queue(1000); + #region profile - for (int i = 0; i < 1000; i++) - ids.Enqueue(i); + private static GetProfileDataDelegate _GetProfileData; + public static GetProfileDataDelegate GetProfileData + { + internal get { return CServer._GetProfileData; } + set { CServer._GetProfileData = value; } + } + + private static SendProfileDataDelegate _SendProfileData; + public static SendProfileDataDelegate SendProfileData + { + internal get { return CServer._SendProfileData; } + set { CServer._SendProfileData = value; } + } + + private static GetProfileListDelegate _GetProfileList; + public static GetProfileListDelegate GetProfileList + { + internal get { return CServer._GetProfileList; } + set { CServer._GetProfileList = value; } + } + + #endregion + + #region photo + private static SendPhotoDelegate _SendPhoto; + public static SendPhotoDelegate SendPhoto + { + get { return CServer._SendPhoto; } + set { CServer._SendPhoto = value; } + } + + #endregion + + #region website + + private static GetSiteFileDelegate _GetSiteFile; + public static GetSiteFileDelegate GetSiteFile + { + internal get { return CServer._GetSiteFile; } + set { CServer._GetSiteFile = value; } + } + + private static GetDelayedImageDelegate _GetDelayedImage; + public static GetDelayedImageDelegate GetDelayedImage + { + internal get { return CServer._GetDelayedImage; } + set { CServer._GetDelayedImage = value; } + } + + #endregion + + #region songs + + private static GetSongDelegate _GetSong; + public static GetSongDelegate GetSong + { + internal get { return CServer._GetSong; } + set { CServer._GetSong = value; } + } + + private static GetAllSongsDelegate _GetAllSongs; + public static GetAllSongsDelegate GetAllSongs + { + internal get { return CServer._GetAllSongs; } + set { CServer._GetAllSongs = value; } + } + + private static GetCurrentSongIdDelegate _GetCurrentSongId; + public static GetCurrentSongIdDelegate GetCurrentSongId + { + internal get { return CServer._GetCurrentSongId; } + set { CServer._GetCurrentSongId = value; } + } + + + #endregion + + #region playlist + + private static GetPlaylistsDelegate _GetPlaylists; + public static GetPlaylistsDelegate GetPlaylists + { + internal get { return _GetPlaylists; } + set { _GetPlaylists = value; } + } + + + private static GetPlaylistDelegate _GetPlaylist; + public static GetPlaylistDelegate GetPlaylist + { + internal get { return _GetPlaylist; } + set { _GetPlaylist = value; } + } + + private static AddSongToPlaylistDelegate _AddSongToPlaylist; + public static AddSongToPlaylistDelegate AddSongToPlaylist + { + internal get { return _AddSongToPlaylist; } + set { _AddSongToPlaylist = value; } + } + + private static RemoveSongFromPlaylistDelegate _RemoveSongFromPlaylist; + public static RemoveSongFromPlaylistDelegate RemoveSongFromPlaylist + { + internal get { return _RemoveSongFromPlaylist; } + set { _RemoveSongFromPlaylist = value; } + } + + private static MoveSongInPlaylistDelegate _MoveSongInPlaylist; + public static MoveSongInPlaylistDelegate MoveSongInPlaylist + { + internal get { return _MoveSongInPlaylist; } + set { _MoveSongInPlaylist = value; } + } + + private static PlaylistContainsSongDelegate _PlaylistContainsSong; + public static PlaylistContainsSongDelegate PlaylistContainsSong + { + internal get { return _PlaylistContainsSong; } + set { _PlaylistContainsSong = value; } + } + + private static GetPlaylistSongsDelegate _GetPlaylistSongs; + public static GetPlaylistSongsDelegate GetPlaylistSongs + { + internal get { return _GetPlaylistSongs; } + set { _GetPlaylistSongs = value; } + } + + private static RemovePlaylistDelegate _RemovePlaylist; + public static RemovePlaylistDelegate RemovePlaylist + { + internal get { return _RemovePlaylist; } + set { _RemovePlaylist = value; } + } + + private static AddPlaylistDelegate _AddPlaylist; + public static AddPlaylistDelegate AddPlaylist + { + internal get { return _AddPlaylist; } + set { _AddPlaylist = value; } + } + + #endregion + + #region user management + + private static ValidatePasswordDelegate _ValidatePassword; + public static ValidatePasswordDelegate ValidatePassword + { + internal get { return CServer._ValidatePassword; } + set { CServer._ValidatePassword = value; } + } + + private static GetUserRoleDelegate _GetUserRole; + public static GetUserRoleDelegate GetUserRole + { + internal get { return CServer._GetUserRole; } + set { CServer._GetUserRole = value; } + } + + private static SetUserRoleDelegate _SetUserRole; + public static SetUserRoleDelegate SetUserRole + { + internal get { return CServer._SetUserRole; } + set { CServer._SetUserRole = value; } + } + + private static GetUserIdFromUsernameDelegate _GetUserIdFromUsername; + public static GetUserIdFromUsernameDelegate GetUserIdFromUsername + { + internal get { return CServer._GetUserIdFromUsername; } + set { CServer._GetUserIdFromUsername = value; } + } + + #endregion + + public CServer(int port, bool encrypted) + { + _Init(port, encrypted); + } + + #region server control + + private void _Init(int port, bool encrypted) + { + string hostname = Dns.GetHostName(); + if (encrypted) + { + _BaseAddress = new Uri("https://" + hostname + ":" + port + "/"); + } + else + { + _BaseAddress = new Uri("http://" + hostname + ":" + port + "/"); + } + this._Encrypted = encrypted; + _Host = new WebServiceHost(typeof(CWebservice), _BaseAddress); + + WebHttpBinding wb = new WebHttpBinding + { + MaxReceivedMessageSize = 10485760, + MaxBufferSize = 10485760, + MaxBufferPoolSize = 10485760, + ReaderQuotas = { MaxStringContentLength = 10485760, MaxArrayLength = 10485760, MaxBytesPerRead = 10485760 } + }; + if (encrypted) + { + wb.Security.Mode = WebHttpSecurityMode.Transport; + wb.Security.Transport = new HttpTransportSecurity { ClientCredentialType = HttpClientCredentialType.None }; + } + _Host.AddServiceEndpoint(typeof(ICWebservice), wb, ""); } public void Start() { - if (!running) + try { - running = true; + /*ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); + smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; + smb.HttpGetEnabled = true; + host.Description.Behaviors.Add(smb);*/ - tcpListener = new TcpListener(IPAddress.Any, port); - - listenThread = new Thread(new ThreadStart(ListenForClients)); - listenThread.Start(); + _Host.Open(); + } + catch (CommunicationException e) + { + if (e is AddressAccessDeniedException || e is AddressAlreadyInUseException) + { + _RegisterUrlAndCert(_BaseAddress.Port); + try + { + _Host.Abort(); + _Init(_BaseAddress.Port, _Encrypted); + _Host.Open(); + } + catch (CommunicationException e2) + { + _Host.Abort(); + } + } + else + { + _Host.Abort(); + } } } public void Stop() { - if (running) + try { - running = false; - tcpListener.Stop(); - Thread.Sleep(100); - listenThread.Join(); - - lock (clients) - { - int[] cIDs = new int[clients.Count]; - clients.Keys.CopyTo(cIDs, 0); - - foreach (int id in cIDs) - { - clients.Remove(id); - ids.Enqueue(id); - } - } + _Host.Close(); + } + catch (CommunicationException e) + { + _Host.Abort(); } } - private void ListenForClients() + private void _RegisterUrlAndCert(int port) { - tcpListener.Start(); - TcpClient client; +#if WIN - while (running) + ProcessStartInfo info = new ProcessStartInfo { - //wait for new client - try - { - client = tcpListener.AcceptTcpClient(); - } - catch - { - client = null; - } - - if (client != null) - { - int id = ids.Dequeue(); - CConnection connection = new CConnection(client, id, password); - - lock (clients) - { - clients.Add(id, connection); - } - - Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientCom)); - - NetworkStream clientStream = client.GetStream(); - byte[] serverParams = connection.GetKeyParams(); - - try - { - clientStream.Write(serverParams, 0, serverParams.Length); - clientStream.Flush(); - } - catch - { - client = null; - } - - if (client != null) - clientThread.Start(connection); - } - } - } - - private void HandleClientCom(object client) - { - CConnection connection = (CConnection)client; - TcpClient tcpClient = (TcpClient)connection.TcpClient; - NetworkStream clientStream = tcpClient.GetStream(); - - byte[] data = new byte[bufferLength]; - int bytesRead; - - while (running) + FileName = "VocaluxeServerConfig.exe", + Arguments = port.ToString() + " " + _Encrypted.ToString(), + UseShellExecute = true, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + Verb = "runas" + }; + Process p = Process.Start(info); + if (p != null) { - bytesRead = 0; - - try - { - bytesRead = clientStream.Read(data, 0, bufferLength); - } - catch - { - break; - } - - if (bytesRead == 0) - break; - - if (!connection.KeySet) - { - byte[] clientResponse = new byte[bytesRead]; - Array.Copy(data, clientResponse, bytesRead); - connection.CreateServerKey(clientResponse); - } - else - { - //receive message - int messageLength = BitConverter.ToInt32(data, 0); - while (messageLength > bytesRead) - { - if (data.Length < messageLength + bufferLength) - Array.Resize(ref data, messageLength + bufferLength); - bytesRead += clientStream.Read(data, bytesRead, bufferLength); - } - - byte[] message = new byte[bytesRead]; - Array.Copy(data, message, bytesRead); - byte[] decrypted = connection.Decrypt(message); - - byte[] answer = HandleClientMessage(decrypted, connection); - - //send message - byte[] encrypted = connection.Encrypt(answer); - - try - { - clientStream.Write(encrypted, 0, encrypted.Length); - clientStream.Flush(); - } - catch - { - break; - } - } + p.WaitForExit(); + p.Close(); } + +#else + + //Required? + +#endif } - private byte[] HandleClientMessage(byte[] Message, CConnection connection) - { - return requestCallback(connection.ConnectionID, Message); - } + #endregion + } } diff --git a/ClientServerLib/ClientServerLib/CWebservice.cs b/ClientServerLib/ClientServerLib/CWebservice.cs new file mode 100644 index 00000000..8da01ab2 --- /dev/null +++ b/ClientServerLib/ClientServerLib/CWebservice.cs @@ -0,0 +1,458 @@ +using System; +using System.Net; +using System.ServiceModel; +using System.ServiceModel.Web; +using System.IO; +using System.ServiceModel.Channels; + +namespace ServerLib +{ + class CWebservice : ICWebservice + { + private static Guid _GetSession() + { + Guid sessionKey = Guid.Empty; + string sessionHeader = + ((HttpRequestMessageProperty)OperationContext.Current.IncomingMessageProperties["httpRequest"]).Headers["session"]; + if (string.IsNullOrEmpty(sessionHeader)) + { + return sessionKey; + } + try + { + sessionKey = Guid.Parse(sessionHeader); + } + catch (Exception e) + { + } + return sessionKey; + } + + public void SendKeyEvent(string key) + { + if (!_CheckRight(EUserRights.UseKeyboard)) + { + return; + } + + if (CServer.SendKeyEvent == null) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound; + WebOperationContext.Current.OutgoingResponse.StatusDescription = "Not found"; + } + } + else + { + CServer.SendKeyEvent(key); + } + } + + #region profile + + public int GetOwnProfileId() + { + Guid sessionKey = _GetSession(); + if (sessionKey == Guid.Empty) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.Forbidden; + WebOperationContext.Current.OutgoingResponse.StatusDescription = "No session"; + } + return -1; + } + int profileId = CSessionControl.GetUserIdFromSession(sessionKey); + if (profileId < 0) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.Forbidden; + WebOperationContext.Current.OutgoingResponse.StatusDescription = "No session"; + } + return -1; + } + return profileId; + } + + public void SendProfile(SProfileData profile) + { + Guid sessionKey = _GetSession(); + + if (profile.ProfileId != -1) //-1 is the id for a new profile + { + if (CSessionControl.GetUserIdFromSession(sessionKey) != profile.ProfileId + && !(_CheckRight(EUserRights.EditAllProfiles) )) + { + return; + } + } + + if (CServer.SendProfileData == null) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound; + WebOperationContext.Current.OutgoingResponse.StatusDescription = "Not found"; + } + return; + } + + CServer.SendProfileData(profile); + } + + public SProfileData GetProfile(int profileId) + { + Guid sessionKey = _GetSession(); + if (_CheckRight(EUserRights.ViewOtherProfiles) || CSessionControl.GetUserIdFromSession(sessionKey) == profileId) + { + if (CServer.GetProfileData == null) + { + return new SProfileData(); + } + + bool isReadonly = (!CSessionControl.RequestRight(sessionKey, EUserRights.EditAllProfiles) && + CSessionControl.GetUserIdFromSession(sessionKey) != profileId); + + return CServer.GetProfileData(profileId, isReadonly); + } + else + { + return new SProfileData(); + } + } + + public SProfileData[] GetProfileList() + { + if (CServer.GetProfileList == null) + { + return new SProfileData[] { }; + } + return CServer.GetProfileList(); + } + + #endregion + + #region photo + + public void SendPhoto(SPhotoData photo) + { + if (_CheckRight(EUserRights.UploadPhotos)) + { + CServer.SendPhoto(photo); + } + } + + #endregion + + #region website + + public Guid Login(string username, string password) + { + Guid sessionId = CSessionControl.OpenSession(username, password); + if (sessionId == Guid.Empty) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.Forbidden; + WebOperationContext.Current.OutgoingResponse.StatusDescription = "Wrong username or password"; + } + } + return sessionId; + } + + public Stream Index() + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.ContentType = "text/html"; + } + + return new MemoryStream(CServer.GetSiteFile("index.html")); + } + + public Stream GetJsFile(string filename) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.ContentType = "text/javascript"; + WebOperationContext.Current.OutgoingResponse.LastModified = DateTime.UtcNow; + WebOperationContext.Current.OutgoingResponse.Headers.Add( + HttpResponseHeader.Expires, + DateTime.UtcNow.AddHours(4).ToString("r")); + } + + byte[] data = CServer.GetSiteFile("js/" + filename); + + if (data != null) + { + return new MemoryStream(data); + } + + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound; + } + return null; + } + + public Stream GetCssFile(string filename) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.ContentType = "text/css"; + WebOperationContext.Current.OutgoingResponse.LastModified = DateTime.UtcNow; + WebOperationContext.Current.OutgoingResponse.Headers.Add( + HttpResponseHeader.Expires, + DateTime.UtcNow.AddHours(4).ToString("r")); + } + + byte[] data = CServer.GetSiteFile("css/" + filename); + + if (data != null) + { + return new MemoryStream(data); + } + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound; + } + return null; + } + + public Stream GetCssImageFile(string filename) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.ContentType = "image/png"; + WebOperationContext.Current.OutgoingResponse.LastModified = DateTime.UtcNow; + WebOperationContext.Current.OutgoingResponse.Headers.Add( + HttpResponseHeader.Expires, + DateTime.UtcNow.AddYears(1).ToString("r")); + } + + byte[] data = CServer.GetSiteFile("css\\images\\" + filename); + + if (data != null) + { + return new MemoryStream(data); + } + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound; + } + return null; + } + + public Stream GetImgFile(string filename) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.ContentType = "image/png"; + WebOperationContext.Current.OutgoingResponse.LastModified = DateTime.UtcNow; + WebOperationContext.Current.OutgoingResponse.Headers.Add( + HttpResponseHeader.Expires, + DateTime.UtcNow.AddYears(1).ToString("r")); + } + + byte[] data = CServer.GetSiteFile("img/" + filename); + + if (data != null) + { + return new MemoryStream(data); + } + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound; + } + return null; + } + + public Stream GetLocaleFile(string filename) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.ContentType = "text/javascript"; + WebOperationContext.Current.OutgoingResponse.LastModified = DateTime.UtcNow; + WebOperationContext.Current.OutgoingResponse.Headers.Add( + HttpResponseHeader.Expires, + DateTime.UtcNow.AddHours(4).ToString("r")); + } + + byte[] data = CServer.GetSiteFile("locales/" + filename); + + if (data != null) + { + return new MemoryStream(data); + } + + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound; + } + return null; + } + + public CBase64Image GetDelayedImage(string id) + { + return CServer.GetDelayedImage(id); + } + + public bool IsServerOnline() + { + return true; + } + + #endregion + + #region songs + + public SSongInfo GetSong(int songId) + { + return CServer.GetSong(songId); + } + + public int GetCurrentSongId() + { + return CServer.GetCurrentSongId(); + } + + public SSongInfo[] GetAllSongs() + { + return CServer.GetAllSongs(); + } + #endregion + + #region playlist + + public SPlaylistInfo[] GetPlaylists() + { + return CServer.GetPlaylists(); + } + + public SPlaylistInfo GetPlaylist(int playlistId) + { + return CServer.GetPlaylist(playlistId); + } + + public void AddSongToPlaylist(int songId, int playlistId, bool allowDuplicates) + { + if (_CheckRight(EUserRights.AddSongToPlaylist)) + { + CServer.AddSongToPlaylist(songId, playlistId, allowDuplicates); + } + } + + public void RemoveSongFromPlaylist(int position, int playlistId, int songId) + { + if (_CheckRight(EUserRights.RemoveSongsFromPlaylists)) + { + CServer.RemoveSongFromPlaylist(position, playlistId, songId); + } + } + + public void MoveSongInPlaylist(int newPosition, int playlistId, int songId) + { + if (_CheckRight(EUserRights.ReorderPlaylists)) + { + CServer.MoveSongInPlaylist(newPosition, playlistId, songId); + } + } + + public bool PlaylistContainsSong(int songId, int playlistId) + { + return CServer.PlaylistContainsSong(songId, playlistId); + } + + public SPlaylistSongInfo[] GetPlaylistSongs(int playlistId) + { + return CServer.GetPlaylistSongs(playlistId); + } + + public void RemovePlaylist(int playlistId) + { + if (_CheckRight(EUserRights.DeletePlaylists)) + { + CServer.RemovePlaylist(playlistId); + } + } + + public int AddPlaylist(string playlistName) + { + if (_CheckRight(EUserRights.CreatePlaylists)) + { + return CServer.AddPlaylist(playlistName); + } + return -1; + } + + #endregion + + #region user management + + public int GetUserRole(int profileId) + { + return CServer.GetUserRole(profileId); + } + + public void SetUserRole(int profileId, int userRole) + { + if (_CheckRight(EUserRights.EditAllProfiles)) + { + CServer.SetUserRole(profileId, userRole); + } + } + + public bool HasUserRight(int right) + { + return _CheckRightWithNoErrorMessage((EUserRights)right); + } + + private static bool _CheckRight(EUserRights requestedRight) + { + Guid sessionKey = _GetSession(); + + if (sessionKey == Guid.Empty) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.Forbidden; + WebOperationContext.Current.OutgoingResponse.StatusDescription = "No session"; + } + return false; + } + + if (!CSessionControl.RequestRight(sessionKey, requestedRight)) + { + if (WebOperationContext.Current != null) + { + WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.Forbidden; + WebOperationContext.Current.OutgoingResponse.StatusDescription = "Not allowed"; + } + return false; + } + return true; + } + + private static bool _CheckRightWithNoErrorMessage(EUserRights requestedRight) + { + Guid sessionKey = _GetSession(); + + if (sessionKey == Guid.Empty) + { + return false; + } + + if (!CSessionControl.RequestRight(sessionKey, requestedRight)) + { + return false; + } + + return true; + } + + #endregion + + } +} diff --git a/ClientServerLib/ClientServerLib/DataStructs.cs b/ClientServerLib/ClientServerLib/DataStructs.cs new file mode 100644 index 00000000..cf52fd80 --- /dev/null +++ b/ClientServerLib/ClientServerLib/DataStructs.cs @@ -0,0 +1,196 @@ +using System; +using System.Linq; +using System.Runtime.Serialization; +using System.Drawing; +using System.IO; +using System.Drawing.Imaging; +using System.Text.RegularExpressions; + +namespace ServerLib +{ + public delegate bool SendKeyEventDelegate(string key); + + + #region profile + + public delegate SProfileData GetProfileDataDelegate(int profileId, bool isReadonly); + public delegate bool SendProfileDataDelegate(SProfileData profile); + public delegate SProfileData[] GetProfileListDelegate(); + + [DataContract] + public struct SProfileData + { + [DataMember] + public CBase64Image Avatar; + [DataMember] + public string PlayerName; + [DataMember] + public int Type; + [DataMember] + public int Difficulty; + [DataMember] + public int ProfileId; + [DataMember] + public bool IsEditable; + [DataMember] + public string Password; + } + + #endregion + + #region photo + + public delegate bool SendPhotoDelegate(SPhotoData photo); + + [DataContract] + public struct SPhotoData + { + [DataMember] + public CBase64Image Photo; + //Add infomation about the user who took this image?? + } + + #endregion + + #region website + + public delegate byte[] GetSiteFileDelegate(string filename); + + public delegate CBase64Image GetDelayedImageDelegate(string hashedFilename); + + #endregion + + [DataContract] + public class CBase64Image + { + [DataMember] + private string base64Data = ""; + + [DataMember] + private string imageId = ""; + + public CBase64Image(Image img, ImageFormat format) + { + MemoryStream ms = new MemoryStream(); + img.Save(ms, format); + string formatString = ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == format.Guid).FilenameExtension.Replace("*.", "").ToLower(); + base64Data = "data:image/" + formatString + ";base64," + Convert.ToBase64String(ms.ToArray()); + } + + public CBase64Image(string imageId) + { + this.imageId = imageId; + } + + public Image GetImage() + { + string onlyBase64Data = base64Data.Substring(base64Data.IndexOf(";base64,") + (";base64,").Length); + byte[] imageData = Convert.FromBase64String(onlyBase64Data); + MemoryStream ms = new MemoryStream(imageData, 0, imageData.Length); + ms.Write(imageData, 0, imageData.Length); + Image image = Image.FromStream(ms, true); + return image; + } + + public string GetImageType() + { + Match match = Regex.Match(base64Data, "(?<=data:image/)[a-zA-Z]+(?=;base64)"); + return match.Success ? match.Groups[0].Value : ""; + } + + + } + + #region songs + + public delegate SSongInfo GetSongDelegate(int songId); + + public delegate SSongInfo[] GetAllSongsDelegate(); + + public delegate int GetCurrentSongIdDelegate(); + + + [DataContract] + public struct SSongInfo + { + [DataMember] + public string Title; + [DataMember] + public string Artist; + [DataMember] + public CBase64Image Cover; + [DataMember] + public string Genre { get; set; } + [DataMember] + public string Language { get; set; } + [DataMember] + public string Year { get; set; } + [DataMember] + public bool IsDuet { get; set; } + [DataMember] + public int SongId { get; set; } + } + + #endregion + + #region playlists + public delegate SPlaylistInfo[] GetPlaylistsDelegate(); + + public delegate SPlaylistInfo GetPlaylistDelegate(int playlistId); + + public delegate void AddSongToPlaylistDelegate(int songId, int playlistId, bool allowDuplicates); + + public delegate void RemoveSongFromPlaylistDelegate(int position, int playlistId, int songId); + + public delegate void MoveSongInPlaylistDelegate(int newPosition, int playlistId, int songId); + + public delegate bool PlaylistContainsSongDelegate(int songId, int playlistId); + + public delegate SPlaylistSongInfo[] GetPlaylistSongsDelegate(int playlistId); + + public delegate void RemovePlaylistDelegate(int playlistId); + + public delegate int AddPlaylistDelegate(string playlistName); + + [DataContract] + public struct SPlaylistSongInfo + { + [DataMember] + public SSongInfo Song; + [DataMember] + public int PlaylistId; + [DataMember] + public int PlaylistPosition; + [DataMember] + public int GameMode; + } + + [DataContract] + public struct SPlaylistInfo + { + [DataMember] + public int PlaylistId; + [DataMember] + public string PlaylistName; + [DataMember] + public int SongCount; + [DataMember] + public string LastChanged; + } + + #endregion + + #region user management + + public delegate void SetPasswordDelegate(int profileId, string newPassword); + + public delegate bool ValidatePasswordDelegate(int profileId, string password); + + public delegate int GetUserRoleDelegate(int profileId); + + public delegate void SetUserRoleDelegate(int profileId, int userRole); + + public delegate int GetUserIdFromUsernameDelegate(string username); + + #endregion +} diff --git a/ClientServerLib/ClientServerLib/DeffieHellman/BigInt.cs b/ClientServerLib/ClientServerLib/DeffieHellman/BigInt.cs deleted file mode 100644 index c667644f..00000000 --- a/ClientServerLib/ClientServerLib/DeffieHellman/BigInt.cs +++ /dev/null @@ -1,2975 +0,0 @@ -//************************************************************************************ -// BigInteger Class Version 1.03 -// -// Copyright (c) 2002 Chew Keong TAN -// All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, provided that the above -// copyright notice(s) and this permission notice appear in all copies of -// the Software and that both the above copyright notice(s) and this -// permission notice appear in supporting documentation. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -// OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -// HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL -// INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING -// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION -// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -// -// -// Disclaimer -// ---------- -// Although reasonable care has been taken to ensure the correctness of this -// implementation, this code should never be used in any application without -// proper verification and testing. I disclaim all liability and responsibility -// to any person or entity with respect to any loss or damage caused, or alleged -// to be caused, directly or indirectly, by the use of this BigInteger class. -// -// Comments, bugs and suggestions to -// (http://www.codeproject.com/csharp/biginteger.asp) -// -// -// Overloaded Operators +, -, *, /, %, >>, <<, ==, !=, >, <, >=, <=, &, |, ^, ++, --, ~ -// -// Features -// -------- -// 1) Arithmetic operations involving large signed integers (2's complement). -// 2) Primality test using Fermat little theorm, Rabin Miller's method, -// Solovay Strassen's method and Lucas strong pseudoprime. -// 3) Modulo exponential with Barrett's reduction. -// 4) Inverse modulo. -// 5) Pseudo prime generation. -// 6) Co-prime generation. -// -// -// Known Problem -// ------------- -// This pseudoprime passes my implementation of -// primality test but failed in JDK's isProbablePrime test. -// -// byte[] pseudoPrime1 = { (byte)0x00, -// (byte)0x85, (byte)0x84, (byte)0x64, (byte)0xFD, (byte)0x70, (byte)0x6A, -// (byte)0x9F, (byte)0xF0, (byte)0x94, (byte)0x0C, (byte)0x3E, (byte)0x2C, -// (byte)0x74, (byte)0x34, (byte)0x05, (byte)0xC9, (byte)0x55, (byte)0xB3, -// (byte)0x85, (byte)0x32, (byte)0x98, (byte)0x71, (byte)0xF9, (byte)0x41, -// (byte)0x21, (byte)0x5F, (byte)0x02, (byte)0x9E, (byte)0xEA, (byte)0x56, -// (byte)0x8D, (byte)0x8C, (byte)0x44, (byte)0xCC, (byte)0xEE, (byte)0xEE, -// (byte)0x3D, (byte)0x2C, (byte)0x9D, (byte)0x2C, (byte)0x12, (byte)0x41, -// (byte)0x1E, (byte)0xF1, (byte)0xC5, (byte)0x32, (byte)0xC3, (byte)0xAA, -// (byte)0x31, (byte)0x4A, (byte)0x52, (byte)0xD8, (byte)0xE8, (byte)0xAF, -// (byte)0x42, (byte)0xF4, (byte)0x72, (byte)0xA1, (byte)0x2A, (byte)0x0D, -// (byte)0x97, (byte)0xB1, (byte)0x31, (byte)0xB3, -// }; -// -// -// Change Log -// ---------- -// 1) September 23, 2002 (Version 1.03) -// - Fixed operator- to give correct data length. -// - Added Lucas sequence generation. -// - Added Strong Lucas Primality test. -// - Added integer square root method. -// - Added setBit/unsetBit methods. -// - New isProbablePrime() method which do not require the -// confident parameter. -// -// 2) August 29, 2002 (Version 1.02) -// - Fixed bug in the exponentiation of negative numbers. -// - Faster modular exponentiation using Barrett reduction. -// - Added getBytes() method. -// - Fixed bug in ToHexString method. -// - Added overloading of ^ operator. -// - Faster computation of Jacobi symbol. -// -// 3) August 19, 2002 (Version 1.01) -// - Big integer is stored and manipulated as unsigned integers (4 bytes) instead of -// individual bytes this gives significant performance improvement. -// - Updated Fermat's Little Theorem test to use a^(p-1) mod p = 1 -// - Added isProbablePrime method. -// - Updated documentation. -// -// 4) August 9, 2002 (Version 1.0) -// - Initial Release. -// -// -// References -// [1] D. E. Knuth, "Seminumerical Algorithms", The Art of Computer Programming Vol. 2, -// 3rd Edition, Addison-Wesley, 1998. -// -// [2] K. H. Rosen, "Elementary Number Theory and Its Applications", 3rd Ed, -// Addison-Wesley, 1993. -// -// [3] B. Schneier, "Applied Cryptography", 2nd Ed, John Wiley & Sons, 1996. -// -// [4] A. Menezes, P. van Oorschot, and S. Vanstone, "Handbook of Applied Cryptography", -// CRC Press, 1996, www.cacr.math.uwaterloo.ca/hac -// -// [5] A. Bosselaers, R. Govaerts, and J. Vandewalle, "Comparison of Three Modular -// Reduction Functions," Proc. CRYPTO'93, pp.175-186. -// -// [6] R. Baillie and S. S. Wagstaff Jr, "Lucas Pseudoprimes", Mathematics of Computation, -// Vol. 35, No. 152, Oct 1980, pp. 1391-1417. -// -// [7] H. C. Williams, "Édouard Lucas and Primality Testing", Canadian Mathematical -// Society Series of Monographs and Advance Texts, vol. 22, John Wiley & Sons, New York, -// NY, 1998. -// -// [8] P. Ribenboim, "The new book of prime number records", 3rd edition, Springer-Verlag, -// New York, NY, 1995. -// -// [9] M. Joye and J.-J. Quisquater, "Efficient computation of full Lucas sequences", -// Electronics Letters, 32(6), 1996, pp 537-538. -// -//************************************************************************************ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace DiffieHellman -{ - internal class BigInteger : IDisposable - { - // maximum length of the BigInteger in uint (4 bytes) - // change this to suit the required level of precision. - - private const int maxLength = 50; - - // primes smaller than 2000 to test the generated prime number - - public static readonly int[] primesBelow2000 = { - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, - 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, - 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, - 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, - 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, - 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, - 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, - 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, - 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, - 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, - 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, - 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, - 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, - 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, - 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, - 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, - 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, - 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, - 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, - 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999 }; - - - private uint[] data = null; // stores bytes from the Big Integer - public int dataLength; // number of actual chars used - - - //*********************************************************************** - // Constructor (Default value for BigInteger is 0 - //*********************************************************************** - - public BigInteger() - { - data = new uint[maxLength]; - dataLength = 1; - } - - - //*********************************************************************** - // Constructor (Default value provided by long) - //*********************************************************************** - - public BigInteger(long value) - { - data = new uint[maxLength]; - long tempVal = value; - - // copy bytes from long to BigInteger without any assumption of - // the length of the long datatype - - dataLength = 0; - while (value != 0 && dataLength < maxLength) - { - data[dataLength] = (uint)(value & 0xFFFFFFFF); - value >>= 32; - dataLength++; - } - - if (tempVal > 0) // overflow check for +ve value - { - if (value != 0 || (data[maxLength - 1] & 0x80000000) != 0) - throw (new ArithmeticException("Positive overflow in constructor.")); - } - else if (tempVal < 0) // underflow check for -ve value - { - if (value != -1 || (data[dataLength - 1] & 0x80000000) == 0) - throw (new ArithmeticException("Negative underflow in constructor.")); - } - - if (dataLength == 0) - dataLength = 1; - } - - - //*********************************************************************** - // Constructor (Default value provided by ulong) - //*********************************************************************** - - public BigInteger(ulong value) - { - data = new uint[maxLength]; - - // copy bytes from ulong to BigInteger without any assumption of - // the length of the ulong datatype - - dataLength = 0; - while (value != 0 && dataLength < maxLength) - { - data[dataLength] = (uint)(value & 0xFFFFFFFF); - value >>= 32; - dataLength++; - } - - if (value != 0 || (data[maxLength - 1] & 0x80000000) != 0) - throw (new ArithmeticException("Positive overflow in constructor.")); - - if (dataLength == 0) - dataLength = 1; - } - - - - //*********************************************************************** - // Constructor (Default value provided by BigInteger) - //*********************************************************************** - - public BigInteger(BigInteger bi) - { - data = new uint[maxLength]; - - dataLength = bi.dataLength; - - for (int i = 0; i < dataLength; i++) - data[i] = bi.data[i]; - } - - - //*********************************************************************** - // Constructor (Default value provided by a string of digits of the - // specified base) - // - // Example (base 10) - // ----------------- - // To initialize "a" with the default value of 1234 in base 10 - // BigInteger a = new BigInteger("1234", 10) - // - // To initialize "a" with the default value of -1234 - // BigInteger a = new BigInteger("-1234", 10) - // - // Example (base 16) - // ----------------- - // To initialize "a" with the default value of 0x1D4F in base 16 - // BigInteger a = new BigInteger("1D4F", 16) - // - // To initialize "a" with the default value of -0x1D4F - // BigInteger a = new BigInteger("-1D4F", 16) - // - // Note that string values are specified in the - // format. - // - //*********************************************************************** - - public BigInteger(string value, int radix) - { - BigInteger multiplier = new BigInteger(1); - BigInteger result = new BigInteger(); - value = (value.ToUpper()).Trim(); - int limit = 0; - - if (value[0] == '-') - limit = 1; - - for (int i = value.Length - 1; i >= limit; i--) - { - int posVal = (int)value[i]; - - if (posVal >= '0' && posVal <= '9') - posVal -= '0'; - else if (posVal >= 'A' && posVal <= 'Z') - posVal = (posVal - 'A') + 10; - else - posVal = 9999999; // arbitrary large - - - if (posVal >= radix) - throw (new ArithmeticException("Invalid string in constructor.")); - else - { - if (value[0] == '-') - posVal = -posVal; - - result = result + (multiplier * posVal); - - if ((i - 1) >= limit) - multiplier = multiplier * radix; - } - } - - if (value[0] == '-') // negative values - { - if ((result.data[maxLength - 1] & 0x80000000) == 0) - throw (new ArithmeticException("Negative underflow in constructor.")); - } - else // positive values - { - if ((result.data[maxLength - 1] & 0x80000000) != 0) - throw (new ArithmeticException("Positive overflow in constructor.")); - } - - data = new uint[maxLength]; - for (int i = 0; i < result.dataLength; i++) - data[i] = result.data[i]; - - dataLength = result.dataLength; - } - - - //*********************************************************************** - // Constructor (Default value provided by an array of bytes) - // - // The lowest index of the input byte array (i.e [0]) should contain the - // most significant byte of the number, and the highest index should - // contain the least significant byte. - // - // E.g. - // To initialize "a" with the default value of 0x1D4F in base 16 - // byte[] temp = { 0x1D, 0x4F }; - // BigInteger a = new BigInteger(temp) - // - // Note that this method of initialization does not allow the - // sign to be specified. - // - //*********************************************************************** - - public BigInteger(byte[] inData) - { - dataLength = inData.Length >> 2; - - int leftOver = inData.Length & 0x3; - if (leftOver != 0) // length not multiples of 4 - dataLength++; - - - if (dataLength > maxLength) - throw (new ArithmeticException("Byte overflow in constructor.")); - - data = new uint[maxLength]; - - for (int i = inData.Length - 1, j = 0; i >= 3; i -= 4, j++) - { - data[j] = (uint)((inData[i - 3] << 24) + (inData[i - 2] << 16) + - (inData[i - 1] << 8) + inData[i]); - } - - if (leftOver == 1) - data[dataLength - 1] = (uint)inData[0]; - else if (leftOver == 2) - data[dataLength - 1] = (uint)((inData[0] << 8) + inData[1]); - else if (leftOver == 3) - data[dataLength - 1] = (uint)((inData[0] << 16) + (inData[1] << 8) + inData[2]); - - - while (dataLength > 1 && data[dataLength - 1] == 0) - dataLength--; - - //Console.WriteLine("Len = " + dataLength); - } - - - //*********************************************************************** - // Constructor (Default value provided by an array of bytes of the - // specified length.) - //*********************************************************************** - - public BigInteger(byte[] inData, int inLen) - { - dataLength = inLen >> 2; - - int leftOver = inLen & 0x3; - if (leftOver != 0) // length not multiples of 4 - dataLength++; - - if (dataLength > maxLength || inLen > inData.Length) - throw (new ArithmeticException("Byte overflow in constructor.")); - - - data = new uint[maxLength]; - - for (int i = inLen - 1, j = 0; i >= 3; i -= 4, j++) - { - data[j] = (uint)((inData[i - 3] << 24) + (inData[i - 2] << 16) + - (inData[i - 1] << 8) + inData[i]); - } - - if (leftOver == 1) - data[dataLength - 1] = (uint)inData[0]; - else if (leftOver == 2) - data[dataLength - 1] = (uint)((inData[0] << 8) + inData[1]); - else if (leftOver == 3) - data[dataLength - 1] = (uint)((inData[0] << 16) + (inData[1] << 8) + inData[2]); - - - if (dataLength == 0) - dataLength = 1; - - while (dataLength > 1 && data[dataLength - 1] == 0) - dataLength--; - - //Console.WriteLine("Len = " + dataLength); - } - - - //*********************************************************************** - // Constructor (Default value provided by an array of unsigned integers) - //********************************************************************* - - public BigInteger(uint[] inData) - { - dataLength = inData.Length; - - if (dataLength > maxLength) - throw (new ArithmeticException("Byte overflow in constructor.")); - - data = new uint[maxLength]; - - for (int i = dataLength - 1, j = 0; i >= 0; i--, j++) - data[j] = inData[i]; - - while (dataLength > 1 && data[dataLength - 1] == 0) - dataLength--; - - //Console.WriteLine("Len = " + dataLength); - } - - - //*********************************************************************** - // Overloading of the typecast operator. - // For BigInteger bi = 10; - //*********************************************************************** - - public static implicit operator BigInteger(long value) - { - return (new BigInteger(value)); - } - - public static implicit operator BigInteger(ulong value) - { - return (new BigInteger(value)); - } - - public static implicit operator BigInteger(int value) - { - return (new BigInteger((long)value)); - } - - public static implicit operator BigInteger(uint value) - { - return (new BigInteger((ulong)value)); - } - - - //*********************************************************************** - // Overloading of addition operator - //*********************************************************************** - - public static BigInteger operator +(BigInteger bi1, BigInteger bi2) - { - BigInteger result = new BigInteger(); - - result.dataLength = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength; - - long carry = 0; - for (int i = 0; i < result.dataLength; i++) - { - long sum = (long)bi1.data[i] + (long)bi2.data[i] + carry; - carry = sum >> 32; - result.data[i] = (uint)(sum & 0xFFFFFFFF); - } - - if (carry != 0 && result.dataLength < maxLength) - { - result.data[result.dataLength] = (uint)(carry); - result.dataLength++; - } - - while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) - result.dataLength--; - - - // overflow check - int lastPos = maxLength - 1; - if ((bi1.data[lastPos] & 0x80000000) == (bi2.data[lastPos] & 0x80000000) && - (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) - { - throw (new ArithmeticException()); - } - - return result; - } - - - //*********************************************************************** - // Overloading of the unary ++ operator - //*********************************************************************** - - public static BigInteger operator ++(BigInteger bi1) - { - BigInteger result = new BigInteger(bi1); - - long val, carry = 1; - int index = 0; - - while (carry != 0 && index < maxLength) - { - val = (long)(result.data[index]); - val++; - - result.data[index] = (uint)(val & 0xFFFFFFFF); - carry = val >> 32; - - index++; - } - - if (index > result.dataLength) - result.dataLength = index; - else - { - while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) - result.dataLength--; - } - - // overflow check - int lastPos = maxLength - 1; - - // overflow if initial value was +ve but ++ caused a sign - // change to negative. - - if ((bi1.data[lastPos] & 0x80000000) == 0 && - (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) - { - throw (new ArithmeticException("Overflow in ++.")); - } - return result; - } - - - //*********************************************************************** - // Overloading of subtraction operator - //*********************************************************************** - - public static BigInteger operator -(BigInteger bi1, BigInteger bi2) - { - BigInteger result = new BigInteger(); - - result.dataLength = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength; - - long carryIn = 0; - for (int i = 0; i < result.dataLength; i++) - { - long diff; - - diff = (long)bi1.data[i] - (long)bi2.data[i] - carryIn; - result.data[i] = (uint)(diff & 0xFFFFFFFF); - - if (diff < 0) - carryIn = 1; - else - carryIn = 0; - } - - // roll over to negative - if (carryIn != 0) - { - for (int i = result.dataLength; i < maxLength; i++) - result.data[i] = 0xFFFFFFFF; - result.dataLength = maxLength; - } - - // fixed in v1.03 to give correct datalength for a - (-b) - while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) - result.dataLength--; - - // overflow check - - int lastPos = maxLength - 1; - if ((bi1.data[lastPos] & 0x80000000) != (bi2.data[lastPos] & 0x80000000) && - (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) - { - throw (new ArithmeticException()); - } - - return result; - } - - - //*********************************************************************** - // Overloading of the unary -- operator - //*********************************************************************** - - public static BigInteger operator --(BigInteger bi1) - { - BigInteger result = new BigInteger(bi1); - - long val; - bool carryIn = true; - int index = 0; - - while (carryIn && index < maxLength) - { - val = (long)(result.data[index]); - val--; - - result.data[index] = (uint)(val & 0xFFFFFFFF); - - if (val >= 0) - carryIn = false; - - index++; - } - - if (index > result.dataLength) - result.dataLength = index; - - while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) - result.dataLength--; - - // overflow check - int lastPos = maxLength - 1; - - // overflow if initial value was -ve but -- caused a sign - // change to positive. - - if ((bi1.data[lastPos] & 0x80000000) != 0 && - (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) - { - throw (new ArithmeticException("Underflow in --.")); - } - - return result; - } - - - //*********************************************************************** - // Overloading of multiplication operator - //*********************************************************************** - - public static BigInteger operator *(BigInteger bi1, BigInteger bi2) - { - int lastPos = maxLength - 1; - bool bi1Neg = false, bi2Neg = false; - - // take the absolute value of the inputs - try - { - if ((bi1.data[lastPos] & 0x80000000) != 0) // bi1 negative - { - bi1Neg = true; bi1 = -bi1; - } - if ((bi2.data[lastPos] & 0x80000000) != 0) // bi2 negative - { - bi2Neg = true; bi2 = -bi2; - } - } - catch (Exception) { } - - BigInteger result = new BigInteger(); - - // multiply the absolute values - try - { - for (int i = 0; i < bi1.dataLength; i++) - { - if (bi1.data[i] == 0) continue; - - ulong mcarry = 0; - for (int j = 0, k = i; j < bi2.dataLength; j++, k++) - { - // k = i + j - ulong val = ((ulong)bi1.data[i] * (ulong)bi2.data[j]) + - (ulong)result.data[k] + mcarry; - - result.data[k] = (uint)(val & 0xFFFFFFFF); - mcarry = (val >> 32); - } - - if (mcarry != 0) - result.data[i + bi2.dataLength] = (uint)mcarry; - } - } - catch (Exception) - { - throw (new ArithmeticException("Multiplication overflow.")); - } - - - result.dataLength = bi1.dataLength + bi2.dataLength; - if (result.dataLength > maxLength) - result.dataLength = maxLength; - - while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) - result.dataLength--; - - // overflow check (result is -ve) - if ((result.data[lastPos] & 0x80000000) != 0) - { - if (bi1Neg != bi2Neg && result.data[lastPos] == 0x80000000) // different sign - { - // handle the special case where multiplication produces - // a max negative number in 2's complement. - - if (result.dataLength == 1) - return result; - else - { - bool isMaxNeg = true; - for (int i = 0; i < result.dataLength - 1 && isMaxNeg; i++) - { - if (result.data[i] != 0) - isMaxNeg = false; - } - - if (isMaxNeg) - return result; - } - } - - throw (new ArithmeticException("Multiplication overflow.")); - } - - // if input has different signs, then result is -ve - if (bi1Neg != bi2Neg) - return -result; - - return result; - } - - - - //*********************************************************************** - // Overloading of unary << operators - //*********************************************************************** - - public static BigInteger operator <<(BigInteger bi1, int shiftVal) - { - BigInteger result = new BigInteger(bi1); - result.dataLength = ShiftLeft(result.data, shiftVal); - - return result; - } - - - // least significant bits at lower part of buffer - - private static int ShiftLeft(uint[] buffer, int shiftVal) - { - int shiftAmount = 32; - int bufLen = buffer.Length; - - while (bufLen > 1 && buffer[bufLen - 1] == 0) - bufLen--; - - for (int count = shiftVal; count > 0; ) - { - if (count < shiftAmount) - shiftAmount = count; - - //Console.WriteLine("shiftAmount = {0}", shiftAmount); - - ulong carry = 0; - for (int i = 0; i < bufLen; i++) - { - ulong val = ((ulong)buffer[i]) << shiftAmount; - val |= carry; - - buffer[i] = (uint)(val & 0xFFFFFFFF); - carry = val >> 32; - } - - if (carry != 0) - { - if (bufLen + 1 <= buffer.Length) - { - buffer[bufLen] = (uint)carry; - bufLen++; - } - } - count -= shiftAmount; - } - return bufLen; - } - - - //*********************************************************************** - // Overloading of unary >> operators - //*********************************************************************** - - public static BigInteger operator >>(BigInteger bi1, int shiftVal) - { - BigInteger result = new BigInteger(bi1); - result.dataLength = ShiftRight(result.data, shiftVal); - - - if ((bi1.data[maxLength - 1] & 0x80000000) != 0) // negative - { - for (int i = maxLength - 1; i >= result.dataLength; i--) - result.data[i] = 0xFFFFFFFF; - - uint mask = 0x80000000; - for (int i = 0; i < 32; i++) - { - if ((result.data[result.dataLength - 1] & mask) != 0) - break; - - result.data[result.dataLength - 1] |= mask; - mask >>= 1; - } - result.dataLength = maxLength; - } - - return result; - } - - - private static int ShiftRight(uint[] buffer, int shiftVal) - { - int shiftAmount = 32; - int invShift = 0; - int bufLen = buffer.Length; - - while (bufLen > 1 && buffer[bufLen - 1] == 0) - bufLen--; - - //Console.WriteLine("bufLen = " + bufLen + " buffer.Length = " + buffer.Length); - - for (int count = shiftVal; count > 0; ) - { - if (count < shiftAmount) - { - shiftAmount = count; - invShift = 32 - shiftAmount; - } - - //Console.WriteLine("shiftAmount = {0}", shiftAmount); - - ulong carry = 0; - for (int i = bufLen - 1; i >= 0; i--) - { - ulong val = ((ulong)buffer[i]) >> shiftAmount; - val |= carry; - - carry = ((ulong)buffer[i]) << invShift; - buffer[i] = (uint)(val); - } - - count -= shiftAmount; - } - - while (bufLen > 1 && buffer[bufLen - 1] == 0) - bufLen--; - - return bufLen; - } - - - //*********************************************************************** - // Overloading of the NOT operator (1's complement) - //*********************************************************************** - - public static BigInteger operator ~(BigInteger bi1) - { - BigInteger result = new BigInteger(bi1); - - for (int i = 0; i < maxLength; i++) - result.data[i] = (uint)(~(bi1.data[i])); - - result.dataLength = maxLength; - - while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) - result.dataLength--; - - return result; - } - - - //*********************************************************************** - // Overloading of the NEGATE operator (2's complement) - //*********************************************************************** - - public static BigInteger operator -(BigInteger bi1) - { - // handle neg of zero separately since it'll cause an overflow - // if we proceed. - - if (bi1.dataLength == 1 && bi1.data[0] == 0) - return (new BigInteger()); - - BigInteger result = new BigInteger(bi1); - - // 1's complement - for (int i = 0; i < maxLength; i++) - result.data[i] = (uint)(~(bi1.data[i])); - - // add one to result of 1's complement - long val, carry = 1; - int index = 0; - - while (carry != 0 && index < maxLength) - { - val = (long)(result.data[index]); - val++; - - result.data[index] = (uint)(val & 0xFFFFFFFF); - carry = val >> 32; - - index++; - } - - if ((bi1.data[maxLength - 1] & 0x80000000) == (result.data[maxLength - 1] & 0x80000000)) - throw (new ArithmeticException("Overflow in negation.\n")); - - result.dataLength = maxLength; - - while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) - result.dataLength--; - return result; - } - - - //*********************************************************************** - // Overloading of equality operator - //*********************************************************************** - - public static bool operator ==(BigInteger bi1, BigInteger bi2) - { - return bi1.Equals(bi2); - } - - - public static bool operator !=(BigInteger bi1, BigInteger bi2) - { - return !(bi1.Equals(bi2)); - } - - - public override bool Equals(object o) - { - if (o == null) - return false; - - BigInteger bi = (BigInteger)o; - - if (this.dataLength != bi.dataLength) - return false; - - for (int i = 0; i < this.dataLength; i++) - { - if (this.data[i] != bi.data[i]) - return false; - } - return true; - } - - - public override int GetHashCode() - { - return this.ToString().GetHashCode(); - } - - - //*********************************************************************** - // Overloading of inequality operator - //*********************************************************************** - - public static bool operator >(BigInteger bi1, BigInteger bi2) - { - int pos = maxLength - 1; - - // bi1 is negative, bi2 is positive - if ((bi1.data[pos] & 0x80000000) != 0 && (bi2.data[pos] & 0x80000000) == 0) - return false; - - // bi1 is positive, bi2 is negative - else if ((bi1.data[pos] & 0x80000000) == 0 && (bi2.data[pos] & 0x80000000) != 0) - return true; - - // same sign - int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength; - for (pos = len - 1; pos >= 0 && bi1.data[pos] == bi2.data[pos]; pos--) ; - - if (pos >= 0) - { - if (bi1.data[pos] > bi2.data[pos]) - return true; - return false; - } - return false; - } - - - public static bool operator <(BigInteger bi1, BigInteger bi2) - { - int pos = maxLength - 1; - - // bi1 is negative, bi2 is positive - if ((bi1.data[pos] & 0x80000000) != 0 && (bi2.data[pos] & 0x80000000) == 0) - return true; - - // bi1 is positive, bi2 is negative - else if ((bi1.data[pos] & 0x80000000) == 0 && (bi2.data[pos] & 0x80000000) != 0) - return false; - - // same sign - int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength; - for (pos = len - 1; pos >= 0 && bi1.data[pos] == bi2.data[pos]; pos--) ; - - if (pos >= 0) - { - if (bi1.data[pos] < bi2.data[pos]) - return true; - return false; - } - return false; - } - - - public static bool operator >=(BigInteger bi1, BigInteger bi2) - { - return (bi1 == bi2 || bi1 > bi2); - } - - - public static bool operator <=(BigInteger bi1, BigInteger bi2) - { - return (bi1 == bi2 || bi1 < bi2); - } - - - //*********************************************************************** - // Private function that supports the division of two numbers with - // a divisor that has more than 1 digit. - // - // Algorithm taken from [1] - //*********************************************************************** - - private static void MultiByteDivide(BigInteger bi1, BigInteger bi2, - BigInteger outQuotient, BigInteger outRemainder) - { - uint[] result = new uint[maxLength]; - - int remainderLen = bi1.dataLength + 1; - uint[] remainder = new uint[remainderLen]; - - uint mask = 0x80000000; - uint val = bi2.data[bi2.dataLength - 1]; - int shift = 0, resultPos = 0; - - while (mask != 0 && (val & mask) == 0) - { - shift++; mask >>= 1; - } - - //Console.WriteLine("shift = {0}", shift); - //Console.WriteLine("Before bi1 Len = {0}, bi2 Len = {1}", bi1.dataLength, bi2.dataLength); - - for (int i = 0; i < bi1.dataLength; i++) - remainder[i] = bi1.data[i]; - ShiftLeft(remainder, shift); - bi2 = bi2 << shift; - - /* - Console.WriteLine("bi1 Len = {0}, bi2 Len = {1}", bi1.dataLength, bi2.dataLength); - Console.WriteLine("dividend = " + bi1 + "\ndivisor = " + bi2); - for(int q = remainderLen - 1; q >= 0; q--) - Console.Write("{0:x2}", remainder[q]); - Console.WriteLine(); - */ - - int j = remainderLen - bi2.dataLength; - int pos = remainderLen - 1; - - ulong firstDivisorByte = bi2.data[bi2.dataLength - 1]; - ulong secondDivisorByte = bi2.data[bi2.dataLength - 2]; - - int divisorLen = bi2.dataLength + 1; - uint[] dividendPart = new uint[divisorLen]; - - while (j > 0) - { - ulong dividend = ((ulong)remainder[pos] << 32) + (ulong)remainder[pos - 1]; - //Console.WriteLine("dividend = {0}", dividend); - - ulong q_hat = dividend / firstDivisorByte; - ulong r_hat = dividend % firstDivisorByte; - - //Console.WriteLine("q_hat = {0:X}, r_hat = {1:X}", q_hat, r_hat); - - bool done = false; - while (!done) - { - done = true; - - if (q_hat == 0x100000000 || - (q_hat * secondDivisorByte) > ((r_hat << 32) + remainder[pos - 2])) - { - q_hat--; - r_hat += firstDivisorByte; - - if (r_hat < 0x100000000) - done = false; - } - } - - for (int h = 0; h < divisorLen; h++) - dividendPart[h] = remainder[pos - h]; - - BigInteger kk = new BigInteger(dividendPart); - BigInteger ss = bi2 * (long)q_hat; - - //Console.WriteLine("ss before = " + ss); - while (ss > kk) - { - q_hat--; - ss -= bi2; - //Console.WriteLine(ss); - } - BigInteger yy = kk - ss; - - //Console.WriteLine("ss = " + ss); - //Console.WriteLine("kk = " + kk); - //Console.WriteLine("yy = " + yy); - - for (int h = 0; h < divisorLen; h++) - remainder[pos - h] = yy.data[bi2.dataLength - h]; - - /* - Console.WriteLine("dividend = "); - for(int q = remainderLen - 1; q >= 0; q--) - Console.Write("{0:x2}", remainder[q]); - Console.WriteLine("\n************ q_hat = {0:X}\n", q_hat); - */ - - result[resultPos++] = (uint)q_hat; - - pos--; - j--; - } - - outQuotient.dataLength = resultPos; - int y = 0; - for (int x = outQuotient.dataLength - 1; x >= 0; x--, y++) - outQuotient.data[y] = result[x]; - for (; y < maxLength; y++) - outQuotient.data[y] = 0; - - while (outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength - 1] == 0) - outQuotient.dataLength--; - - if (outQuotient.dataLength == 0) - outQuotient.dataLength = 1; - - outRemainder.dataLength = ShiftRight(remainder, shift); - - for (y = 0; y < outRemainder.dataLength; y++) - outRemainder.data[y] = remainder[y]; - for (; y < maxLength; y++) - outRemainder.data[y] = 0; - } - - - //*********************************************************************** - // Private function that supports the division of two numbers with - // a divisor that has only 1 digit. - //*********************************************************************** - - private static void SingleByteDivide(BigInteger bi1, BigInteger bi2, - BigInteger outQuotient, BigInteger outRemainder) - { - uint[] result = new uint[maxLength]; - int resultPos = 0; - - // copy dividend to reminder - for (int i = 0; i < maxLength; i++) - outRemainder.data[i] = bi1.data[i]; - outRemainder.dataLength = bi1.dataLength; - - while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0) - outRemainder.dataLength--; - - ulong divisor = (ulong)bi2.data[0]; - int pos = outRemainder.dataLength - 1; - ulong dividend = (ulong)outRemainder.data[pos]; - - //Console.WriteLine("divisor = " + divisor + " dividend = " + dividend); - //Console.WriteLine("divisor = " + bi2 + "\ndividend = " + bi1); - - if (dividend >= divisor) - { - ulong quotient = dividend / divisor; - result[resultPos++] = (uint)quotient; - - outRemainder.data[pos] = (uint)(dividend % divisor); - } - pos--; - - while (pos >= 0) - { - //Console.WriteLine(pos); - - dividend = ((ulong)outRemainder.data[pos + 1] << 32) + (ulong)outRemainder.data[pos]; - ulong quotient = dividend / divisor; - result[resultPos++] = (uint)quotient; - - outRemainder.data[pos + 1] = 0; - outRemainder.data[pos--] = (uint)(dividend % divisor); - //Console.WriteLine(">>>> " + bi1); - } - - outQuotient.dataLength = resultPos; - int j = 0; - for (int i = outQuotient.dataLength - 1; i >= 0; i--, j++) - outQuotient.data[j] = result[i]; - for (; j < maxLength; j++) - outQuotient.data[j] = 0; - - while (outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength - 1] == 0) - outQuotient.dataLength--; - - if (outQuotient.dataLength == 0) - outQuotient.dataLength = 1; - - while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0) - outRemainder.dataLength--; - } - - - //*********************************************************************** - // Overloading of division operator - //*********************************************************************** - - public static BigInteger operator /(BigInteger bi1, BigInteger bi2) - { - BigInteger quotient = new BigInteger(); - BigInteger remainder = new BigInteger(); - - int lastPos = maxLength - 1; - bool divisorNeg = false, dividendNeg = false; - - if ((bi1.data[lastPos] & 0x80000000) != 0) // bi1 negative - { - bi1 = -bi1; - dividendNeg = true; - } - if ((bi2.data[lastPos] & 0x80000000) != 0) // bi2 negative - { - bi2 = -bi2; - divisorNeg = true; - } - - if (bi1 < bi2) - { - return quotient; - } - - else - { - if (bi2.dataLength == 1) - SingleByteDivide(bi1, bi2, quotient, remainder); - else - MultiByteDivide(bi1, bi2, quotient, remainder); - - if (dividendNeg != divisorNeg) - return -quotient; - - return quotient; - } - } - - - //*********************************************************************** - // Overloading of modulus operator - //*********************************************************************** - - public static BigInteger operator %(BigInteger bi1, BigInteger bi2) - { - BigInteger quotient = new BigInteger(); - BigInteger remainder = new BigInteger(bi1); - - int lastPos = maxLength - 1; - bool dividendNeg = false; - - if ((bi1.data[lastPos] & 0x80000000) != 0) // bi1 negative - { - bi1 = -bi1; - dividendNeg = true; - } - if ((bi2.data[lastPos] & 0x80000000) != 0) // bi2 negative - bi2 = -bi2; - - if (bi1 < bi2) - { - return remainder; - } - - else - { - if (bi2.dataLength == 1) - SingleByteDivide(bi1, bi2, quotient, remainder); - else - MultiByteDivide(bi1, bi2, quotient, remainder); - - if (dividendNeg) - return -remainder; - - return remainder; - } - } - - - //*********************************************************************** - // Overloading of bitwise AND operator - //*********************************************************************** - - public static BigInteger operator &(BigInteger bi1, BigInteger bi2) - { - BigInteger result = new BigInteger(); - - int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength; - - for (int i = 0; i < len; i++) - { - uint sum = (uint)(bi1.data[i] & bi2.data[i]); - result.data[i] = sum; - } - - result.dataLength = maxLength; - - while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) - result.dataLength--; - - return result; - } - - - //*********************************************************************** - // Overloading of bitwise OR operator - //*********************************************************************** - - public static BigInteger operator |(BigInteger bi1, BigInteger bi2) - { - BigInteger result = new BigInteger(); - - int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength; - - for (int i = 0; i < len; i++) - { - uint sum = (uint)(bi1.data[i] | bi2.data[i]); - result.data[i] = sum; - } - - result.dataLength = maxLength; - - while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) - result.dataLength--; - - return result; - } - - - //*********************************************************************** - // Overloading of bitwise XOR operator - //*********************************************************************** - - public static BigInteger operator ^(BigInteger bi1, BigInteger bi2) - { - BigInteger result = new BigInteger(); - - int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength; - - for (int i = 0; i < len; i++) - { - uint sum = (uint)(bi1.data[i] ^ bi2.data[i]); - result.data[i] = sum; - } - - result.dataLength = maxLength; - - while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) - result.dataLength--; - - return result; - } - - - //*********************************************************************** - // Returns max(this, bi) - //*********************************************************************** - - public BigInteger Max(BigInteger bi) - { - if (this > bi) - return (new BigInteger(this)); - else - return (new BigInteger(bi)); - } - - - //*********************************************************************** - // Returns min(this, bi) - //*********************************************************************** - - public BigInteger Min(BigInteger bi) - { - if (this < bi) - return (new BigInteger(this)); - else - return (new BigInteger(bi)); - - } - - - //*********************************************************************** - // Returns the absolute value - //*********************************************************************** - - public BigInteger Abs() - { - if ((this.data[maxLength - 1] & 0x80000000) != 0) - return (-this); - else - return (new BigInteger(this)); - } - - - //*********************************************************************** - // Returns a string representing the BigInteger in base 10. - //*********************************************************************** - - public override string ToString() - { - return ToString(10); - } - - - //*********************************************************************** - // Returns a string representing the BigInteger in sign-and-magnitude - // format in the specified radix. - // - // Example - // ------- - // If the value of BigInteger is -255 in base 10, then - // ToString(16) returns "-FF" - // - //*********************************************************************** - - public string ToString(int radix) - { - if (radix < 2 || radix > 36) - throw (new ArgumentException("Radix must be >= 2 and <= 36")); - - string charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - string result = ""; - - BigInteger a = this; - - bool negative = false; - if ((a.data[maxLength - 1] & 0x80000000) != 0) - { - negative = true; - try - { - a = -a; - } - catch (Exception) { } - } - - BigInteger quotient = new BigInteger(); - BigInteger remainder = new BigInteger(); - BigInteger biRadix = new BigInteger(radix); - - if (a.dataLength == 1 && a.data[0] == 0) - result = "0"; - else - { - while (a.dataLength > 1 || (a.dataLength == 1 && a.data[0] != 0)) - { - SingleByteDivide(a, biRadix, quotient, remainder); - - if (remainder.data[0] < 10) - result = remainder.data[0] + result; - else - result = charSet[(int)remainder.data[0] - 10] + result; - - a = quotient; - } - if (negative) - result = "-" + result; - } - - return result; - } - - - //*********************************************************************** - // Returns a hex string showing the contains of the BigInteger - // - // Examples - // ------- - // 1) If the value of BigInteger is 255 in base 10, then - // ToHexString() returns "FF" - // - // 2) If the value of BigInteger is -255 in base 10, then - // ToHexString() returns ".....FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01", - // which is the 2's complement representation of -255. - // - //*********************************************************************** - - public string ToHexString() - { - string result = data[dataLength - 1].ToString("X"); - - for (int i = dataLength - 2; i >= 0; i--) - { - result += data[i].ToString("X8"); - } - - return result; - } - - - - //*********************************************************************** - // Modulo Exponentiation - //*********************************************************************** - - public BigInteger ModPow(BigInteger exp, BigInteger n) - { - if ((exp.data[maxLength - 1] & 0x80000000) != 0) - throw (new ArithmeticException("Positive exponents only.")); - - BigInteger resultNum = 1; - BigInteger tempNum; - bool thisNegative = false; - - if ((this.data[maxLength - 1] & 0x80000000) != 0) // negative this - { - tempNum = -this % n; - thisNegative = true; - } - else - tempNum = this % n; // ensures (tempNum * tempNum) < b^(2k) - - if ((n.data[maxLength - 1] & 0x80000000) != 0) // negative n - n = -n; - - // calculate constant = b^(2k) / m - BigInteger constant = new BigInteger(); - - int i = n.dataLength << 1; - constant.data[i] = 0x00000001; - constant.dataLength = i + 1; - - constant = constant / n; - int totalBits = exp.BitCount(); - int count = 0; - - // perform squaring and multiply exponentiation - for (int pos = 0; pos < exp.dataLength; pos++) - { - uint mask = 0x01; - //Console.WriteLine("pos = " + pos); - - for (int index = 0; index < 32; index++) - { - if ((exp.data[pos] & mask) != 0) - resultNum = BarrettReduction(resultNum * tempNum, n, constant); - - mask <<= 1; - - tempNum = BarrettReduction(tempNum * tempNum, n, constant); - - - if (tempNum.dataLength == 1 && tempNum.data[0] == 1) - { - if (thisNegative && (exp.data[0] & 0x1) != 0) //odd exp - return -resultNum; - return resultNum; - } - count++; - if (count == totalBits) - break; - } - } - - if (thisNegative && (exp.data[0] & 0x1) != 0) //odd exp - return -resultNum; - - return resultNum; - } - - - - //*********************************************************************** - // Fast calculation of modular reduction using Barrett's reduction. - // Requires x < b^(2k), where b is the base. In this case, base is - // 2^32 (uint). - // - // Reference [4] - //*********************************************************************** - - private BigInteger BarrettReduction(BigInteger x, BigInteger n, BigInteger constant) - { - int k = n.dataLength, - kPlusOne = k + 1, - kMinusOne = k - 1; - - BigInteger q1 = new BigInteger(); - - // q1 = x / b^(k-1) - for (int i = kMinusOne, j = 0; i < x.dataLength; i++, j++) - q1.data[j] = x.data[i]; - q1.dataLength = x.dataLength - kMinusOne; - if (q1.dataLength <= 0) - q1.dataLength = 1; - - - BigInteger q2 = q1 * constant; - BigInteger q3 = new BigInteger(); - - // q3 = q2 / b^(k+1) - for (int i = kPlusOne, j = 0; i < q2.dataLength; i++, j++) - q3.data[j] = q2.data[i]; - q3.dataLength = q2.dataLength - kPlusOne; - if (q3.dataLength <= 0) - q3.dataLength = 1; - - - // r1 = x mod b^(k+1) - // i.e. keep the lowest (k+1) words - BigInteger r1 = new BigInteger(); - int lengthToCopy = (x.dataLength > kPlusOne) ? kPlusOne : x.dataLength; - for (int i = 0; i < lengthToCopy; i++) - r1.data[i] = x.data[i]; - r1.dataLength = lengthToCopy; - - - // r2 = (q3 * n) mod b^(k+1) - // partial multiplication of q3 and n - - BigInteger r2 = new BigInteger(); - for (int i = 0; i < q3.dataLength; i++) - { - if (q3.data[i] == 0) continue; - - ulong mcarry = 0; - int t = i; - for (int j = 0; j < n.dataLength && t < kPlusOne; j++, t++) - { - // t = i + j - ulong val = ((ulong)q3.data[i] * (ulong)n.data[j]) + - (ulong)r2.data[t] + mcarry; - - r2.data[t] = (uint)(val & 0xFFFFFFFF); - mcarry = (val >> 32); - } - - if (t < kPlusOne) - r2.data[t] = (uint)mcarry; - } - r2.dataLength = kPlusOne; - while (r2.dataLength > 1 && r2.data[r2.dataLength - 1] == 0) - r2.dataLength--; - - r1 -= r2; - if ((r1.data[maxLength - 1] & 0x80000000) != 0) // negative - { - BigInteger val = new BigInteger(); - val.data[kPlusOne] = 0x00000001; - val.dataLength = kPlusOne + 1; - r1 += val; - } - - while (r1 >= n) - r1 -= n; - - return r1; - } - - - //*********************************************************************** - // Returns gcd(this, bi) - //*********************************************************************** - - public BigInteger Gcd(BigInteger bi) - { - BigInteger x; - BigInteger y; - - if ((data[maxLength - 1] & 0x80000000) != 0) // negative - x = -this; - else - x = this; - - if ((bi.data[maxLength - 1] & 0x80000000) != 0) // negative - y = -bi; - else - y = bi; - - BigInteger g = y; - - while (x.dataLength > 1 || (x.dataLength == 1 && x.data[0] != 0)) - { - g = x; - x = y % x; - y = g; - } - - return g; - } - - - //*********************************************************************** - // Populates "this" with the specified amount of random bits - //*********************************************************************** - - public void GenRandomBits(int bits, StrongNumberProvider rand) - { - int dwords = bits >> 5; - int remBits = bits & 0x1F; - - if (remBits != 0) - dwords++; - - if (dwords > maxLength) - throw (new ArithmeticException("Number of required bits > maxLength.")); - - for (int i = 0; i < dwords; i++) - data[i] = (uint)rand.NextUInt32(); - - for (int i = dwords; i < maxLength; i++) - data[i] = 0; - - if (remBits != 0) - { - uint mask = (uint)(0x01 << (remBits - 1)); - data[dwords - 1] |= mask; - - mask = (uint)(0xFFFFFFFF >> (32 - remBits)); - data[dwords - 1] &= mask; - } - else - data[dwords - 1] |= 0x80000000; - - dataLength = dwords; - - if (dataLength == 0) - dataLength = 1; - } - - - //*********************************************************************** - // Returns the position of the most significant bit in the BigInteger. - // - // Eg. The result is 0, if the value of BigInteger is 0...0000 0000 - // The result is 1, if the value of BigInteger is 0...0000 0001 - // The result is 2, if the value of BigInteger is 0...0000 0010 - // The result is 2, if the value of BigInteger is 0...0000 0011 - // - //*********************************************************************** - - public int BitCount() - { - while (dataLength > 1 && data[dataLength - 1] == 0) - dataLength--; - - uint value = data[dataLength - 1]; - uint mask = 0x80000000; - int bits = 32; - - while (bits > 0 && (value & mask) == 0) - { - bits--; - mask >>= 1; - } - bits += ((dataLength - 1) << 5); - - return bits; - } - - - //*********************************************************************** - // Probabilistic prime test based on Fermat's little theorem - // - // for any a < p (p does not divide a) if - // a^(p-1) mod p != 1 then p is not prime. - // - // Otherwise, p is probably prime (pseudoprime to the chosen base). - // - // Returns - // ------- - // True if "this" is a pseudoprime to randomly chosen - // bases. The number of chosen bases is given by the "confidence" - // parameter. - // - // False if "this" is definitely NOT prime. - // - // Note - this method is fast but fails for Carmichael numbers except - // when the randomly chosen base is a factor of the number. - // - //*********************************************************************** - - public bool FermatLittleTest(int confidence) - { - BigInteger thisVal; - if ((this.data[maxLength - 1] & 0x80000000) != 0) // negative - thisVal = -this; - else - thisVal = this; - - if (thisVal.dataLength == 1) - { - // test small numbers - if (thisVal.data[0] == 0 || thisVal.data[0] == 1) - return false; - else if (thisVal.data[0] == 2 || thisVal.data[0] == 3) - return true; - } - - if ((thisVal.data[0] & 0x1) == 0) // even numbers - return false; - - int bits = thisVal.BitCount(); - BigInteger a = new BigInteger(); - BigInteger p_sub1 = thisVal - (new BigInteger(1)); - StrongNumberProvider rand = new StrongNumberProvider(); - - for (int round = 0; round < confidence; round++) - { - bool done = false; - - while (!done) // generate a < n - { - int testBits = 0; - - // make sure "a" has at least 2 bits - while (testBits < 2) - testBits = rand.NextInt() * bits; - - a.GenRandomBits(testBits, rand); - - int byteLen = a.dataLength; - - // make sure "a" is not 0 - if (byteLen > 1 || (byteLen == 1 && a.data[0] != 1)) - done = true; - } - - // check whether a factor exists (fix for version 1.03) - BigInteger gcdTest = a.Gcd(thisVal); - if (gcdTest.dataLength == 1 && gcdTest.data[0] != 1) - return false; - - // calculate a^(p-1) mod p - BigInteger expResult = a.ModPow(p_sub1, thisVal); - - int resultLen = expResult.dataLength; - - // is NOT prime is a^(p-1) mod p != 1 - - if (resultLen > 1 || (resultLen == 1 && expResult.data[0] != 1)) - { - //Console.WriteLine("a = " + a.ToString()); - return false; - } - } - - return true; - } - - - //*********************************************************************** - // Probabilistic prime test based on Rabin-Miller's - // - // for any p > 0 with p - 1 = 2^s * t - // - // p is probably prime (strong pseudoprime) if for any a < p, - // 1) a^t mod p = 1 or - // 2) a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1 - // - // Otherwise, p is composite. - // - // Returns - // ------- - // True if "this" is a strong pseudoprime to randomly chosen - // bases. The number of chosen bases is given by the "confidence" - // parameter. - // - // False if "this" is definitely NOT prime. - // - //*********************************************************************** - - public bool RabinMillerTest(int confidence) - { - BigInteger thisVal; - if ((this.data[maxLength - 1] & 0x80000000) != 0) // negative - thisVal = -this; - else - thisVal = this; - - if (thisVal.dataLength == 1) - { - // test small numbers - if (thisVal.data[0] == 0 || thisVal.data[0] == 1) - return false; - else if (thisVal.data[0] == 2 || thisVal.data[0] == 3) - return true; - } - - if ((thisVal.data[0] & 0x1) == 0) // even numbers - return false; - - - // calculate values of s and t - BigInteger p_sub1 = thisVal - (new BigInteger(1)); - int s = 0; - - for (int index = 0; index < p_sub1.dataLength; index++) - { - uint mask = 0x01; - - for (int i = 0; i < 32; i++) - { - if ((p_sub1.data[index] & mask) != 0) - { - index = p_sub1.dataLength; // to break the outer loop - break; - } - mask <<= 1; - s++; - } - } - - BigInteger t = p_sub1 >> s; - - int bits = thisVal.BitCount(); - BigInteger a = new BigInteger(); - StrongNumberProvider rand = new StrongNumberProvider(); - - for (int round = 0; round < confidence; round++) - { - bool done = false; - - while (!done) // generate a < n - { - int testBits = 0; - - // make sure "a" has at least 2 bits - while (testBits < 2) - testBits = (int)(rand.NextSingle() * bits); - - a.GenRandomBits(testBits, rand); - - int byteLen = a.dataLength; - - // make sure "a" is not 0 - if (byteLen > 1 || (byteLen == 1 && a.data[0] != 1)) - done = true; - } - - // check whether a factor exists (fix for version 1.03) - BigInteger gcdTest = a.Gcd(thisVal); - if (gcdTest.dataLength == 1 && gcdTest.data[0] != 1) - return false; - - BigInteger b = a.ModPow(t, thisVal); - - bool result = false; - - if (b.dataLength == 1 && b.data[0] == 1) // a^t mod p = 1 - result = true; - - for (int j = 0; result == false && j < s; j++) - { - if (b == p_sub1) // a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1 - { - result = true; - break; - } - - b = (b * b) % thisVal; - } - - if (result == false) - return false; - } - return true; - } - - - //*********************************************************************** - // Probabilistic prime test based on Solovay-Strassen (Euler Criterion) - // - // p is probably prime if for any a < p (a is not multiple of p), - // a^((p-1)/2) mod p = J(a, p) - // - // where J is the Jacobi symbol. - // - // Otherwise, p is composite. - // - // Returns - // ------- - // True if "this" is a Euler pseudoprime to randomly chosen - // bases. The number of chosen bases is given by the "confidence" - // parameter. - // - // False if "this" is definitely NOT prime. - // - //*********************************************************************** - - public bool SolovayStrassenTest(int confidence) - { - BigInteger thisVal; - if ((this.data[maxLength - 1] & 0x80000000) != 0) // negative - thisVal = -this; - else - thisVal = this; - - if (thisVal.dataLength == 1) - { - // test small numbers - if (thisVal.data[0] == 0 || thisVal.data[0] == 1) - return false; - else if (thisVal.data[0] == 2 || thisVal.data[0] == 3) - return true; - } - - if ((thisVal.data[0] & 0x1) == 0) // even numbers - return false; - - - int bits = thisVal.BitCount(); - BigInteger a = new BigInteger(); - BigInteger p_sub1 = thisVal - 1; - BigInteger p_sub1_shift = p_sub1 >> 1; - - StrongNumberProvider rand = new StrongNumberProvider(); - - for (int round = 0; round < confidence; round++) - { - bool done = false; - - while (!done) // generate a < n - { - int testBits = 0; - - // make sure "a" has at least 2 bits - while (testBits < 2) - testBits = (int)(rand.NextSingle() * bits); - - a.GenRandomBits(testBits, rand); - - int byteLen = a.dataLength; - - // make sure "a" is not 0 - if (byteLen > 1 || (byteLen == 1 && a.data[0] != 1)) - done = true; - } - - // check whether a factor exists (fix for version 1.03) - BigInteger gcdTest = a.Gcd(thisVal); - if (gcdTest.dataLength == 1 && gcdTest.data[0] != 1) - return false; - - // calculate a^((p-1)/2) mod p - - BigInteger expResult = a.ModPow(p_sub1_shift, thisVal); - if (expResult == p_sub1) - expResult = -1; - - // calculate Jacobi symbol - BigInteger jacob = Jacobi(a, thisVal); - - //Console.WriteLine("a = " + a.ToString(10) + " b = " + thisVal.ToString(10)); - //Console.WriteLine("expResult = " + expResult.ToString(10) + " Jacob = " + jacob.ToString(10)); - - // if they are different then it is not prime - if (expResult != jacob) - return false; - } - - return true; - } - - - //*********************************************************************** - // Implementation of the Lucas Strong Pseudo Prime test. - // - // Let n be an odd number with gcd(n,D) = 1, and n - J(D, n) = 2^s * d - // with d odd and s >= 0. - // - // If Ud mod n = 0 or V2^r*d mod n = 0 for some 0 <= r < s, then n - // is a strong Lucas pseudoprime with parameters (P, Q). We select - // P and Q based on Selfridge. - // - // Returns True if number is a strong Lucus pseudo prime. - // Otherwise, returns False indicating that number is composite. - //*********************************************************************** - - public bool LucasStrongTest() - { - BigInteger thisVal; - if ((this.data[maxLength - 1] & 0x80000000) != 0) // negative - thisVal = -this; - else - thisVal = this; - - if (thisVal.dataLength == 1) - { - // test small numbers - if (thisVal.data[0] == 0 || thisVal.data[0] == 1) - return false; - else if (thisVal.data[0] == 2 || thisVal.data[0] == 3) - return true; - } - - if ((thisVal.data[0] & 0x1) == 0) // even numbers - return false; - - return LucasStrongTestHelper(thisVal); - } - - - private bool LucasStrongTestHelper(BigInteger thisVal) - { - // Do the test (selects D based on Selfridge) - // Let D be the first element of the sequence - // 5, -7, 9, -11, 13, ... for which J(D,n) = -1 - // Let P = 1, Q = (1-D) / 4 - - long D = 5, sign = -1, dCount = 0; - bool done = false; - - while (!done) - { - int Jresult = BigInteger.Jacobi(D, thisVal); - - if (Jresult == -1) - done = true; // J(D, this) = 1 - else - { - if (Jresult == 0 && Math.Abs(D) < thisVal) // divisor found - return false; - - if (dCount == 20) - { - // check for square - BigInteger root = thisVal.Sqrt(); - if (root * root == thisVal) - return false; - } - - //Console.WriteLine(D); - D = (Math.Abs(D) + 2) * sign; - sign = -sign; - } - dCount++; - } - - long Q = (1 - D) >> 2; - - BigInteger p_add1 = thisVal + 1; - int s = 0; - - for (int index = 0; index < p_add1.dataLength; index++) - { - uint mask = 0x01; - - for (int i = 0; i < 32; i++) - { - if ((p_add1.data[index] & mask) != 0) - { - index = p_add1.dataLength; // to break the outer loop - break; - } - mask <<= 1; - s++; - } - } - - BigInteger t = p_add1 >> s; - - // calculate constant = b^(2k) / m - // for Barrett Reduction - BigInteger constant = new BigInteger(); - - int nLen = thisVal.dataLength << 1; - constant.data[nLen] = 0x00000001; - constant.dataLength = nLen + 1; - - constant = constant / thisVal; - - BigInteger[] lucas = LucasSequenceHelper(1, Q, t, thisVal, constant, 0); - bool isPrime = false; - - if ((lucas[0].dataLength == 1 && lucas[0].data[0] == 0) || - (lucas[1].dataLength == 1 && lucas[1].data[0] == 0)) - { - // u(t) = 0 or V(t) = 0 - isPrime = true; - } - - for (int i = 1; i < s; i++) - { - if (!isPrime) - { - // doubling of index - lucas[1] = thisVal.BarrettReduction(lucas[1] * lucas[1], thisVal, constant); - lucas[1] = (lucas[1] - (lucas[2] << 1)) % thisVal; - - //lucas[1] = ((lucas[1] * lucas[1]) - (lucas[2] << 1)) % thisVal; - - if ((lucas[1].dataLength == 1 && lucas[1].data[0] == 0)) - isPrime = true; - } - - lucas[2] = thisVal.BarrettReduction(lucas[2] * lucas[2], thisVal, constant); //Q^k - } - - - if (isPrime) // additional checks for composite numbers - { - // If n is prime and gcd(n, Q) == 1, then - // Q^((n+1)/2) = Q * Q^((n-1)/2) is congruent to (Q * J(Q, n)) mod n - - BigInteger g = thisVal.Gcd(Q); - if (g.dataLength == 1 && g.data[0] == 1) // gcd(this, Q) == 1 - { - if ((lucas[2].data[maxLength - 1] & 0x80000000) != 0) - lucas[2] += thisVal; - - BigInteger temp = (Q * BigInteger.Jacobi(Q, thisVal)) % thisVal; - if ((temp.data[maxLength - 1] & 0x80000000) != 0) - temp += thisVal; - - if (lucas[2] != temp) - isPrime = false; - } - } - - return isPrime; - } - - - //*********************************************************************** - // Determines whether a number is probably prime, using the Rabin-Miller's - // test. Before applying the test, the number is tested for divisibility - // by primes < 2000 - // - // Returns true if number is probably prime. - //*********************************************************************** - - public bool IsProbablePrime(int confidence) - { - BigInteger thisVal; - if ((this.data[maxLength - 1] & 0x80000000) != 0) // negative - thisVal = -this; - else - thisVal = this; - - - // test for divisibility by primes < 2000 - for (int p = 0; p < primesBelow2000.Length; p++) - { - BigInteger divisor = primesBelow2000[p]; - - if (divisor >= thisVal) - break; - - BigInteger resultNum = thisVal % divisor; - if (resultNum.IntValue() == 0) - { - /* - Console.WriteLine("Not prime! Divisible by {0}\n", - primesBelow2000[p]); - */ - return false; - } - } - - if (thisVal.RabinMillerTest(confidence)) - return true; - else - { - //Console.WriteLine("Not prime! Failed primality test\n"); - return false; - } - } - - - //*********************************************************************** - // Determines whether this BigInteger is probably prime using a - // combination of base 2 strong pseudoprime test and Lucas strong - // pseudoprime test. - // - // The sequence of the primality test is as follows, - // - // 1) Trial divisions are carried out using prime numbers below 2000. - // if any of the primes divides this BigInteger, then it is not prime. - // - // 2) Perform base 2 strong pseudoprime test. If this BigInteger is a - // base 2 strong pseudoprime, proceed on to the next step. - // - // 3) Perform strong Lucas pseudoprime test. - // - // Returns True if this BigInteger is both a base 2 strong pseudoprime - // and a strong Lucas pseudoprime. - // - // For a detailed discussion of this primality test, see [6]. - // - //*********************************************************************** - - public bool IsProbablePrime() - { - BigInteger thisVal; - if ((this.data[maxLength - 1] & 0x80000000) != 0) // negative - thisVal = -this; - else - thisVal = this; - - if (thisVal.dataLength == 1) - { - // test small numbers - if (thisVal.data[0] == 0 || thisVal.data[0] == 1) - return false; - else if (thisVal.data[0] == 2 || thisVal.data[0] == 3) - return true; - } - - if ((thisVal.data[0] & 0x1) == 0) // even numbers - return false; - - - // test for divisibility by primes < 2000 - for (int p = 0; p < primesBelow2000.Length; p++) - { - BigInteger divisor = primesBelow2000[p]; - - if (divisor >= thisVal) - break; - - BigInteger resultNum = thisVal % divisor; - if (resultNum.IntValue() == 0) - { - //Console.WriteLine("Not prime! Divisible by {0}\n", - // primesBelow2000[p]); - - return false; - } - } - - // Perform BASE 2 Rabin-Miller Test - - // calculate values of s and t - BigInteger p_sub1 = thisVal - (new BigInteger(1)); - int s = 0; - - for (int index = 0; index < p_sub1.dataLength; index++) - { - uint mask = 0x01; - - for (int i = 0; i < 32; i++) - { - if ((p_sub1.data[index] & mask) != 0) - { - index = p_sub1.dataLength; // to break the outer loop - break; - } - mask <<= 1; - s++; - } - } - - BigInteger t = p_sub1 >> s; - - int bits = thisVal.BitCount(); - BigInteger a = 2; - - // b = a^t mod p - BigInteger b = a.ModPow(t, thisVal); - bool result = false; - - if (b.dataLength == 1 && b.data[0] == 1) // a^t mod p = 1 - result = true; - - for (int j = 0; result == false && j < s; j++) - { - if (b == p_sub1) // a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1 - { - result = true; - break; - } - - b = (b * b) % thisVal; - } - - // if number is strong pseudoprime to base 2, then do a strong lucas test - if (result) - result = LucasStrongTestHelper(thisVal); - - return result; - } - - - - //*********************************************************************** - // Returns the lowest 4 bytes of the BigInteger as an int. - //*********************************************************************** - - public int IntValue() - { - return (int)data[0]; - } - - - //*********************************************************************** - // Returns the lowest 8 bytes of the BigInteger as a long. - //*********************************************************************** - - public long LongValue() - { - long val = 0; - - val = (long)data[0]; - try - { // exception if maxLength = 1 - val |= (long)data[1] << 32; - } - catch (Exception) - { - if ((data[0] & 0x80000000) != 0) // negative - val = (int)data[0]; - } - - return val; - } - - - //*********************************************************************** - // Computes the Jacobi Symbol for a and b. - // Algorithm adapted from [3] and [4] with some optimizations - //*********************************************************************** - - public static int Jacobi(BigInteger a, BigInteger b) - { - // Jacobi defined only for odd integers - if ((b.data[0] & 0x1) == 0) - throw (new ArgumentException("Jacobi defined only for odd integers.")); - - if (a >= b) a %= b; - if (a.dataLength == 1 && a.data[0] == 0) return 0; // a == 0 - if (a.dataLength == 1 && a.data[0] == 1) return 1; // a == 1 - - if (a < 0) - { - if ((((b - 1).data[0]) & 0x2) == 0) //if( (((b-1) >> 1).data[0] & 0x1) == 0) - return Jacobi(-a, b); - else - return -Jacobi(-a, b); - } - - int e = 0; - for (int index = 0; index < a.dataLength; index++) - { - uint mask = 0x01; - - for (int i = 0; i < 32; i++) - { - if ((a.data[index] & mask) != 0) - { - index = a.dataLength; // to break the outer loop - break; - } - mask <<= 1; - e++; - } - } - - BigInteger a1 = a >> e; - - int s = 1; - if ((e & 0x1) != 0 && ((b.data[0] & 0x7) == 3 || (b.data[0] & 0x7) == 5)) - s = -1; - - if ((b.data[0] & 0x3) == 3 && (a1.data[0] & 0x3) == 3) - s = -s; - - if (a1.dataLength == 1 && a1.data[0] == 1) - return s; - else - return (s * Jacobi(b % a1, a1)); - } - - - - //*********************************************************************** - // Generates a positive BigInteger that is probably prime. - //*********************************************************************** - - public static BigInteger GenPseudoPrime(int bits, int confidence, StrongNumberProvider rand) - { - BigInteger result = new BigInteger(); - bool done = false; - - while (!done) - { - result.GenRandomBits(bits, rand); - result.data[0] |= 0x01; // make it odd - - // prime test - done = result.IsProbablePrime(confidence); - } - return result; - } - - - //*********************************************************************** - // Generates a random number with the specified number of bits such - // that gcd(number, this) = 1 - //*********************************************************************** - - public BigInteger GenCoPrime(int bits, StrongNumberProvider rand) - { - bool done = false; - BigInteger result = new BigInteger(); - - while (!done) - { - result.GenRandomBits(bits, rand); - //Console.WriteLine(result.ToString(16)); - - // gcd test - BigInteger g = result.Gcd(this); - if (g.dataLength == 1 && g.data[0] == 1) - done = true; - } - - return result; - } - - - //*********************************************************************** - // Returns the modulo inverse of this. Throws ArithmeticException if - // the inverse does not exist. (i.e. gcd(this, modulus) != 1) - //*********************************************************************** - - public BigInteger ModInverse(BigInteger modulus) - { - BigInteger[] p = { 0, 1 }; - BigInteger[] q = new BigInteger[2]; // quotients - BigInteger[] r = { 0, 0 }; // remainders - - int step = 0; - - BigInteger a = modulus; - BigInteger b = this; - - while (b.dataLength > 1 || (b.dataLength == 1 && b.data[0] != 0)) - { - BigInteger quotient = new BigInteger(); - BigInteger remainder = new BigInteger(); - - if (step > 1) - { - BigInteger pval = (p[0] - (p[1] * q[0])) % modulus; - p[0] = p[1]; - p[1] = pval; - } - - if (b.dataLength == 1) - SingleByteDivide(a, b, quotient, remainder); - else - MultiByteDivide(a, b, quotient, remainder); - - /* - Console.WriteLine(quotient.dataLength); - Console.WriteLine("{0} = {1}({2}) + {3} p = {4}", a.ToString(10), - b.ToString(10), quotient.ToString(10), remainder.ToString(10), - p[1].ToString(10)); - */ - - q[0] = q[1]; - r[0] = r[1]; - q[1] = quotient; r[1] = remainder; - - a = b; - b = remainder; - - step++; - } - - if (r[0].dataLength > 1 || (r[0].dataLength == 1 && r[0].data[0] != 1)) - throw (new ArithmeticException("No inverse!")); - - BigInteger result = ((p[0] - (p[1] * q[0])) % modulus); - - if ((result.data[maxLength - 1] & 0x80000000) != 0) - result += modulus; // get the least positive modulus - - return result; - } - - - //*********************************************************************** - // Returns the value of the BigInteger as a byte array. The lowest - // index contains the MSB. - //*********************************************************************** - - public byte[] GetBytes() - { - int numBits = BitCount(); - - int numBytes = numBits >> 3; - if ((numBits & 0x7) != 0) - numBytes++; - - byte[] result = new byte[numBytes]; - - //Console.WriteLine(result.Length); - - int pos = 0; - uint tempVal, val = data[dataLength - 1]; - - if ((tempVal = (val >> 24 & 0xFF)) != 0) - result[pos++] = (byte)tempVal; - if ((tempVal = (val >> 16 & 0xFF)) != 0) - result[pos++] = (byte)tempVal; - if ((tempVal = (val >> 8 & 0xFF)) != 0) - result[pos++] = (byte)tempVal; - if ((tempVal = (val & 0xFF)) != 0) - result[pos++] = (byte)tempVal; - - for (int i = dataLength - 2; i >= 0; i--, pos += 4) - { - val = data[i]; - result[pos + 3] = (byte)(val & 0xFF); - val >>= 8; - result[pos + 2] = (byte)(val & 0xFF); - val >>= 8; - result[pos + 1] = (byte)(val & 0xFF); - val >>= 8; - result[pos] = (byte)(val & 0xFF); - } - - return result; - } - - - //*********************************************************************** - // Sets the value of the specified bit to 1 - // The Least Significant Bit position is 0. - //*********************************************************************** - - public void SetBit(uint bitNum) - { - uint bytePos = bitNum >> 5; // divide by 32 - byte bitPos = (byte)(bitNum & 0x1F); // get the lowest 5 bits - - uint mask = (uint)1 << bitPos; - this.data[bytePos] |= mask; - - if (bytePos >= this.dataLength) - this.dataLength = (int)bytePos + 1; - } - - - //*********************************************************************** - // Sets the value of the specified bit to 0 - // The Least Significant Bit position is 0. - //*********************************************************************** - - public void UnsetBit(uint bitNum) - { - uint bytePos = bitNum >> 5; - - if (bytePos < this.dataLength) - { - byte bitPos = (byte)(bitNum & 0x1F); - - uint mask = (uint)1 << bitPos; - uint mask2 = 0xFFFFFFFF ^ mask; - - this.data[bytePos] &= mask2; - - if (this.dataLength > 1 && this.data[this.dataLength - 1] == 0) - this.dataLength--; - } - } - - - //*********************************************************************** - // Returns a value that is equivalent to the integer square root - // of the BigInteger. - // - // The integer square root of "this" is defined as the largest integer n - // such that (n * n) <= this - // - //*********************************************************************** - - public BigInteger Sqrt() - { - uint numBits = (uint)this.BitCount(); - - if ((numBits & 0x1) != 0) // odd number of bits - numBits = (numBits >> 1) + 1; - else - numBits = (numBits >> 1); - - uint bytePos = numBits >> 5; - byte bitPos = (byte)(numBits & 0x1F); - - uint mask; - - BigInteger result = new BigInteger(); - if (bitPos == 0) - mask = 0x80000000; - else - { - mask = (uint)1 << bitPos; - bytePos++; - } - result.dataLength = (int)bytePos; - - for (int i = (int)bytePos - 1; i >= 0; i--) - { - while (mask != 0) - { - // guess - result.data[i] ^= mask; - - // undo the guess if its square is larger than this - if ((result * result) > this) - result.data[i] ^= mask; - - mask >>= 1; - } - mask = 0x80000000; - } - return result; - } - - - //*********************************************************************** - // Returns the k_th number in the Lucas Sequence reduced modulo n. - // - // Uses index doubling to speed up the process. For example, to calculate V(k), - // we maintain two numbers in the sequence V(n) and V(n+1). - // - // To obtain V(2n), we use the identity - // V(2n) = (V(n) * V(n)) - (2 * Q^n) - // To obtain V(2n+1), we first write it as - // V(2n+1) = V((n+1) + n) - // and use the identity - // V(m+n) = V(m) * V(n) - Q * V(m-n) - // Hence, - // V((n+1) + n) = V(n+1) * V(n) - Q^n * V((n+1) - n) - // = V(n+1) * V(n) - Q^n * V(1) - // = V(n+1) * V(n) - Q^n * P - // - // We use k in its binary expansion and perform index doubling for each - // bit position. For each bit position that is set, we perform an - // index doubling followed by an index addition. This means that for V(n), - // we need to update it to V(2n+1). For V(n+1), we need to update it to - // V((2n+1)+1) = V(2*(n+1)) - // - // This function returns - // [0] = U(k) - // [1] = V(k) - // [2] = Q^n - // - // Where U(0) = 0 % n, U(1) = 1 % n - // V(0) = 2 % n, V(1) = P % n - //*********************************************************************** - - public static BigInteger[] LucasSequence(BigInteger P, BigInteger Q, - BigInteger k, BigInteger n) - { - if (k.dataLength == 1 && k.data[0] == 0) - { - BigInteger[] result = new BigInteger[3]; - - result[0] = 0; result[1] = 2 % n; result[2] = 1 % n; - return result; - } - - // calculate constant = b^(2k) / m - // for Barrett Reduction - BigInteger constant = new BigInteger(); - - int nLen = n.dataLength << 1; - constant.data[nLen] = 0x00000001; - constant.dataLength = nLen + 1; - - constant = constant / n; - - // calculate values of s and t - int s = 0; - - for (int index = 0; index < k.dataLength; index++) - { - uint mask = 0x01; - - for (int i = 0; i < 32; i++) - { - if ((k.data[index] & mask) != 0) - { - index = k.dataLength; // to break the outer loop - break; - } - mask <<= 1; - s++; - } - } - - BigInteger t = k >> s; - - //Console.WriteLine("s = " + s + " t = " + t); - return LucasSequenceHelper(P, Q, t, n, constant, s); - } - - - //*********************************************************************** - // Performs the calculation of the kth term in the Lucas Sequence. - // For details of the algorithm, see reference [9]. - // - // k must be odd. i.e LSB == 1 - //*********************************************************************** - - private static BigInteger[] LucasSequenceHelper(BigInteger P, BigInteger Q, - BigInteger k, BigInteger n, - BigInteger constant, int s) - { - BigInteger[] result = new BigInteger[3]; - - if ((k.data[0] & 0x00000001) == 0) - throw (new ArgumentException("Argument k must be odd.")); - - int numbits = k.BitCount(); - uint mask = (uint)0x1 << ((numbits & 0x1F) - 1); - - // v = v0, v1 = v1, u1 = u1, Q_k = Q^0 - - BigInteger v = 2 % n, Q_k = 1 % n, - v1 = P % n, u1 = Q_k; - bool flag = true; - - for (int i = k.dataLength - 1; i >= 0; i--) // iterate on the binary expansion of k - { - //Console.WriteLine("round"); - while (mask != 0) - { - if (i == 0 && mask == 0x00000001) // last bit - break; - - if ((k.data[i] & mask) != 0) // bit is set - { - // index doubling with addition - - u1 = (u1 * v1) % n; - - v = ((v * v1) - (P * Q_k)) % n; - v1 = n.BarrettReduction(v1 * v1, n, constant); - v1 = (v1 - ((Q_k * Q) << 1)) % n; - - if (flag) - flag = false; - else - Q_k = n.BarrettReduction(Q_k * Q_k, n, constant); - - Q_k = (Q_k * Q) % n; - } - else - { - // index doubling - u1 = ((u1 * v) - Q_k) % n; - - v1 = ((v * v1) - (P * Q_k)) % n; - v = n.BarrettReduction(v * v, n, constant); - v = (v - (Q_k << 1)) % n; - - if (flag) - { - Q_k = Q % n; - flag = false; - } - else - Q_k = n.BarrettReduction(Q_k * Q_k, n, constant); - } - - mask >>= 1; - } - mask = 0x80000000; - } - - // at this point u1 = u(n+1) and v = v(n) - // since the last bit always 1, we need to transform u1 to u(2n+1) and v to v(2n+1) - - u1 = ((u1 * v) - Q_k) % n; - v = ((v * v1) - (P * Q_k)) % n; - if (flag) - flag = false; - else - Q_k = n.BarrettReduction(Q_k * Q_k, n, constant); - - Q_k = (Q_k * Q) % n; - - - for (int i = 0; i < s; i++) - { - // index doubling - u1 = (u1 * v) % n; - v = ((v * v) - (Q_k << 1)) % n; - - if (flag) - { - Q_k = Q % n; - flag = false; - } - else - Q_k = n.BarrettReduction(Q_k * Q_k, n, constant); - } - - result[0] = u1; - result[1] = v; - result[2] = Q_k; - - return result; - } - - #region IDisposable Members - - public void Dispose() - { - data = new uint[0]; - data = null; - } - - #endregion - } -} diff --git a/ClientServerLib/ClientServerLib/DeffieHellman/DeffieHellman.cs b/ClientServerLib/ClientServerLib/DeffieHellman/DeffieHellman.cs deleted file mode 100644 index fd8543fb..00000000 --- a/ClientServerLib/ClientServerLib/DeffieHellman/DeffieHellman.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Security.Cryptography; - -namespace DiffieHellman -{ - /// - /// Represents the Diffie-Hellman algorithm. - /// - public class CDiffieHellman : IDisposable - { - #region - Util - - static StrongNumberProvider _strongRng = new StrongNumberProvider(); - #endregion - - #region - Fields - - /// - /// The number of bits to generate. - /// - private int bits = 256; - - /// - /// The shared prime. - /// - BigInteger prime; - /// - /// The shared base. - /// - BigInteger g; - /// - /// The private prime. - /// - BigInteger mine; - - /// - /// The final key. - /// - byte[] key; - /// - /// The string representation/packet. - /// - string representation; - #endregion - - #region - Properties - - /// - /// Gets the final key to use for encryption. - /// - public byte[] Key - { - get { return key; } - } - #endregion - - #region - Ctor - - public CDiffieHellman() - { - } - - public CDiffieHellman(int bits) - { - this.bits = bits; - } - - ~CDiffieHellman() - { - Dispose(); - } - #endregion - - #region - Implementation Methods - - #region Flow - /// - /// Generates a request packet. - /// - /// - public CDiffieHellman GenerateRequest() - { - // Generate the parameters. - prime = BigInteger.GenPseudoPrime(bits, 30, _strongRng); - mine = BigInteger.GenPseudoPrime(bits, 30, _strongRng); - g = (BigInteger)5; - - // Gemerate the string. - StringBuilder rep = new StringBuilder(); - rep.Append(prime.ToString(36)); - rep.Append("|"); - rep.Append(g.ToString(36)); - rep.Append("|"); - - // Generate the send BigInt. - using (BigInteger send = g.ModPow(mine, prime)) - { - rep.Append(send.ToString(36)); - } - - representation = rep.ToString(); - return this; - } - - /// - /// Generate a response packet. - /// - /// The string representation of the request. - /// - public CDiffieHellman GenerateResponse(string request) - { - string[] parts = request.Split('|'); - - // Generate the would-be fields. - using (BigInteger prime = new BigInteger(parts[0], 36)) - using (BigInteger g = new BigInteger(parts[1], 36)) - using (BigInteger mine = BigInteger.GenPseudoPrime(bits, 30, _strongRng)) - { - // Generate the key. - using (BigInteger given = new BigInteger(parts[2], 36)) - using (BigInteger key = given.ModPow(mine, prime)) - { - this.key = key.GetBytes(); - } - - // Generate the response. - using (BigInteger send = g.ModPow(mine, prime)) - { - this.representation = send.ToString(36); - } - } - - return this; - } - - /// - /// Generates the key after a response is received. - /// - /// The string representation of the response. - public void HandleResponse(string response) - { - // Get the response and modpow it with the stored prime. - using (BigInteger given = new BigInteger(response, 36)) - using (BigInteger key = given.ModPow(mine, prime)) - { - this.key = key.GetBytes(); - } - Dispose(); - } - #endregion - - public override string ToString() - { - return representation; - } - #endregion - - #region IDisposable Members - /// - /// Ends the calculation. The key will still be available. - /// - public void Dispose() - { - if (!Object.ReferenceEquals(prime, null)) - prime.Dispose(); - if (!Object.ReferenceEquals(mine, null)) - mine.Dispose(); - if (!Object.ReferenceEquals(g, null)) - g.Dispose(); - - prime = null; - mine = null; - g = null; - - representation = null; - GC.Collect(); - GC.Collect(); - } - - #endregion - } -} diff --git a/ClientServerLib/ClientServerLib/DeffieHellman/StrongNumberProvider.cs b/ClientServerLib/ClientServerLib/DeffieHellman/StrongNumberProvider.cs deleted file mode 100644 index 720a1414..00000000 --- a/ClientServerLib/ClientServerLib/DeffieHellman/StrongNumberProvider.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Security.Cryptography; - -namespace DiffieHellman -{ - internal class StrongNumberProvider - { - private static RNGCryptoServiceProvider csp = new RNGCryptoServiceProvider(); - - public uint NextUInt32() - { - byte[] res = new byte[4]; - csp.GetBytes(res); - return BitConverter.ToUInt32(res, 0); - } - - public int NextInt() - { - byte[] res = new byte[4]; - csp.GetBytes(res); - return BitConverter.ToInt32(res, 0); - } - - public Single NextSingle() - { - float numerator = NextUInt32(); - float denominator = uint.MaxValue; - return numerator / denominator; - } - } -} diff --git a/ClientServerLib/ClientServerLib/ICWebservice.cs b/ClientServerLib/ClientServerLib/ICWebservice.cs new file mode 100644 index 00000000..3e79d8ce --- /dev/null +++ b/ClientServerLib/ClientServerLib/ICWebservice.cs @@ -0,0 +1,214 @@ +using System; +using System.IO; +using System.ServiceModel; +using System.ServiceModel.Web; + +namespace ServerLib +{ + [ServiceContract] + public interface ICWebservice + { + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/sendKeyEvent?key={key}")] + void SendKeyEvent(string key); + + #region profile + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/getOwnProfileId")] + int GetOwnProfileId(); + + [OperationContract] + [WebInvoke(Method = "POST", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/sendProfile")] + void SendProfile(SProfileData profile); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/getProfile?profileId={profileId}")] + SProfileData GetProfile(int profileId); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/getProfileList")] + SProfileData[] GetProfileList(); + + #endregion + + #region photo + + [OperationContract] + [WebInvoke(Method = "POST", + RequestFormat = WebMessageFormat.Json, + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/sendPhoto")] + void SendPhoto(SPhotoData photo); + + #endregion + + #region website + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/login?username={username}&password={password}")] + Guid Login(string username, string password); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "")] + Stream Index(); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/js/{filename}")] + Stream GetJsFile(String filename); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/css/{filename}")] + Stream GetCssFile(String filename); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/css/images/{filename}")] + Stream GetCssImageFile(String filename); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/img/{filename}")] + Stream GetImgFile(String filename); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/locales/{filename}")] + Stream GetLocaleFile(String filename); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/delayedImage?id={id}")] + CBase64Image GetDelayedImage(String id); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/isServerOnline")] + bool IsServerOnline(); + + #endregion + + #region songs + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/getSong?songId={songId}")] + SSongInfo GetSong(int songId); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/getCurrentSongId")] + int GetCurrentSongId(); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/getAllSongs")] + SSongInfo[] GetAllSongs(); + + #endregion + + #region playlist + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/getPlaylists")] + SPlaylistInfo[] GetPlaylists(); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/getPlaylist?id={playlistId}")] + SPlaylistInfo GetPlaylist(int playlistId); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/addSongToPlaylist?songId={songId}&playlistId={playlistId}&duplicates={allowDuplicates}")] + void AddSongToPlaylist(int songId, int playlistId, bool allowDuplicates); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/removeSongFromPlaylist?position={position}&playlistId={playlistId}&songId={songId}")] + void RemoveSongFromPlaylist(int position, int playlistId, int songId); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/moveSongInPlaylist?newPosition={newPosition}&playlistId={playlistId}&songId={songId}")] + void MoveSongInPlaylist(int newPosition, int playlistId, int songId); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/playlistContainsSong?songId={songId}&playlistId={playlistId}")] + bool PlaylistContainsSong(int songId, int playlistId); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/getPlaylistSongs?playlistId={playlistId}")] + SPlaylistSongInfo[] GetPlaylistSongs(int playlistId); + + [OperationContract, WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/removePlaylist?playlistId={playlistId}")] + void RemovePlaylist(int playlistId); + + [OperationContract, WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/addPlaylist?playlistName={playlistName}")] + int AddPlaylist(string playlistName); + + #endregion + + #region user management + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/getUserRole?profileId={profileId}")] + int GetUserRole(int profileId); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/setUserRole?profileId={profileId}&userRole={userRole}")] + void SetUserRole(int profileId, int userRole); + + [OperationContract] + [WebInvoke(Method = "GET", + ResponseFormat = WebMessageFormat.Json, + UriTemplate = "/hasUserRight?right={right}")] + bool HasUserRight(int right); + + #endregion + } +} \ No newline at end of file diff --git a/ClientServerLib/ClientServerLib/ClientServerLib.csproj b/ClientServerLib/ClientServerLib/ServerLib.csproj similarity index 74% rename from ClientServerLib/ClientServerLib/ClientServerLib.csproj rename to ClientServerLib/ClientServerLib/ServerLib.csproj index 8b4826b3..3a00f689 100644 --- a/ClientServerLib/ClientServerLib/ClientServerLib.csproj +++ b/ClientServerLib/ClientServerLib/ServerLib.csproj @@ -8,17 +8,19 @@ {EC5167E4-CCFB-4CEE-987C-CF816F1062A3} Library Properties - ClientServerLib + ServerLib ClientServerLib v4.0 512 + + true full false bin\ - DEBUG;TRACE + TRACE;DEBUG;WIN; prompt 4 @@ -33,6 +35,11 @@ + + + + + @@ -40,15 +47,17 @@ - - - - - + + + - + + + + + + \ No newline at end of file diff --git a/ConfigHttpApi/HttpApi.cs b/ConfigHttpApi/HttpApi.cs new file mode 100644 index 00000000..e5d104a0 --- /dev/null +++ b/ConfigHttpApi/HttpApi.cs @@ -0,0 +1,643 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; + +namespace ConfigHttpApi +{ + internal static class HttpApi + { + private static readonly HTTPAPI_VERSION HttpApiVersion = new HTTPAPI_VERSION(1, 0); + + #region DllImport + + [DllImport("httpapi.dll", SetLastError = true)] + static extern uint HttpInitialize( + HTTPAPI_VERSION version, + uint flags, + IntPtr pReserved); + + [DllImport("httpapi.dll", SetLastError = true)] + static extern uint HttpSetServiceConfiguration( + IntPtr serviceIntPtr, + HTTP_SERVICE_CONFIG_ID configId, + IntPtr pConfigInformation, + int configInformationLength, + IntPtr pOverlapped); + + [DllImport("httpapi.dll", SetLastError = true)] + static extern uint HttpDeleteServiceConfiguration( + IntPtr serviceIntPtr, + HTTP_SERVICE_CONFIG_ID configId, + IntPtr pConfigInformation, + int configInformationLength, + IntPtr pOverlapped); + + [DllImport("httpapi.dll", SetLastError = true)] + static extern uint HttpTerminate( + uint Flags, + IntPtr pReserved); + + [DllImport("httpapi.dll", SetLastError = true)] + static extern uint HttpQueryServiceConfiguration( + IntPtr serviceIntPtr, + HTTP_SERVICE_CONFIG_ID configId, + IntPtr pInputConfigInfo, + int inputConfigInfoLength, + IntPtr pOutputConfigInfo, + int outputConfigInfoLength, + [Optional] + out int pReturnLength, + IntPtr pOverlapped); + + + enum HTTP_SERVICE_CONFIG_ID + { + + HttpServiceConfigIPListenList = 0, + HttpServiceConfigSSLCertInfo, + HttpServiceConfigUrlAclInfo, + HttpServiceConfigMax + } + + [StructLayout(LayoutKind.Sequential)] + struct HTTP_SERVICE_CONFIG_SSL_SET + { + public HTTP_SERVICE_CONFIG_SSL_KEY KeyDesc; + public HTTP_SERVICE_CONFIG_SSL_PARAM ParamDesc; + } + + [StructLayout(LayoutKind.Sequential)] + struct HTTP_SERVICE_CONFIG_SSL_KEY + { + public IntPtr pIpPort; + + public HTTP_SERVICE_CONFIG_SSL_KEY(IntPtr pIpPort) + { + this.pIpPort = pIpPort; + } + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + struct HTTP_SERVICE_CONFIG_SSL_PARAM + { + public int SslHashLength; + public IntPtr pSslHash; + public Guid AppId; + [MarshalAs(UnmanagedType.LPWStr)] + public string pSslCertStoreName; + public uint DefaultCertCheckMode; + public int DefaultRevocationFreshnessTime; + public int DefaultRevocationUrlRetrievalTimeout; + [MarshalAs(UnmanagedType.LPWStr)] + public string pDefaultSslCtlIdentifier; + [MarshalAs(UnmanagedType.LPWStr)] + public string pDefaultSslCtlStoreName; + public uint DefaultFlags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + struct HTTPAPI_VERSION + { + public ushort HttpApiMajorVersion; + public ushort HttpApiMinorVersion; + + public HTTPAPI_VERSION(ushort majorVersion, ushort minorVersion) + { + HttpApiMajorVersion = majorVersion; + HttpApiMinorVersion = minorVersion; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct HTTP_SERVICE_CONFIG_SSL_QUERY + { + public HTTP_SERVICE_CONFIG_QUERY_TYPE QueryDesc; + public HTTP_SERVICE_CONFIG_SSL_KEY KeyDesc; + public uint dwToken; + } + + enum HTTP_SERVICE_CONFIG_QUERY_TYPE + { + HttpServiceConfigQueryExact = 0, + HttpServiceConfigQueryNext, + HttpServiceConfigQueryMax + } + + [StructLayout(LayoutKind.Sequential)] + struct HTTP_SERVICE_CONFIG_URLACL_SET + { + public HTTP_SERVICE_CONFIG_URLACL_KEY KeyDesc; + public HTTP_SERVICE_CONFIG_URLACL_PARAM ParamDesc; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct HTTP_SERVICE_CONFIG_URLACL_KEY + { + [MarshalAs(UnmanagedType.LPWStr)] + public string pUrlPrefix; + + public HTTP_SERVICE_CONFIG_URLACL_KEY(string urlPrefix) + { + pUrlPrefix = urlPrefix; + } + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + struct HTTP_SERVICE_CONFIG_URLACL_PARAM + { + [MarshalAs(UnmanagedType.LPWStr)] + public string pStringSecurityDescriptor; + + public HTTP_SERVICE_CONFIG_URLACL_PARAM(string securityDescriptor) + { + pStringSecurityDescriptor = securityDescriptor; + } + } + + #endregion + + #region Constants + + public const uint HTTP_INITIALIZE_CONFIG = 0x00000002; + public const uint HTTP_SERVICE_CONFIG_SSL_FLAG_NEGOTIATE_CLIENT_CERT = 0x00000002; + public const uint HTTP_SERVICE_CONFIG_SSL_FLAG_NO_RAW_FILTER = 0x00000004; + private const uint NOERROR = 0; + private const uint ERROR_INSUFFICIENT_BUFFER = 122; + private const uint ERROR_ALREADY_EXISTS = 183; + private const uint ERROR_FILE_NOT_FOUND = 2; + private const int ERROR_NO_MORE_ITEMS = 259; + + #endregion + + #region Public methods + + public class SslCertificateInfo + { + public byte[] Hash { get; set; } + public Guid AppId { get; set; } + public string StoreName { get; set; } + public IPEndPoint IpPort { get; set; } + } + + public static SslCertificateInfo QuerySslCertificateInfo(IPEndPoint ipPort) + { + SslCertificateInfo result = null; + + uint retVal; + CallHttpApi(delegate + { + GCHandle sockAddrHandle = CreateSockaddrStructure(ipPort); + IntPtr pIpPort = sockAddrHandle.AddrOfPinnedObject(); + HTTP_SERVICE_CONFIG_SSL_KEY sslKey = new HTTP_SERVICE_CONFIG_SSL_KEY(pIpPort); + + HTTP_SERVICE_CONFIG_SSL_QUERY inputConfigInfoQuery = + new HTTP_SERVICE_CONFIG_SSL_QUERY + { + QueryDesc = HTTP_SERVICE_CONFIG_QUERY_TYPE.HttpServiceConfigQueryExact, + KeyDesc = sslKey + }; + + IntPtr pInputConfigInfo = + Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_QUERY))); + Marshal.StructureToPtr(inputConfigInfoQuery, pInputConfigInfo, false); + + IntPtr pOutputConfigInfo = IntPtr.Zero; + int returnLength = 0; + + try + { + HTTP_SERVICE_CONFIG_ID queryType = HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo; + int inputConfigInfoSize = Marshal.SizeOf(inputConfigInfoQuery); + retVal = HttpQueryServiceConfiguration(IntPtr.Zero, + queryType, + pInputConfigInfo, + inputConfigInfoSize, + pOutputConfigInfo, + returnLength, + out returnLength, + IntPtr.Zero); + if (retVal == ERROR_FILE_NOT_FOUND) + return; + + if (ERROR_INSUFFICIENT_BUFFER == retVal) // ERROR_INSUFFICIENT_BUFFER = 122 + { + pOutputConfigInfo = Marshal.AllocCoTaskMem(returnLength); + + try + { + retVal = HttpQueryServiceConfiguration(IntPtr.Zero, + queryType, + pInputConfigInfo, + inputConfigInfoSize, + pOutputConfigInfo, + returnLength, + out returnLength, + IntPtr.Zero); + ThrowWin32ExceptionIfError(retVal); + + var outputConfigInfo = + (HTTP_SERVICE_CONFIG_SSL_SET) + Marshal.PtrToStructure(pOutputConfigInfo, typeof(HTTP_SERVICE_CONFIG_SSL_SET)); + + byte[] hash = new byte[outputConfigInfo.ParamDesc.SslHashLength]; + Marshal.Copy(outputConfigInfo.ParamDesc.pSslHash, hash, 0, hash.Length); + + Guid appId = outputConfigInfo.ParamDesc.AppId; + string storeName = outputConfigInfo.ParamDesc.pSslCertStoreName; + + result = new SslCertificateInfo { AppId = appId, Hash = hash, StoreName = storeName, IpPort = ipPort }; + } + finally + { + Marshal.FreeCoTaskMem(pOutputConfigInfo); + } + } + else + { + ThrowWin32ExceptionIfError(retVal); + } + + } + finally + { + Marshal.FreeCoTaskMem(pInputConfigInfo); + if (sockAddrHandle.IsAllocated) + sockAddrHandle.Free(); + } + + }); + + return result; + } + + public static void BindCertificate(IPEndPoint ipPort, byte[] hash, StoreName storeName, Guid appId) + { + if (ipPort == null) throw new ArgumentNullException("ipPort"); + if (hash == null) throw new ArgumentNullException("hash"); + + CallHttpApi( + delegate + { + HTTP_SERVICE_CONFIG_SSL_SET configSslSet = new HTTP_SERVICE_CONFIG_SSL_SET(); + + GCHandle sockAddrHandle = CreateSockaddrStructure(ipPort); + IntPtr pIpPort = sockAddrHandle.AddrOfPinnedObject(); + HTTP_SERVICE_CONFIG_SSL_KEY httpServiceConfigSslKey = + new HTTP_SERVICE_CONFIG_SSL_KEY(pIpPort); + HTTP_SERVICE_CONFIG_SSL_PARAM configSslParam = new HTTP_SERVICE_CONFIG_SSL_PARAM(); + + + GCHandle handleHash = GCHandle.Alloc(hash, GCHandleType.Pinned); + configSslParam.AppId = appId; + configSslParam.DefaultCertCheckMode = 0; + configSslParam.DefaultFlags = 0; //HTTP_SERVICE_CONFIG_SSL_FLAG_NEGOTIATE_CLIENT_CERT; + configSslParam.DefaultRevocationFreshnessTime = 0; + configSslParam.DefaultRevocationUrlRetrievalTimeout = 0; + configSslParam.pSslCertStoreName = storeName.ToString(); + configSslParam.pSslHash = handleHash.AddrOfPinnedObject(); + configSslParam.SslHashLength = hash.Length; + configSslSet.ParamDesc = configSslParam; + configSslSet.KeyDesc = httpServiceConfigSslKey; + + IntPtr pInputConfigInfo = + Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_SET))); + Marshal.StructureToPtr(configSslSet, pInputConfigInfo, false); + + try + { + uint retVal = HttpSetServiceConfiguration(IntPtr.Zero, + HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo, + pInputConfigInfo, + Marshal.SizeOf(configSslSet), + IntPtr.Zero); + + if (ERROR_ALREADY_EXISTS != retVal) + { + ThrowWin32ExceptionIfError(retVal); + } + else + { + retVal = HttpDeleteServiceConfiguration(IntPtr.Zero, + HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo, + pInputConfigInfo, + Marshal.SizeOf(configSslSet), + IntPtr.Zero); + ThrowWin32ExceptionIfError(retVal); + + retVal = HttpSetServiceConfiguration(IntPtr.Zero, + HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo, + pInputConfigInfo, + Marshal.SizeOf(configSslSet), + IntPtr.Zero); + ThrowWin32ExceptionIfError(retVal); + } + } + finally + { + Marshal.FreeCoTaskMem(pInputConfigInfo); + if (handleHash.IsAllocated) + handleHash.Free(); + if (sockAddrHandle.IsAllocated) + sockAddrHandle.Free(); + } + }); + } + + public static void DeleteCertificateBinding(params IPEndPoint[] ipPorts) + { + if (ipPorts == null || ipPorts.Length == 0) + return; + + CallHttpApi( + delegate + { + foreach (var ipPort in ipPorts) + { + HTTP_SERVICE_CONFIG_SSL_SET configSslSet = + new HTTP_SERVICE_CONFIG_SSL_SET(); + + GCHandle sockAddrHandle = CreateSockaddrStructure(ipPort); + IntPtr pIpPort = sockAddrHandle.AddrOfPinnedObject(); + HTTP_SERVICE_CONFIG_SSL_KEY httpServiceConfigSslKey = + new HTTP_SERVICE_CONFIG_SSL_KEY(pIpPort); + configSslSet.KeyDesc = httpServiceConfigSslKey; + + IntPtr pInputConfigInfo = + Marshal.AllocCoTaskMem( + Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_SET))); + Marshal.StructureToPtr(configSslSet, pInputConfigInfo, false); + + try + { + uint retVal = HttpDeleteServiceConfiguration(IntPtr.Zero, + HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo, + pInputConfigInfo, + Marshal.SizeOf(configSslSet), + IntPtr.Zero); + ThrowWin32ExceptionIfError(retVal); + } + finally + { + Marshal.FreeCoTaskMem(pInputConfigInfo); + if (sockAddrHandle.IsAllocated) + sockAddrHandle.Free(); + } + } + }); + } + + public static SslCertificateInfo[] QuerySslCertificateInfo() + { + var result = new List(); + + CallHttpApi( + delegate + { + uint token = 0; + + uint retVal; + do + { + HTTP_SERVICE_CONFIG_SSL_QUERY inputConfigInfoQuery = + new HTTP_SERVICE_CONFIG_SSL_QUERY + { + QueryDesc = HTTP_SERVICE_CONFIG_QUERY_TYPE.HttpServiceConfigQueryNext, + dwToken = token, + }; + + IntPtr pInputConfigInfo = + Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_QUERY))); + Marshal.StructureToPtr(inputConfigInfoQuery, pInputConfigInfo, false); + + IntPtr pOutputConfigInfo = IntPtr.Zero; + int returnLength = 0; + + const HTTP_SERVICE_CONFIG_ID queryType = HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo; + + try + { + int inputConfigInfoSize = Marshal.SizeOf(inputConfigInfoQuery); + retVal = HttpQueryServiceConfiguration(IntPtr.Zero, + queryType, + pInputConfigInfo, + inputConfigInfoSize, + pOutputConfigInfo, + returnLength, + out returnLength, + IntPtr.Zero); + if (ERROR_NO_MORE_ITEMS == retVal) + break; + if (ERROR_INSUFFICIENT_BUFFER == retVal) // ERROR_INSUFFICIENT_BUFFER = 122 + { + pOutputConfigInfo = Marshal.AllocCoTaskMem(returnLength); + + try + { + retVal = HttpQueryServiceConfiguration(IntPtr.Zero, + queryType, + pInputConfigInfo, + inputConfigInfoSize, + pOutputConfigInfo, + returnLength, + out returnLength, + IntPtr.Zero); + ThrowWin32ExceptionIfError(retVal); + + var outputConfigInfo = (HTTP_SERVICE_CONFIG_SSL_SET)Marshal.PtrToStructure( + pOutputConfigInfo, typeof(HTTP_SERVICE_CONFIG_SSL_SET)); + + byte[] hash = new byte[outputConfigInfo.ParamDesc.SslHashLength]; + Marshal.Copy(outputConfigInfo.ParamDesc.pSslHash, hash, 0, hash.Length); + + Guid appId = outputConfigInfo.ParamDesc.AppId; + string storeName = outputConfigInfo.ParamDesc.pSslCertStoreName; + IPEndPoint ipPort = ReadSockaddrStructure(outputConfigInfo.KeyDesc.pIpPort); + + var resultItem = new SslCertificateInfo + { + AppId = appId, + Hash = hash, + StoreName = storeName, + IpPort = ipPort + }; + result.Add(resultItem); + token++; + } + finally + { + Marshal.FreeCoTaskMem(pOutputConfigInfo); + } + } + else + { + ThrowWin32ExceptionIfError(retVal); + } + } + finally + { + Marshal.FreeCoTaskMem(pInputConfigInfo); + } + + } while (NOERROR == retVal); + + }); + + return result.ToArray(); + } + + public static void ReserveURL(string networkURL, string securityDescriptor) + { + if (String.IsNullOrEmpty(networkURL)) throw new ArgumentNullException("networkURL"); + if (String.IsNullOrEmpty(securityDescriptor)) throw new ArgumentNullException("securityDescriptor"); + + CallHttpApi( + delegate + { + uint retVal = (uint)NOERROR; // NOERROR = 0 + + HTTP_SERVICE_CONFIG_URLACL_KEY keyDesc = new HTTP_SERVICE_CONFIG_URLACL_KEY(networkURL); + HTTP_SERVICE_CONFIG_URLACL_PARAM paramDesc = new HTTP_SERVICE_CONFIG_URLACL_PARAM(securityDescriptor); + + HTTP_SERVICE_CONFIG_URLACL_SET inputConfigInfoSet = new HTTP_SERVICE_CONFIG_URLACL_SET(); + inputConfigInfoSet.KeyDesc = keyDesc; + inputConfigInfoSet.ParamDesc = paramDesc; + + IntPtr pInputConfigInfo = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_URLACL_SET))); + Marshal.StructureToPtr(inputConfigInfoSet, pInputConfigInfo, false); + try + { + retVal = HttpApi.HttpSetServiceConfiguration(IntPtr.Zero, + HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo, + pInputConfigInfo, + Marshal.SizeOf(inputConfigInfoSet), + IntPtr.Zero); + + if ((uint)ERROR_ALREADY_EXISTS == retVal) // ERROR_ALREADY_EXISTS = 183 + { + retVal = HttpApi.HttpDeleteServiceConfiguration(IntPtr.Zero, + HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo, + pInputConfigInfo, + Marshal.SizeOf(inputConfigInfoSet), + IntPtr.Zero); + + if ((uint)NOERROR == retVal) + { + retVal = HttpApi.HttpSetServiceConfiguration(IntPtr.Zero, + HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo, + pInputConfigInfo, + Marshal.SizeOf(inputConfigInfoSet), + IntPtr.Zero); + } + } + } + finally + { + Marshal.FreeCoTaskMem(pInputConfigInfo); + HttpApi.HttpTerminate(HttpApi.HTTP_INITIALIZE_CONFIG, IntPtr.Zero); + } + if ((uint)NOERROR != retVal) + { + ThrowWin32ExceptionIfError(retVal); + } + }); + } + + #endregion + + private static void ThrowWin32ExceptionIfError(uint retVal) + { + if (NOERROR != retVal) + { + throw new Win32Exception(Convert.ToInt32(retVal)); + } + } + + private static void CallHttpApi(Action body) + { + uint retVal = HttpInitialize(HttpApiVersion, HTTP_INITIALIZE_CONFIG, IntPtr.Zero); + ThrowWin32ExceptionIfError(retVal); + + try + { + body(); + } + finally + { + HttpTerminate(HTTP_INITIALIZE_CONFIG, IntPtr.Zero); + } + } + + /// + /// Creates an unmanaged sockaddr structure to pass to a WinAPI function. + /// + /// IP address and port number + /// a handle for the structure. Use the AddrOfPinnedObject Method to get a stable pointer to the object. + /// When the handle goes out of scope you must explicitly release it by calling the Free method; otherwise, memory leaks may occur. + private static GCHandle CreateSockaddrStructure(IPEndPoint ipEndPoint) + { + SocketAddress socketAddress = ipEndPoint.Serialize(); + + // use an array of bytes instead of the sockaddr structure + byte[] sockAddrStructureBytes = new byte[socketAddress.Size]; + GCHandle sockAddrHandle = GCHandle.Alloc(sockAddrStructureBytes, GCHandleType.Pinned); + for (int i = 0; i < socketAddress.Size; ++i) + { + sockAddrStructureBytes[i] = socketAddress[i]; + } + return sockAddrHandle; + } + + /// + /// Reads the unmanaged sockaddr structure returned by a WinAPI function + /// + /// pointer to the unmanaged sockaddr structure + /// IP address and port number + private static IPEndPoint ReadSockaddrStructure(IntPtr pSockaddrStructure) + { + short sAddressFamily = Marshal.ReadInt16(pSockaddrStructure); + AddressFamily addressFamily = (AddressFamily)sAddressFamily; + + int sockAddrSructureSize; + IPEndPoint ipEndPointAny; + switch (addressFamily) + { + case AddressFamily.InterNetwork: + // IP v4 address + sockAddrSructureSize = 16; + ipEndPointAny = new IPEndPoint(IPAddress.Any, 0); + break; + case AddressFamily.InterNetworkV6: + // IP v6 address + sockAddrSructureSize = 28; + ipEndPointAny = new IPEndPoint(IPAddress.IPv6Any, 0); + break; + default: + throw new ArgumentOutOfRangeException("pSockaddrStructure", "Unknown address family"); + } + + + // get bytes of the sockadrr structure + byte[] sockAddrSructureBytes = new byte[sockAddrSructureSize]; + Marshal.Copy(pSockaddrStructure, sockAddrSructureBytes, 0, sockAddrSructureSize); + + // create SocketAddress from bytes + var socketAddress = new SocketAddress(AddressFamily.Unspecified, sockAddrSructureSize); + for (int i = 0; i < sockAddrSructureSize; i++) + { + socketAddress[i] = sockAddrSructureBytes[i]; + } + + // create IPEndPoint from SocketAddress + IPEndPoint result = (IPEndPoint)ipEndPointAny.Create(socketAddress); + + return result; + } + } +} diff --git a/ConfigHttpApi/Properties/AssemblyInfo.cs b/ConfigHttpApi/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..c63c94dd --- /dev/null +++ b/ConfigHttpApi/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("ConfigHttpApi")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ConfigHttpApi")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("89f719af-3a0d-4704-be7f-16e5b4e19c02")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Output/ClientServerLib.dll b/Output/ClientServerLib.dll deleted file mode 100644 index 69ccb313..00000000 Binary files a/Output/ClientServerLib.dll and /dev/null differ diff --git a/Output/Interop.NetFwTypeLib.dll b/Output/Interop.NetFwTypeLib.dll new file mode 100644 index 00000000..135c15c5 Binary files /dev/null and b/Output/Interop.NetFwTypeLib.dll differ diff --git a/Output/Security.Cryptography.dll b/Output/Security.Cryptography.dll new file mode 100644 index 00000000..d1919854 Binary files /dev/null and b/Output/Security.Cryptography.dll differ diff --git a/Output/Security.dll b/Output/Security.dll new file mode 100644 index 00000000..f0c2c513 Binary files /dev/null and b/Output/Security.dll differ diff --git a/PhoneGap/config.xml b/PhoneGap/config.xml new file mode 100644 index 00000000..d0ee02a0 --- /dev/null +++ b/PhoneGap/config.xml @@ -0,0 +1,36 @@ + + + + + + Vocaluxe + + + Interact with Vocaluxe via your mobile device. + + + + Vocaluxe Team + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PhoneGap/icon.png b/PhoneGap/icon.png new file mode 100644 index 00000000..43151bf6 Binary files /dev/null and b/PhoneGap/icon.png differ diff --git a/Vocaluxe.sln b/Vocaluxe.sln index 0896a6f6..9b95b426 100644 --- a/Vocaluxe.sln +++ b/Vocaluxe.sln @@ -1,11 +1,12 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocaluxe.csproj", "{2A1E0F2D-5392-4BB7-B0A1-A9DFA13E79FF}" ProjectSection(ProjectDependencies) = postProject + {55F89808-4E79-4FFE-BC13-48258913F5C9} = {55F89808-4E79-4FFE-BC13-48258913F5C9} {6F3E1874-F28A-40E9-AFBD-31934D593678} = {6F3E1874-F28A-40E9-AFBD-31934D593678} {6F3E1874-F28A-40E9-AFBD-31934D593679} = {6F3E1874-F28A-40E9-AFBD-31934D593679} {ED007796-367F-4142-AA55-5450C7645C2C} = {ED007796-367F-4142-AA55-5450C7645C2C} + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3} = {EC5167E4-CCFB-4CEE-987C-CF816F1062A3} {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} = {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} {5A4053F1-5AD5-441F-B254-D97A088127B6} = {5A4053F1-5AD5-441F-B254-D97A088127B6} EndProjectSection @@ -20,6 +21,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeChallengeMedley", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GstreamerHelper", "GstreamerHelper\GstreamerHelper.vcxproj", "{ED007796-367F-4142-AA55-5450C7645C2C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerLib", "ClientServerLib\ClientServerLib\ServerLib.csproj", "{EC5167E4-CCFB-4CEE-987C-CF816F1062A3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebserverInitalConfig", "WebserverInitalConfig\WebserverInitalConfig.csproj", "{55F89808-4E79-4FFE-BC13-48258913F5C9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution DebugLinux|x64 = DebugLinux|x64 @@ -102,10 +107,8 @@ Global {5A4053F1-5AD5-441F-B254-D97A088127B6}.DebugWin|x64.Build.0 = DebugWin|x64 {5A4053F1-5AD5-441F-B254-D97A088127B6}.DebugWin|x86.ActiveCfg = DebugWin|x86 {5A4053F1-5AD5-441F-B254-D97A088127B6}.DebugWin|x86.Build.0 = DebugWin|x86 - {5A4053F1-5AD5-441F-B254-D97A088127B6}.InstallerWin|x64.ActiveCfg = InstallerWin|x64 - {5A4053F1-5AD5-441F-B254-D97A088127B6}.InstallerWin|x64.Build.0 = InstallerWin|x64 - {5A4053F1-5AD5-441F-B254-D97A088127B6}.InstallerWin|x86.ActiveCfg = InstallerWin|x86 - {5A4053F1-5AD5-441F-B254-D97A088127B6}.InstallerWin|x86.Build.0 = InstallerWin|x86 + {5A4053F1-5AD5-441F-B254-D97A088127B6}.InstallerWin|x64.ActiveCfg = ReleaseWin|x64 + {5A4053F1-5AD5-441F-B254-D97A088127B6}.InstallerWin|x86.ActiveCfg = ReleaseWin|x86 {5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|x64 {5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseLinux|x64.Build.0 = ReleaseLinux|x64 {5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseLinux|x86.ActiveCfg = ReleaseLinux|x86 @@ -122,10 +125,8 @@ Global {6F3E1874-F28A-40E9-AFBD-31934D593678}.DebugWin|x64.Build.0 = DebugWin|x64 {6F3E1874-F28A-40E9-AFBD-31934D593678}.DebugWin|x86.ActiveCfg = DebugWin|x86 {6F3E1874-F28A-40E9-AFBD-31934D593678}.DebugWin|x86.Build.0 = DebugWin|x86 - {6F3E1874-F28A-40E9-AFBD-31934D593678}.InstallerWin|x64.ActiveCfg = InstallerWin|x64 - {6F3E1874-F28A-40E9-AFBD-31934D593678}.InstallerWin|x64.Build.0 = InstallerWin|x64 - {6F3E1874-F28A-40E9-AFBD-31934D593678}.InstallerWin|x86.ActiveCfg = InstallerWin|x86 - {6F3E1874-F28A-40E9-AFBD-31934D593678}.InstallerWin|x86.Build.0 = InstallerWin|x86 + {6F3E1874-F28A-40E9-AFBD-31934D593678}.InstallerWin|x64.ActiveCfg = ReleaseWin|x64 + {6F3E1874-F28A-40E9-AFBD-31934D593678}.InstallerWin|x86.ActiveCfg = ReleaseWin|x86 {6F3E1874-F28A-40E9-AFBD-31934D593678}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|x64 {6F3E1874-F28A-40E9-AFBD-31934D593678}.ReleaseLinux|x64.Build.0 = ReleaseLinux|x64 {6F3E1874-F28A-40E9-AFBD-31934D593678}.ReleaseLinux|x86.ActiveCfg = ReleaseLinux|x86 @@ -140,16 +141,40 @@ Global {ED007796-367F-4142-AA55-5450C7645C2C}.DebugWin|x64.Build.0 = DebugWin|x64 {ED007796-367F-4142-AA55-5450C7645C2C}.DebugWin|x86.ActiveCfg = DebugWin|Win32 {ED007796-367F-4142-AA55-5450C7645C2C}.DebugWin|x86.Build.0 = DebugWin|Win32 - {ED007796-367F-4142-AA55-5450C7645C2C}.InstallerWin|x64.ActiveCfg = InstallerWin|x64 - {ED007796-367F-4142-AA55-5450C7645C2C}.InstallerWin|x64.Build.0 = InstallerWin|x64 - {ED007796-367F-4142-AA55-5450C7645C2C}.InstallerWin|x86.ActiveCfg = InstallerWin|Win32 - {ED007796-367F-4142-AA55-5450C7645C2C}.InstallerWin|x86.Build.0 = InstallerWin|Win32 + {ED007796-367F-4142-AA55-5450C7645C2C}.InstallerWin|x64.ActiveCfg = ReleaseWin|x64 + {ED007796-367F-4142-AA55-5450C7645C2C}.InstallerWin|x86.ActiveCfg = ReleaseWin|Win32 {ED007796-367F-4142-AA55-5450C7645C2C}.ReleaseLinux|x64.ActiveCfg = ReleaseWin|x64 {ED007796-367F-4142-AA55-5450C7645C2C}.ReleaseLinux|x86.ActiveCfg = ReleaseWin|x64 {ED007796-367F-4142-AA55-5450C7645C2C}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 {ED007796-367F-4142-AA55-5450C7645C2C}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 {ED007796-367F-4142-AA55-5450C7645C2C}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Win32 {ED007796-367F-4142-AA55-5450C7645C2C}.ReleaseWin|x86.Build.0 = ReleaseWin|Win32 + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugLinux|x64.ActiveCfg = Debug|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugLinux|x64.Build.0 = Debug|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugLinux|x86.ActiveCfg = Debug|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugWin|x64.ActiveCfg = Debug|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugWin|x64.Build.0 = Debug|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.DebugWin|x86.ActiveCfg = Debug|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.InstallerWin|x64.ActiveCfg = Release|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.InstallerWin|x86.ActiveCfg = Release|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseLinux|x64.ActiveCfg = Release|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseLinux|x64.Build.0 = Release|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseLinux|x86.ActiveCfg = Release|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseWin|x64.ActiveCfg = Release|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseWin|x64.Build.0 = Release|Any CPU + {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}.ReleaseWin|x86.ActiveCfg = Release|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugLinux|x64.ActiveCfg = Debug|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugLinux|x86.ActiveCfg = Debug|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugWin|x64.ActiveCfg = Debug|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugWin|x64.Build.0 = Debug|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugWin|x86.ActiveCfg = Debug|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.InstallerWin|x64.ActiveCfg = Release|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.InstallerWin|x86.ActiveCfg = Release|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseLinux|x64.ActiveCfg = Release|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseLinux|x86.ActiveCfg = Release|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x64.ActiveCfg = Release|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x64.Build.0 = Release|Any CPU + {55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Vocaluxe/Base/CConfig.cs b/Vocaluxe/Base/CConfig.cs index 9902d6b9..b350c067 100644 --- a/Vocaluxe/Base/CConfig.cs +++ b/Vocaluxe/Base/CConfig.cs @@ -124,7 +124,7 @@ namespace Vocaluxe.Base public static EOffOn ServerActive = EOffOn.TR_CONFIG_OFF; public static EOffOn ServerEncryption = EOffOn.TR_CONFIG_OFF; public static int ServerPort = 3000; - public static string ServerPassword = "vocaluxe"; + //public static string ServerPassword = "vocaluxe"; //Lists to save parameters and values private static readonly List _Params = new List(); @@ -299,7 +299,7 @@ namespace Vocaluxe.Base if (ServerPort < 1 || ServerPort > 65535) ServerPort = 3000; - xmlReader.GetValue("//root/Server/ServerPassword", out ServerPassword, ServerPassword); + //xmlReader.GetValue("//root/Server/ServerPassword", out ServerPassword, ServerPassword); #endregion Server } @@ -573,8 +573,8 @@ namespace Vocaluxe.Base writer.WriteComment("Server Port (default: 3000) [1..65535]"); writer.WriteElementString("ServerPort", ServerPort.ToString()); - writer.WriteComment("Server Password (default: vocaluxe)"); - writer.WriteElementString("ServerPassword", ServerPassword); + //writer.WriteComment("Server Password (default: vocaluxe)"); + //writer.WriteElementString("ServerPassword", ServerPassword); writer.WriteEndElement(); #endregion Server diff --git a/Vocaluxe/Base/CPlaylists.cs b/Vocaluxe/Base/CPlaylists.cs index 2c9e2d6a..9f0793c1 100644 --- a/Vocaluxe/Base/CPlaylists.cs +++ b/Vocaluxe/Base/CPlaylists.cs @@ -1,18 +1,18 @@ -#region license -// This file is part of Vocaluxe. +#region license +// This file is part of Vocaluxe. // -// Vocaluxe is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// Vocaluxe is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with Vocaluxe. If not, see . +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . #endregion using System; @@ -77,7 +77,7 @@ namespace Vocaluxe.Base foreach (string file in files) { - var playlist = new CPlaylistFile(file); + CPlaylistFile playlist = new CPlaylistFile(file, files.IndexOf(file)); _Playlists.Add(playlist); } } @@ -125,7 +125,7 @@ namespace Vocaluxe.Base public static int NewPlaylist() { - var pl = new CPlaylistFile {PlaylistName = "New Playlist"}; + CPlaylistFile pl = new CPlaylistFile { PlaylistName = "New Playlist", Id = _Playlists.Count }; _Playlists.Add(pl); return _Playlists.Count - 1; } diff --git a/Vocaluxe/Base/CProfiles.cs b/Vocaluxe/Base/CProfiles.cs index d8c61652..44f996fe 100644 --- a/Vocaluxe/Base/CProfiles.cs +++ b/Vocaluxe/Base/CProfiles.cs @@ -1,18 +1,18 @@ -#region license -// This file is part of Vocaluxe. +#region license +// This file is part of Vocaluxe. // -// Vocaluxe is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// Vocaluxe is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with Vocaluxe. If not, see . +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . #endregion using System; @@ -305,6 +305,16 @@ namespace Vocaluxe.Base return list.ToArray(); } + public static CProfile GetProfile(int profileID) + { + if (!IsProfileIDValid(profileID)) + { + return null; + } + + return _Profiles[profileID]; + } + public static IEnumerable GetAvatars() { if (_Avatars.Count == 0) @@ -480,6 +490,14 @@ namespace Vocaluxe.Base return _Profiles[profileID].Avatar.ID; } + public static CAvatar GetAvatar(int profileID) + { + if (!IsProfileIDValid(profileID)) + return null; + + return _Profiles[profileID].Avatar; + } + public static int GetProfileID(int num) { return _Profiles[num].ID; diff --git a/Vocaluxe/Base/CSettings.cs b/Vocaluxe/Base/CSettings.cs index 9fe7b69f..7f63c97e 100644 --- a/Vocaluxe/Base/CSettings.cs +++ b/Vocaluxe/Base/CSettings.cs @@ -1,18 +1,18 @@ -#region license -// This file is part of Vocaluxe. +#region license +// This file is part of Vocaluxe. // -// Vocaluxe is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// Vocaluxe is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with Vocaluxe. If not, see . +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . #endregion using System; @@ -102,6 +102,7 @@ namespace Vocaluxe.Base #endif Path.Combine(DataPath, FolderProfiles) }; + public static string FolderPhotos = "Photos"; public const string FolderSongs = "Songs"; public const string FolderSounds = "Sounds"; public const string FolderLanguages = "Languages"; diff --git a/Vocaluxe/Base/Server/CCommands.cs b/Vocaluxe/Base/Server/CCommands.cs index 544f443e..6e6f0e66 100644 --- a/Vocaluxe/Base/Server/CCommands.cs +++ b/Vocaluxe/Base/Server/CCommands.cs @@ -1,4 +1,4 @@ -#region license +#region license // This file is part of Vocaluxe. // // Vocaluxe is free software: you can redistribute it and/or modify @@ -83,47 +83,6 @@ namespace Vocaluxe.Base.Server } #endregion Login - #region Keyboard - #endregion Keyboard - - #region Profiles - public static byte[] CreateCommandSendAvatarPicture(int width, int height, byte[] data) - { - var ap = new SAvatarPicture {Height = height, Width = width, Data = new byte[data.Length]}; - Array.Copy(data, ap.Data, data.Length); - - return _Serialize(CommandSendAvatarPicture, ap); - } - - public static bool DecodeCommandSendAvatarPicture(byte[] message, out SAvatarPicture avatarPicture) - { - return _TryDeserialize(message, out avatarPicture); - } - - public static byte[] CreateCommandSendAvatarPictureJpg(byte[] avatarJpgData) - { - var ap = new SAvatarPicture {Height = 0, Width = 0, Data = new byte[avatarJpgData.Length]}; - Array.Copy(avatarJpgData, ap.Data, avatarJpgData.Length); - - return _Serialize(CommandSendAvatarPictureJpg, ap); - } - - public static byte[] CreateCommandSendProfile(byte[] avatarJpgData, string playerName, int difficulty) - { - var ap = new SAvatarPicture {Height = 0, Width = 0, Data = new byte[avatarJpgData.Length]}; - Array.Copy(avatarJpgData, ap.Data, avatarJpgData.Length); - - var profile = new SProfile {Avatar = ap, PlayerName = playerName, Difficulty = difficulty}; - - return _Serialize(CommandSendProfile, profile); - } - - public static bool DecodeCommandSendProfile(byte[] message, out SProfile profile) - { - return _TryDeserialize(message, out profile); - } - #endregion Profiles - #region Serializing private static byte[] _Serialize(T obj) { @@ -138,7 +97,7 @@ namespace Vocaluxe.Base.Server stream.Write(cmd, 0, cmd.Length); byte[] data; - string json = JsonConvert.SerializeObject(obj); + string json = JsonConvert.SerializeObject(obj); data = _Encoder.GetBytes(json); stream.Write(data, 0, data.Length); return stream.ToArray(); @@ -156,16 +115,16 @@ namespace Vocaluxe.Base.Server var data = new byte[message.Length - 4]; Array.Copy(message, 4, data, 0, data.Length); - try - { + try + { obj = JsonConvert.DeserializeObject(_Encoder.GetString(data)); - return true; - } - catch - { - return false; + return true; + } + catch + { + return false; } } #endregion Serializing } -} \ No newline at end of file +} diff --git a/Vocaluxe/Base/Server/CVocaluxeServer.cs b/Vocaluxe/Base/Server/CVocaluxeServer.cs index 557bef55..d64bbf4d 100644 --- a/Vocaluxe/Base/Server/CVocaluxeServer.cs +++ b/Vocaluxe/Base/Server/CVocaluxeServer.cs @@ -1,49 +1,75 @@ -#region license -// This file is part of Vocaluxe. +#region license +// This file is part of Vocaluxe. // -// Vocaluxe is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// Vocaluxe is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with Vocaluxe. If not, see . +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . #endregion using System; using System.Collections.Generic; using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.InteropServices; +using System.Linq; using System.IO; +using System.Text; using System.Windows.Forms; -using ClientServerLib; +using ServerLib; using Vocaluxe.Lib.Input; +using Vocaluxe.Lib.Playlist; using VocaluxeLib; +using VocaluxeLib.Draw; +using VocaluxeLib.Menu; using VocaluxeLib.Profile; +using VocaluxeLib.Songs; +using System.Security.Cryptography; namespace Vocaluxe.Base.Server { static class CVocaluxeServer { private static CServer _Server; - private static CDiscover _Discover; - private static Dictionary _Clients; + //private static CDiscover _Discover; public static readonly CControllerFramework Controller = new CControllerFramework(); public static void Init() { - _Clients = new Dictionary(); - String pw = (CConfig.ServerEncryption == EOffOn.TR_CONFIG_ON) ? CConfig.ServerPassword : String.Empty; - _Server = new CServer(RequestHandler, CConfig.ServerPort, pw); + _Server = new CServer(CConfig.ServerPort, CConfig.ServerEncryption == EOffOn.TR_CONFIG_ON); - _Discover = new CDiscover(CConfig.ServerPort, CCommands.BroadcastKeyword); + CServer.SendKeyEvent = _SendKeyEvent; + CServer.GetProfileData = _GetProfileData; + CServer.SendProfileData = _SendProfileData; + CServer.GetProfileList = _GetProfileList; + CServer.SendPhoto = _SendPhoto; + CServer.GetSiteFile = _GetSiteFile; + CServer.GetSong = _GetSong; + CServer.GetAllSongs = _GetAllSongs; + CServer.GetCurrentSongId = _GetCurrentSongId; + CServer.ValidatePassword = _ValidatePassword; + CServer.GetUserRole = _GetUserRole; + CServer.SetUserRole = _SetUserRole; + CServer.GetUserIdFromUsername = _GetUserIdFromUsername; + CServer.GetDelayedImage = _GetDelayedImage; + CServer.GetPlaylists = _GetPlaylists; + CServer.GetPlaylist = _GetPlaylist; + CServer.AddSongToPlaylist = _AddSongToPlaylist; + CServer.RemoveSongFromPlaylist = _RemoveSongFromPlaylist; + CServer.MoveSongInPlaylist = _MoveSongInPlaylist; + CServer.PlaylistContainsSong = _PlaylistContainsSong; + CServer.GetPlaylistSongs = _GetPlaylistSongs; + CServer.RemovePlaylist = _RemovePlaylist; + CServer.AddPlaylist = _AddPlaylist; + + //_Discover = new CDiscover(CConfig.ServerPort, CCommands.BroadcastKeyword); Controller.Init(); } @@ -52,158 +78,673 @@ namespace Vocaluxe.Base.Server if (CConfig.ServerActive == EOffOn.TR_CONFIG_ON) { _Server.Start(); - _Discover.StartBroadcasting(); + //_Discover.StartBroadcasting(); } } public static void Close() { _Server.Stop(); - _Discover.Stop(); - _Clients = new Dictionary(); + //_Discover.Stop(); } - private static byte[] RequestHandler(int connectionID, byte[] message) + private static bool _SendKeyEvent(string key) { - byte[] answer = CCommands.CreateCommandWithoutParams(CCommands.ResponseNOK); - - if (message == null) - return answer; - - if (message.Length < 4) - return answer; - - bool loggedIn; - lock (_Clients) + bool result = false; + if (!string.IsNullOrEmpty(key)) { - if (!_Clients.ContainsKey(connectionID)) + switch (key.ToLower()) { - var client = new CClientHandler(connectionID); - _Clients.Add(connectionID, client); - - //just a small fix: There is no real login at the moment, so set it to true. - _Clients[connectionID].LoggedIn = true; - } - - - loggedIn = _Clients[connectionID].LoggedIn; - } - - if (!loggedIn) - return CCommands.CreateCommandWithoutParams(CCommands.ResponseNOK); - - int command = BitConverter.ToInt32(message, 0); - - switch (command) - { - case CCommands.CommandSendKeyUp: - answer = CCommands.CreateCommandWithoutParams(CCommands.ResponseOK); - Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, Keys.Up)); - break; - - case CCommands.CommandSendKeyDown: - answer = CCommands.CreateCommandWithoutParams(CCommands.ResponseOK); - Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, Keys.Down)); - break; - - case CCommands.CommandSendKeyLeft: - answer = CCommands.CreateCommandWithoutParams(CCommands.ResponseOK); - Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, Keys.Left)); - break; - - case CCommands.CommandSendKeyRight: - answer = CCommands.CreateCommandWithoutParams(CCommands.ResponseOK); - Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, Keys.Right)); - break; - - case CCommands.CommandSendAvatarPicture: - - SAvatarPicture avatarPicture; - if (CCommands.DecodeCommandSendAvatarPicture(message, out avatarPicture)) - { - using (var bmp = new Bitmap(avatarPicture.Width, avatarPicture.Height)) + case "up": + Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, Keys.Up)); + result = true; + break; + case "down": + Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, Keys.Down)); + result = true; + break; + case "left": + Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, Keys.Left)); + result = true; + break; + case "right": + Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, Keys.Right)); + result = true; + break; + case "escape": + Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, Keys.Escape)); + result = true; + break; + case "return": + Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, Keys.Return)); + result = true; + break; + case "tab": + Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, Keys.Tab)); + result = true; + break; + default: + foreach (char c in key.ToCharArray()) { - BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); - Marshal.Copy(avatarPicture.Data, 0, bmpData.Scan0, avatarPicture.Data.Length); - bmp.UnlockBits(bmpData); - - const string filename = "snapshot"; - int i = 0; - while (File.Exists(Path.Combine(CSettings.DataPath, CSettings.FolderProfiles, filename + i + ".png"))) - i++; - bmp.Save(Path.Combine(CSettings.DataPath, CSettings.FolderProfiles, filename + i + ".png"), ImageFormat.Png); - } - - answer = CCommands.CreateCommandWithoutParams(CCommands.ResponseOK); - } - break; - - case CCommands.CommandSendAvatarPictureJpg: - - SAvatarPicture avatarPictureJpg; - if (CCommands.DecodeCommandSendAvatarPicture(message, out avatarPictureJpg)) - { - if (_AddAvatar(avatarPictureJpg.Data) != String.Empty) - answer = CCommands.CreateCommandWithoutParams(CCommands.ResponseOK); - } - break; - - case CCommands.CommandSendProfile: - SProfile profile; - if (CCommands.DecodeCommandSendProfile(message, out profile)) - { - try - { - string avatarFilename = _AddAvatar(profile.Avatar.Data); - if (avatarFilename != String.Empty) + bool shift = true; + char keyChar; + if (char.ToUpper(c) != c) { - var p = new CProfile - { - Active = EOffOn.TR_CONFIG_ON, - AvatarFileName = avatarFilename, - Difficulty = (EGameDifficulty)profile.Difficulty, - GuestProfile = EOffOn.TR_CONFIG_OFF, - PlayerName = profile.PlayerName - }; - CProfiles.AddProfile(p); - answer = CCommands.CreateCommandWithoutParams(CCommands.ResponseOK); + keyChar = char.ToUpper(c); + shift = false; + } + else + { + keyChar = c; + } + + if ((keyChar >= 0x30 && keyChar <= 0x39) || (keyChar >= 0x41 && keyChar <= 0x5A)) + { + Keys keys = (Keys)keyChar; + if (shift) + { + keys |= Keys.Shift; + } + Controller.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, Char.MinValue, keys)); + result = true; } } - catch (Exception) {} - } - - break; + break; + } } - return answer; + return result; + } - private static string _AddAvatar(byte[] jpgData) + #region profile + + private static SProfileData _GetProfileData(int profileId, bool isReadonly) + { + CProfile profile = CProfiles.GetProfile(profileId); + if (profile == null) + { + return new SProfileData(); + } + return _CreateProfileData(profile, isReadonly); + } + + private static bool _SendProfileData(SProfileData profile) + { + CProfile newProfile; + CProfile existingProfile = CProfiles.GetProfile(profile.ProfileId); + + if (existingProfile != null) + { + newProfile = new CProfile + { + ID = existingProfile.ID, + FileName = existingProfile.FileName, + Active = existingProfile.Active, + AvatarFileName = existingProfile.AvatarFileName, + Avatar = existingProfile.Avatar, + Difficulty = existingProfile.Difficulty, + GuestProfile = existingProfile.GuestProfile, + PlayerName = existingProfile.PlayerName + }; + } + else + { + newProfile = new CProfile + { + Active = EOffOn.TR_CONFIG_ON, + GuestProfile = EOffOn.TR_CONFIG_OFF + }; + } + + if (profile.Avatar != null) + { + newProfile.Avatar = _AddAvatar(profile.Avatar); + + } + else if (newProfile.Avatar == null || newProfile.Avatar.ID == -1) + { + newProfile.Avatar = CProfiles.GetAvatars().First(); + + /*CAvatar avatar = new CAvatar(-1); + avatar.LoadFromFile("Profiles\\Avatar_f.png"); + CProfiles.AddAvatar(avatar); + newProfile.Avatar = avatar;*/ + } + + if (!string.IsNullOrEmpty(profile.PlayerName)) + { + newProfile.PlayerName = profile.PlayerName; + } + else if (!string.IsNullOrEmpty(newProfile.PlayerName)) + { + newProfile.PlayerName = "DummyName"; + } + + if (profile.Difficulty >= 0 && profile.Difficulty <= 2) + { + newProfile.Difficulty = (EGameDifficulty)profile.Difficulty; + } + + if (profile.Type >= 0 && profile.Type <= 1) + { + newProfile.GuestProfile = (EOffOn)profile.Type; + } + + if (!string.IsNullOrEmpty(profile.Password)) + { + if (profile.Password == "***__CLEAR_PASSWORD__***") + { + newProfile.PasswordSalt = null; + newProfile.PasswordHash = null; + } + else + { + RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); + byte[] buffer = new byte[32]; + rng.GetNonZeroBytes(buffer); + byte[] salt = buffer; + byte[] hashedPassword = _Hash((new UTF8Encoding()).GetBytes(profile.Password), salt); + + newProfile.PasswordSalt = salt; + newProfile.PasswordHash = hashedPassword; + } + } + + if (existingProfile != null) + { + CProfiles.EditProfile(newProfile); + CProfiles.Update(); + CProfiles.SaveProfiles(); + } + else + { + CProfiles.AddProfile(newProfile); + } + + return true; + } + + private static SProfileData[] _GetProfileList() + { + List result = new List(CProfiles.NumProfiles); + + result.AddRange(CProfiles.GetProfiles().Select(profile => _CreateProfileData(profile, true))); + + return result.ToArray(); + } + + private static SProfileData _CreateProfileData(CProfile profile, bool isReadonly) + { + SProfileData profileData = new SProfileData + { + IsEditable = !isReadonly, + ProfileId = profile.ID, + PlayerName = profile.PlayerName, + Type = (int)profile.GuestProfile, + Difficulty = (int)profile.Difficulty + }; + + CAvatar avatar = profile.Avatar; + if (avatar != null) + { + if (File.Exists(avatar.FileName)) + { + profileData.Avatar = new CBase64Image(_CreateDelayedImage(avatar.FileName)); + } + } + return profileData; + } + + private static CAvatar _AddAvatar(CBase64Image avatarData) { - string result = String.Empty; try { - string filename = Path.Combine(CSettings.DataPath, CSettings.FolderProfiles, "snapshot"); - int i = 0; - while (File.Exists(filename + i + ".jpg")) - i++; - - filename = filename + i + ".jpg"; - FileStream fs = File.Create(filename); - fs.Write(jpgData, 0, jpgData.Length); - fs.Flush(); - fs.Close(); + string filename = _SaveImage(avatarData, "snapshot", CSettings.FolderProfiles); var avatar = new CAvatar(-1); if (avatar.LoadFromFile(filename)) { CProfiles.AddAvatar(avatar); - result = filename; + return avatar; + } + return null; + } + catch + { + return null; + } + } + + #endregion + + #region photo + + private static List photosOfThisRound = new List(); + + private static bool _SendPhoto(SPhotoData photoData) + { + if (photoData.Photo == null) + { + return false; + } + + string name = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"); + string filePath = _SaveImage(photoData.Photo, name, CSettings.FolderPhotos); + if (!string.IsNullOrEmpty(filePath)) + { + photosOfThisRound.Add(filePath); + return true; + } + + return false; + } + + internal static string[] getPhotosOfThisRound() + { + var result = photosOfThisRound.ToArray(); + photosOfThisRound.Clear(); + return result; + } + + #endregion + + #region website + + private static readonly Dictionary _DelayedImagePath = new Dictionary(); + + private static byte[] _GetSiteFile(string filename) + { + string path = "Website/" + filename; + path = path.Replace("..", ""); + + if (!File.Exists(path)) + { + return null; + } + + /*string content = File.ReadAllText(path); + + content = content.Replace("%SERVER%", System.Net.Dns.GetHostName() + ":" + CConfig.ServerPort); + + + return Encoding.UTF8.GetBytes(content);*/ + + return File.ReadAllBytes(path); + } + + private static string _CreateDelayedImage(string filename) + { + byte[] by = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(filename)); + var sb = new StringBuilder(); + foreach (byte b in by) + { + sb.Append(b.ToString("x2")); + } + + string hashedFilename = sb.ToString(); + + if (!_DelayedImagePath.ContainsKey(hashedFilename)) + { + _DelayedImagePath.Add(hashedFilename, filename); + } + return hashedFilename; + } + + private static CBase64Image _GetDelayedImage(string hashedFilename) + { + if (!_DelayedImagePath.ContainsKey(hashedFilename)) + { + throw new FileNotFoundException("Image not found"); + } + + string fileName = _DelayedImagePath[hashedFilename]; + + if (File.Exists(fileName)) + { + Image image = Image.FromFile(fileName); + return new CBase64Image(image, image.RawFormat); + } + throw new FileNotFoundException("Image not found"); + } + + #endregion + + #region songs + + private static SSongInfo _GetSong(int songId) + { + CSong song = CSongs.GetSong(songId); + return _GetSongInfo(song, true); + } + + private static SSongInfo[] _GetAllSongs() + { + var songs = CSongs.Songs; + return (from s in songs + select _GetSongInfo(s, false)).ToArray(); + } + + private static int _GetCurrentSongId() + { + CSong song = CGame.GetSong(); + if (song == null) + { + return -1; + } + return song.ID; + } + + private static SSongInfo _GetSongInfo(CSong song, bool includeCover) + { + SSongInfo result = new SSongInfo(); + if (song != null) + { + result.Title = song.Title; + result.Artist = song.Artist; + result.Genre = song.Genres.FirstOrDefault(); + result.Language = song.Languages.FirstOrDefault(); + result.Year = song.Year; + result.IsDuet = song.IsDuet; + result.SongId = song.ID; + if (includeCover) + { + result.Cover = new CBase64Image(_CreateDelayedImage(song.Folder + "\\" + song.CoverFileName)); } } - catch {} - return result; } + + #endregion + + #region playlist + + private static SPlaylistInfo[] _GetPlaylists() + { + return (from p in CPlaylists.Playlists + select _GetPlaylistInfo(p)).ToArray(); + } + + private static SPlaylistInfo _GetPlaylist(int playlistId) + { + if (CPlaylists.Playlists.Length <= playlistId || playlistId < 0) + { + throw new ArgumentException("invalid playlistId"); + } + return _GetPlaylistInfo(CPlaylists.Playlists[playlistId]); + } + + private static void _AddSongToPlaylist(int songId, int playlistId, bool allowDuplicates) + { + if (CPlaylists.Playlists.Length <= playlistId || playlistId < 0) + { + throw new ArgumentException("invalid playlistId"); + } + + if (allowDuplicates || !_PlaylistContainsSong(songId, playlistId)) + { + CPlaylists.AddPlaylistSong(playlistId, songId); + CPlaylists.SavePlaylist(playlistId); + } + else + { + throw new ArgumentException("song exists in this playlist"); + } + } + + private static void _RemoveSongFromPlaylist(int position, int playlistId, int songId) + { + if (CPlaylists.Playlists.Length <= playlistId || playlistId < 0) + { + throw new ArgumentException("invalid playlistId"); + } + if (!_PlaylistContainsSong(songId, playlistId)) + { + throw new ArgumentException("invalid songId"); + } + if (position < 0 || CPlaylists.Playlists[playlistId].Songs.Count <= position + || CPlaylists.Playlists[playlistId].Songs[position].SongID != songId) + { + throw new ArgumentException("invalid position"); + } + CPlaylists.Playlists[playlistId].DeleteSong(position); + CPlaylists.SavePlaylist(playlistId); + } + + private static void _MoveSongInPlaylist(int newPosition, int playlistId, int songId) + { + if (CPlaylists.Playlists.Length <= playlistId || playlistId < 0) + { + throw new ArgumentException("invalid playlistId"); + } + if (!_PlaylistContainsSong(songId, playlistId)) + { + throw new ArgumentException("invalid songId"); + } + + if (CPlaylists.Playlists[playlistId].Songs.Count < newPosition) + { + throw new ArgumentException("invalid newPosition"); + } + + int oldPosition = CPlaylists.Playlists[playlistId].Songs.FindIndex(s => s.SongID == songId); + CPlaylists.MovePlaylistSong(playlistId, oldPosition, newPosition); + CPlaylists.SavePlaylist(playlistId); + } + + private static bool _PlaylistContainsSong(int songId, int playlistId) + { + if (CPlaylists.Playlists.Length <= playlistId || playlistId < 0) + { + throw new ArgumentException("invalid playlistId"); + } + return CPlaylists.Playlists[playlistId].Songs.Any(s => s.SongID == songId); + } + + private static SPlaylistSongInfo[] _GetPlaylistSongs(int playlistId) + { + if (CPlaylists.Playlists.Length <= playlistId || playlistId < 0) + { + throw new ArgumentException("invalid playlistId"); + } + + return _GetPlaylistSongInfos(CPlaylists.Playlists[playlistId]); + } + + private static SPlaylistSongInfo _GetPlaylistSongInfo(CPlaylistSong playlistSong, int playlistId, int playlistPos) + { + SPlaylistSongInfo result = new SPlaylistSongInfo(); + if (playlistSong != null) + { + result.PlaylistId = playlistId; + result.GameMode = (int)playlistSong.GameMode; + result.PlaylistPosition = playlistPos; + result.Song = _GetSongInfo(CSongs.GetSong(playlistSong.SongID), true); + } + return result; + } + + private static SPlaylistSongInfo[] _GetPlaylistSongInfos(CPlaylistFile playlist) + { + SPlaylistSongInfo[] result = new SPlaylistSongInfo[playlist.Songs.Count]; + for (int i = 0; i < playlist.Songs.Count; i++) + { + result[i] = _GetPlaylistSongInfo(playlist.Songs[i], playlist.Id, i); + } + return result; + } + + private static SPlaylistInfo _GetPlaylistInfo(CPlaylistFile playlist) + { + return new SPlaylistInfo + { + PlaylistId = playlist.Id, + PlaylistName = playlist.PlaylistName, + SongCount = playlist.Songs.Count, + LastChanged = DateTime.Now.ToLongDateString() + }; + } + + private static void _RemovePlaylist(int playlistId) + { + if (CPlaylists.Playlists.Length <= playlistId || playlistId < 0) + { + throw new ArgumentException("invalid playlistId"); + } + CPlaylists.DeletePlaylist(playlistId); + } + + private static int _AddPlaylist(string playlistName) + { + int newPlaylistId = CPlaylists.NewPlaylist(); + CPlaylists.Playlists[newPlaylistId].PlaylistName = playlistName; + CPlaylists.SavePlaylist(newPlaylistId); + + return newPlaylistId; + } + + #endregion + + #region user management + + private static bool _ValidatePassword(int profileId, string password) + { + CProfile profile = CProfiles.GetProfile(profileId); + if (profile == null) + { + throw new ArgumentException("Invalid profileId"); + } + + if (profile.PasswordHash == null) + { + if (string.IsNullOrEmpty(password)) + { + return true; //Allow emty passwords + } + return false; + } + + byte[] salt = profile.PasswordSalt; + return _Hash((new UTF8Encoding()).GetBytes(password), salt).SequenceEqual(profile.PasswordHash); + } + + private static bool _ValidatePassword(int profileId, byte[] hashedPassword) + { + CProfile profile = CProfiles.GetProfile(profileId); + if (profile == null) + { + throw new ArgumentException("Invalid profileId"); + } + + if (profile.PasswordHash == null) + { + if (hashedPassword == null) + { + return true; //Allow emty passwords + } + return false; + } + + byte[] salt = profile.PasswordSalt; + return hashedPassword.SequenceEqual(profile.PasswordHash); + } + + private static byte[] _GetPassowordSalt(int profileId) + { + CProfile profile = CProfiles.GetProfile(profileId); + if (profile == null) + { + throw new ArgumentException("Invalid profileId"); + } + + if (profile.PasswordHash == null) + { + throw new ArgumentException("Emty password"); + } + + return profile.PasswordSalt; + } + + private static int _GetUserRole(int profileId) + { + CProfile profile = CProfiles.GetProfile(profileId); + if (profile == null) + { + throw new ArgumentException("Invalid profileId"); + } + + return profile.UserRoles; + } + + private static void _SetUserRole(int profileId, int userRole) + { + CProfile profile = CProfiles.GetProfile(profileId); + if (profile == null) + { + throw new ArgumentException("Invalid profileId"); + } + + profile.UserRoles = userRole; + + CProfiles.EditProfile(profile); + CProfiles.Update(); + CProfiles.SaveProfiles(); + } + + private static int _GetUserIdFromUsername(string username) + { + var playerIds = (from p in CProfiles.GetProfiles() + where String.Equals(p.PlayerName, username, StringComparison.OrdinalIgnoreCase) + select p.ID); + if (!playerIds.Any()) + { + throw new ArgumentException("Invalid playername"); + } + + return playerIds.First(); + } + + private static byte[] _Hash(byte[] password, byte[] salt) + { + HashAlgorithm hashAlgo = new SHA256Managed(); + + byte[] data = new byte[password.Length + salt.Length]; + + password.CopyTo(data, 0); + salt.CopyTo(data, password.Length); + + return hashAlgo.ComputeHash(data); + } + + #endregion + + private static string _SaveImage(CBase64Image imageDate, string name, string folder) + { + Image avatarImage = imageDate.GetImage(); + string extension = imageDate.GetImageType(); + + if (!Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + + string filename = Path.Combine(folder, name); + if (File.Exists(filename + "." + extension)) + { + int i = 0; + while (File.Exists(filename + "_" + i + "." + extension)) + { + i++; + } + filename = filename + "_" + i + "." + extension; + } + else + { + filename = filename + "." + extension; + } + + avatarImage.Save(filename); + return filename; + } } } \ No newline at end of file diff --git a/Vocaluxe/Base/Server/VocaluxeStructs.cs b/Vocaluxe/Base/Server/VocaluxeStructs.cs index 21aa8f48..1e826831 100644 --- a/Vocaluxe/Base/Server/VocaluxeStructs.cs +++ b/Vocaluxe/Base/Server/VocaluxeStructs.cs @@ -22,7 +22,7 @@ namespace Vocaluxe.Base.Server public byte[] Sha256; } - public struct SAvatarPicture + public struct SPicture { public int Width; public int Height; @@ -31,7 +31,7 @@ namespace Vocaluxe.Base.Server public struct SProfile { - public SAvatarPicture Avatar; + public SPicture Avatar; public string PlayerName; public int Difficulty; } diff --git a/Vocaluxe/Lib/Playlist/CPlaylistFile.cs b/Vocaluxe/Lib/Playlist/CPlaylistFile.cs index d40234e9..58d2f575 100644 --- a/Vocaluxe/Lib/Playlist/CPlaylistFile.cs +++ b/Vocaluxe/Lib/Playlist/CPlaylistFile.cs @@ -1,18 +1,18 @@ -#region license -// This file is part of Vocaluxe. +#region license +// This file is part of Vocaluxe. // -// Vocaluxe is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// Vocaluxe is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with Vocaluxe. If not, see . +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . #endregion using System; @@ -31,6 +31,7 @@ namespace Vocaluxe.Lib.Playlist { public string PlaylistName; public string PlaylistFile; + public int Id = -1; public List Songs = new List(); public CPlaylistFile() @@ -39,8 +40,9 @@ namespace Vocaluxe.Lib.Playlist PlaylistFile = string.Empty; } - public CPlaylistFile(string file) + public CPlaylistFile(string file, int id) { + Id = id; PlaylistFile = file; _LoadPlaylist(); } @@ -217,7 +219,7 @@ namespace Vocaluxe.Lib.Playlist if (destNr < 0 || destNr > Songs.Count - 1) return; - var ps = new CPlaylistSong(songID, gm); + CPlaylistSong ps = new CPlaylistSong(songID, gm); Songs.Insert(destNr, ps); } } diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj index 17132251..2dec4b8e 100644 --- a/Vocaluxe/Vocaluxe.csproj +++ b/Vocaluxe/Vocaluxe.csproj @@ -1,4 +1,4 @@ - + DebugWin @@ -15,7 +15,8 @@ false Vocaluxe.CMainProgram Vocaluxe.ico - Client + + publish\ true Disk @@ -174,10 +175,6 @@ ..\Output\AForge.Video.DirectShow.dll False - - ..\ClientServerLib\ClientServerLib\bin\ClientServerLib.dll - True - ..\Output\Community.CsharpSqlite.dll @@ -197,6 +194,7 @@ + @@ -306,10 +304,122 @@ + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + images + + + PreserveNewest + + + PreserveNewest + images + + + PreserveNewest + images + + + PreserveNewest + images + + + PreserveNewest + images + + + css + PreserveNewest + + + css + PreserveNewest + + + css + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + img + + + PreserveNewest + img + + + PreserveNewest + img + + + PreserveNewest + img + + + PreserveNewest + img + + + PreserveNewest + + + PreserveNewest + js + + + PreserveNewest + + + js + PreserveNewest + + + PreserveNewest + + + js + PreserveNewest + @@ -324,12 +434,22 @@ + + {ec5167e4-ccfb-4cee-987c-cf816f1062a3} + ServerLib + {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} VocaluxeLib + + + + + xcopy /E /D /Y "$(ProjectDir)\Website" "$(SolutionDir)\PhoneGap" + + +
+ + + +
+
+
+ +
+ + + +
+
+

Login

+
+ + +
+ + + + +
+ +
+
+
+ +
+ +
+ + +
+
+

Volcaluxe

+
+ + + + +
+ + +
+
+

+
+ + +
+
    +
    + +
    + + +
    +
    +

    Profile

    +
    + + +
    + Avatar + + + + + + + + + + + +
    + +
    + +
    + + +
    +
    +

    +
    + + +
    + Cover +
    +
    +
    + + - +
    + + - +
    + + - +
    + + - +
    + + - +
    +
    + + +
    + +
    + + +
    + +
    + + +
    +
    +

    +
    + + +
    +
      +
      + +
      + + +
      +
      +

      +
      + + +
      +
      +
      +
      + +
      +
      +
      + +
      +
      +
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      + +
      + + +
      +
      +

      +
      + + +
      +
        +
        + +
        + + +
        +
        +

        +
        + + +
        +
        + + + + + +
        + +
        + +
        + + +
        +
        +

        + +
        + + +
        +
          +
          + +
          + + +
          +
          +

          + +
          + + +
          +
            +
            + +
            + + +
            + + diff --git a/Vocaluxe/Website/js/i18next-1.7.1.min.js b/Vocaluxe/Website/js/i18next-1.7.1.min.js new file mode 100644 index 00000000..7cf162f8 --- /dev/null +++ b/Vocaluxe/Website/js/i18next-1.7.1.min.js @@ -0,0 +1,5 @@ +// i18next, v1.7.1 +// Copyright (c)2013 Jan Mühlemann (jamuhl). +// Distributed under MIT license +// http://i18next.com +!function(){function a(a,b){if(!b||"function"==typeof b)return a;for(var c in b)a[c]=b[c];return a}function b(a,b,c){var d,e=0,f=a.length,g=void 0===f||"function"==typeof a;if(c)if(g){for(d in a)if(b.apply(a[d],c)===!1)break}else for(;f>e&&b.apply(a[e++],c)!==!1;);else if(g){for(d in a)if(b.call(a[d],d,a[d])===!1)break}else for(;f>e&&b.call(a[e],e,a[e++])!==!1;);return a}function c(a){return"string"==typeof a?a.replace(/[&<>"'\/]/g,function(a){return H[a]}):a}function d(a){var b=function(a){if(window.XMLHttpRequest)return a(null,new XMLHttpRequest);if(window.ActiveXObject)try{return a(null,new ActiveXObject("Msxml2.XMLHTTP"))}catch(b){return a(null,new ActiveXObject("Microsoft.XMLHTTP"))}return a(new Error)},c=function(a){if("string"==typeof a)return a;var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(encodeURIComponent(c)+"="+encodeURIComponent(a[c]));return b.join("&")},d=function(a){a=a.replace(/\r\n/g,"\n");for(var b="",c=0;cd?b+=String.fromCharCode(d):d>127&&2048>d?(b+=String.fromCharCode(192|d>>6),b+=String.fromCharCode(128|63&d)):(b+=String.fromCharCode(224|d>>12),b+=String.fromCharCode(128|63&d>>6),b+=String.fromCharCode(128|63&d))}return b},e=function(a){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";a=d(a);var c,e,f,g,h,i,j,k="",l=0;do c=a.charCodeAt(l++),e=a.charCodeAt(l++),f=a.charCodeAt(l++),g=c>>2,h=(3&c)<<4|e>>4,i=(15&e)<<2|f>>6,j=63&f,isNaN(e)?i=j=64:isNaN(f)&&(j=64),k+=b.charAt(g)+b.charAt(h)+b.charAt(i)+b.charAt(j),c=e=f="",g=h=i=j="";while(l1&&(d+=d.indexOf("?")>-1?"&"+k:"?"+k),e.jsonp){var l=document.getElementsByTagName("head")[0],m=document.createElement("script");return m.type="text/javascript",m.src=d,l.appendChild(m),void 0}}b(function(b,c){if(b)return h(b);c.open(a,d,e.async);for(var f in j)j.hasOwnProperty(f)&&c.setRequestHeader(f,j[f]);c.onreadystatechange=function(){if(4===c.readyState){var a=c.responseText||"";if(!h)return;h(c.status,{text:function(){return a},json:function(){return JSON.parse(a)}})}},c.send(i)})},h={authBasic:function(a,b){g.headers.Authorization="Basic "+e(a+":"+b)},connect:function(a,b,c){return g("CONNECT",a,b,c)},del:function(a,b,c){return g("DELETE",a,b,c)},get:function(a,b,c){return g("GET",a,b,c)},head:function(a,b,c){return g("HEAD",a,b,c)},headers:function(a){g.headers=a||{}},isAllowed:function(a,b,c){this.options(a,function(a,d){c(-1!==d.text().indexOf(b))})},options:function(a,b,c){return g("OPTIONS",a,b,c)},patch:function(a,b,c){return g("PATCH",a,b,c)},post:function(a,b,c){return g("POST",a,b,c)},put:function(a,b,c){return g("PUT",a,b,c)},trace:function(a,b,c){return g("TRACE",a,b,c)}},i=a.type?a.type.toLowerCase():"get";h[i](a.url,a,function(b,c){200===b?a.success(c.json(),b,null):a.error(c.text(),b,null)})}function e(a,b){"function"==typeof a&&(b=a,a={}),a=a||{},K.extend(G,a),delete G.fixLng,"string"==typeof G.ns&&(G.ns={namespaces:[G.ns],defaultNs:G.ns}),"string"==typeof G.fallbackNS&&(G.fallbackNS=[G.fallbackNS]),G.interpolationPrefixEscaped=K.regexEscape(G.interpolationPrefix),G.interpolationSuffixEscaped=K.regexEscape(G.interpolationSuffix),G.lng||(G.lng=K.detectLanguage()),G.lng?G.useCookie&&K.cookie.create(G.cookieName,G.lng,G.cookieExpirationTime,G.cookieDomain):(G.lng=G.fallbackLng,G.useCookie&&K.cookie.remove(G.cookieName)),E=K.toLanguages(G.lng),y=E[0],K.log("currentLng set to: "+y);var c=s;a.fixLng&&(c=function(a,b){return b=b||{},b.lng=b.lng||c.lng,s(a,b)},c.lng=y),M.setCurrentLng(y),A&&G.setJqueryExt&&m();var d;if(A&&A.Deferred&&(d=A.Deferred()),!G.resStore){var e=K.toLanguages(G.lng);"string"==typeof G.preload&&(G.preload=[G.preload]);for(var f=0,g=G.preload.length;g>f;f++)for(var h=K.toLanguages(G.preload[f]),i=0,j=h.length;j>i;i++)e.indexOf(h[i])<0&&e.push(h[i]);return B.sync.load(e,G,function(a,e){C=e,F=!0,b&&b(c),d&&d.resolve(c)}),d?d.promise():void 0}return C=G.resStore,F=!0,b&&b(c),d&&d.resolve(c),d?d.promise():void 0}function f(a,b){"string"==typeof a&&(a=[a]);for(var c=0,d=a.length;d>c;c++)G.preload.indexOf(a[c])<0&&G.preload.push(a[c]);return e(b)}function g(a,b,c){"string"!=typeof b?(c=b,b=G.ns.defaultNs):G.ns.namespaces.indexOf(b)<0&&G.ns.namespaces.push(b),C[a]=C[a]||{},C[a][b]=C[a][b]||{},K.extend(C[a][b],c)}function h(a){G.ns.defaultNs=a}function i(a,b){j([a],b)}function j(a,b){var c={dynamicLoad:G.dynamicLoad,resGetPath:G.resGetPath,getAsync:G.getAsync,customLoad:G.customLoad,ns:{namespaces:a,defaultNs:""}},d=K.toLanguages(G.lng);"string"==typeof G.preload&&(G.preload=[G.preload]);for(var e=0,f=G.preload.length;f>e;e++)for(var g=K.toLanguages(G.preload[e]),h=0,i=g.length;i>h;h++)d.indexOf(g[h])<0&&d.push(g[h]);for(var j=[],k=0,l=d.length;l>k;k++){var m=!1,n=C[d[k]];if(n)for(var o=0,p=a.length;p>o;o++)n[a[o]]||(m=!0);else m=!0;m&&j.push(d[k])}j.length?B.sync._fetch(j,c,function(c,d){var e=a.length*j.length;K.each(a,function(a,c){G.ns.namespaces.indexOf(c)<0&&G.ns.namespaces.push(c),K.each(j,function(a,f){C[f]=C[f]||{},C[f][c]=d[f][c],e--,0===e&&b&&(G.useLocalStorage&&B.sync._storeLocal(C),b())})})}):b&&b()}function k(a,b,c){return"function"==typeof b&&(c=b,b={}),b.lng=a,e(b,c)}function l(){return y}function m(){function a(a,b,c){if(0!==b.length){var d="text";if(0===b.indexOf("[")){var e=b.split("]");b=e[1],d=e[0].substr(1,e[0].length-1)}b.indexOf(";")===b.length-1&&(b=b.substr(0,b.length-2));var f;"html"===d?(f=G.defaultValueFromContent?A.extend({defaultValue:a.html()},c):c,a.html(A.t(b,f))):"text"===d?(f=G.defaultValueFromContent?A.extend({defaultValue:a.text()},c):c,a.text(A.t(b,f))):(f=G.defaultValueFromContent?A.extend({defaultValue:a.attr(d)},c):c,a.attr(d,A.t(b,f)))}}function b(b,c){var d=b.attr(G.selectorAttr);if(d||"undefined"==typeof d||d===!1||(d=b.text()||b.val()),d){var e=b,f=b.data("i18n-target");if(f&&(e=b.find(f)||b),c||G.useDataAttrOptions!==!0||(c=b.data("i18n-options")),c=c||{},d.indexOf(";")>=0){var g=d.split(";");A.each(g,function(b,d){""!==d&&a(e,d,c)})}else a(e,d,c);G.useDataAttrOptions===!0&&b.data("i18n-options",c)}}A.t=A.t||s,A.fn.i18n=function(a){return this.each(function(){b(A(this),a);var c=A(this).find("["+G.selectorAttr+"]");c.each(function(){b(A(this),a)})})}}function n(a,b,c,d){if(!a)return a;if(d=d||b,a.indexOf(d.interpolationPrefix||G.interpolationPrefix)<0)return a;var e=d.interpolationPrefix?K.regexEscape(d.interpolationPrefix):G.interpolationPrefixEscaped,f=d.interpolationSuffix?K.regexEscape(d.interpolationSuffix):G.interpolationSuffixEscaped,g="HTML"+f;return K.each(b,function(b,h){var i=c?c+G.keyseparator+b:b;"object"==typeof h&&null!==h?a=n(a,h,i,d):d.escapeInterpolation||G.escapeInterpolation?(a=a.replace(new RegExp([e,i,g].join(""),"g"),h),a=a.replace(new RegExp([e,i,f].join(""),"g"),K.escape(h))):a=a.replace(new RegExp([e,i,f].join(""),"g"),h)}),a}function o(a,b){var c=",",d="{",e="}",f=K.extend({},b);for(delete f.postProcess;-1!=a.indexOf(G.reusePrefix)&&(D++,!(D>G.maxRecursion));){var g=a.lastIndexOf(G.reusePrefix),h=a.indexOf(G.reuseSuffix,g)+G.reuseSuffix.length,i=a.substring(g,h),j=i.replace(G.reusePrefix,"").replace(G.reuseSuffix,"");if(-1!=j.indexOf(c)){var k=j.indexOf(c);if(-1!=j.indexOf(d,k)&&-1!=j.indexOf(e,k)){var l=j.indexOf(d,k),m=j.indexOf(e,l)+e.length;try{f=K.extend(f,JSON.parse(j.substring(l,m))),j=j.substring(0,k)}catch(n){}}}var o=v(j,f);a=a.replace(i,o)}return a}function p(a){return a.context&&"string"==typeof a.context}function q(a){return void 0!==a.count&&"string"!=typeof a.count&&1!==a.count}function r(a,b){b=b||{};var c=t(a,b),d=w(a,b);return void 0!==d||d===c}function s(a,b){return F?(D=0,v.apply(null,arguments)):(K.log("i18next not finished initialization. you might have called t function before loading resources finished."),b.defaultValue||"")}function t(a,b){return void 0!==b.defaultValue?b.defaultValue:a}function u(){for(var a=[],b=1;b-1&&(e=c.split(G.nsseparator),i=e[0],c=e[1]),void 0===g&&G.sendMissing&&(b.lng?L.postMissing(h[0],i,c,f,h):L.postMissing(G.lng,i,c,f,h));var j=b.postProcess||G.postProcess;void 0!==g&&j&&N[j]&&(g=N[j](g,c,b));var k=f;if(f.indexOf(G.nsseparator)>-1&&(e=f.split(G.nsseparator),k=e[1]),k===c&&G.parseMissingKey&&(f=G.parseMissingKey(f)),void 0===g&&(f=n(f,b),f=o(f,b),j&&N[j])){var l=t(c,b);g=N[j](l,c,b)}return void 0!==g?g:f}function w(a,b){b=b||{};var c,d,e=t(a,b),f=E;if(!C)return e;if(b.lng&&(f=K.toLanguages(b.lng),!C[f[0]])){var g=G.getAsync;G.getAsync=!1,B.sync.load(f,G,function(a,b){K.extend(C,b),G.getAsync=g})}var h=b.ns||G.ns.defaultNs;if(a.indexOf(G.nsseparator)>-1){var i=a.split(G.nsseparator);h=i[0],a=i[1]}if(p(b)){c=K.extend({},b),delete c.context,c.defaultValue=G.contextNotFound;var j=h+G.nsseparator+a+"_"+b.context;if(d=s(j,c),d!=G.contextNotFound)return n(d,{context:b.context})}if(q(b)){c=K.extend({},b),delete c.count,c.defaultValue=G.pluralNotFound;var k=h+G.nsseparator+a+G.pluralSuffix,l=M.get(f[0],b.count);if(l>=0?k=k+"_"+l:1===l&&(k=h+G.nsseparator+a),d=s(k,c),d!=G.pluralNotFound)return n(d,{count:b.count,interpolationPrefix:b.interpolationPrefix,interpolationSuffix:b.interpolationSuffix})}for(var m,r=a.split(G.keyseparator),u=0,x=f.length;x>u&&void 0===m;u++){for(var y=f[u],z=0,A=C[y]&&C[y][h];r[z];)A=A&&A[r[z]],z++;if(void 0!==A){if("string"==typeof A)A=n(A,b),A=o(A,b);else if("[object Array]"!==Object.prototype.toString.apply(A)||G.returnObjectTrees||b.returnObjectTrees){if(null===A&&G.fallbackOnNull===!0)A=void 0;else if(null!==A)if(G.returnObjectTrees||b.returnObjectTrees){if("number"!=typeof A){var D={};K.each(A,function(c){D[c]=v(h+G.nsseparator+a+G.keyseparator+c,b)}),A=D}}else A="key '"+h+":"+a+" ("+y+")' "+"returned a object instead of string.",K.log(A)}else A=A.join("\n"),A=n(A,b),A=o(A,b);m=A}}if(void 0===m&&!b.isFallbackLookup&&(G.fallbackToDefaultNS===!0||G.fallbackNS&&G.fallbackNS.length>0))if(b.isFallbackLookup=!0,G.fallbackNS.length){for(var F=0,H=G.fallbackNS.length;H>F;F++)if(m=w(G.fallbackNS[F]+G.nsseparator+a,b)){var I=m.indexOf(G.nsseparator)>-1?m.split(G.nsseparator)[1]:m,J=e.indexOf(G.nsseparator)>-1?e.split(G.nsseparator)[1]:e;if(I!==J)break}}else m=w(a,b);return m}function x(){var a,b=[];if("undefined"!=typeof window&&(!function(){for(var a=window.location.search.substring(1),c=a.split("&"),d=0;d0){var f=c[d].substring(0,e),g=c[d].substring(e+1);b[f]=g}}}(),b[G.detectLngQS]&&(a=b[G.detectLngQS])),!a&&"undefined"!=typeof document&&G.useCookie){var c=K.cookie.read(G.cookieName);c&&(a=c)}return a||"undefined"==typeof navigator||(a=navigator.language?navigator.language:navigator.userLanguage),a}Array.prototype.indexOf||(Array.prototype.indexOf=function(a){"use strict";if(null==this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=0;if(arguments.length>0&&(d=Number(arguments[1]),d!=d?d=0:0!=d&&1/0!=d&&d!=-1/0&&(d=(d>0||-1)*Math.floor(Math.abs(d)))),d>=c)return-1;for(var e=d>=0?d:Math.max(c-Math.abs(d),0);c>e;e++)if(e in b&&b[e]===a)return e;return-1}),Array.prototype.lastIndexOf||(Array.prototype.lastIndexOf=function(a){"use strict";if(null==this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=c;arguments.length>1&&(d=Number(arguments[1]),d!=d?d=0:0!=d&&d!=1/0&&d!=-(1/0)&&(d=(d>0||-1)*Math.floor(Math.abs(d))));for(var e=d>=0?Math.min(d,c-1):c-Math.abs(d);e>=0;e--)if(e in b&&b[e]===a)return e;return-1});var y,z=this,A=z.jQuery||z.Zepto,B={},C={},D=0,E=[],F=!1;"undefined"!=typeof module&&module.exports?module.exports=B:(A&&(A.i18n=A.i18n||B),z.i18n=z.i18n||B);var G={lng:void 0,load:"all",preload:[],lowerCaseLng:!1,returnObjectTrees:!1,fallbackLng:"dev",fallbackNS:[],detectLngQS:"setLng",ns:"translation",fallbackOnNull:!0,fallbackToDefaultNS:!1,nsseparator:":",keyseparator:".",selectorAttr:"data-i18n",debug:!1,resGetPath:"locales/__lng__/__ns__.json",resPostPath:"locales/add/__lng__/__ns__",getAsync:!0,postAsync:!0,resStore:void 0,useLocalStorage:!1,localStorageExpirationTime:6048e5,dynamicLoad:!1,sendMissing:!1,sendMissingTo:"fallback",sendType:"POST",interpolationPrefix:"__",interpolationSuffix:"__",reusePrefix:"$t(",reuseSuffix:")",pluralSuffix:"_plural",pluralNotFound:["plural_not_found",Math.random()].join(""),contextNotFound:["context_not_found",Math.random()].join(""),escapeInterpolation:!1,setJqueryExt:!0,defaultValueFromContent:!0,useDataAttrOptions:!1,cookieExpirationTime:void 0,useCookie:!0,cookieName:"i18next",cookieDomain:void 0,postProcess:void 0,parseMissingKey:void 0,shortcutFunction:"sprintf"},H={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},I={create:function(a,b,c,d){var e;if(c){var f=new Date;f.setTime(f.getTime()+1e3*60*c),e="; expires="+f.toGMTString()}else e="";d=d?"domain="+d+";":"",document.cookie=a+"="+b+e+";"+d+"path=/"},read:function(a){for(var b=a+"=",c=document.cookie.split(";"),d=0;d-1){var c=a.split("-");a=G.lowerCaseLng?c[0].toLowerCase()+"-"+c[1].toLowerCase():c[0].toLowerCase()+"-"+c[1].toUpperCase(),"unspecific"!==G.load&&b.push(a),"current"!==G.load&&b.push(c[0])}else b.push(a);return-1===b.indexOf(G.fallbackLng)&&G.fallbackLng&&b.push(G.fallbackLng),b},regexEscape:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}};K.applyReplacement=n;var L={load:function(a,b,c){b.useLocalStorage?L._loadLocal(a,b,function(d,e){for(var f=[],g=0,h=a.length;h>g;g++)e[a[g]]||f.push(a[g]);f.length>0?L._fetch(f,b,function(a,b){K.extend(e,b),L._storeLocal(b),c(null,e)}):c(null,e)}):L._fetch(a,b,function(a,b){c(null,b)})},_loadLocal:function(a,b,c){var d={},e=(new Date).getTime();if(window.localStorage){var f=a.length;K.each(a,function(a,g){var h=window.localStorage.getItem("res_"+g);h&&(h=JSON.parse(h),h.i18nStamp&&h.i18nStamp+b.localStorageExpirationTime>e&&(d[g]=h)),f--,0===f&&c(null,d)})}},_storeLocal:function(a){if(window.localStorage)for(var b in a)a[b].i18nStamp=(new Date).getTime(),window.localStorage.setItem("res_"+b,JSON.stringify(a[b]))},_fetch:function(a,b,c){var d=b.ns,e={};if(b.dynamicLoad){var f=function(a,b){c(null,b)};if("function"==typeof b.customLoad)b.customLoad(a,d.namespaces,b,f);else{var g=n(b.resGetPath,{lng:a.join("+"),ns:d.namespaces.join("+")});K.ajax({url:g,success:function(a){K.log("loaded: "+g),f(null,a)},error:function(a,b,c){K.log("failed loading: "+g),f("failed loading resource.json error: "+c)},dataType:"json",async:b.getAsync})}}else{var h,i=d.namespaces.length*a.length;K.each(d.namespaces,function(d,f){K.each(a,function(a,d){var g=function(a,b){a&&(h=h||[],h.push(a)),e[d]=e[d]||{},e[d][f]=b,i--,0===i&&c(h,e)};"function"==typeof b.customLoad?b.customLoad(d,f,b,g):L._fetchOne(d,f,b,g)})})}},_fetchOne:function(a,b,c,d){var e=n(c.resGetPath,{lng:a,ns:b});K.ajax({url:e,success:function(a){K.log("loaded: "+e),d(null,a)},error:function(a,b,c){K.log("failed loading: "+e),d(c,{})},dataType:"json",async:c.getAsync})},postMissing:function(a,b,c,d,e){var f={};f[c]=d;var g=[];if("fallback"===G.sendMissingTo&&G.fallbackLng!==!1)g.push({lng:G.fallbackLng,url:n(G.resPostPath,{lng:G.fallbackLng,ns:b})});else if("current"===G.sendMissingTo||"fallback"===G.sendMissingTo&&G.fallbackLng===!1)g.push({lng:a,url:n(G.resPostPath,{lng:a,ns:b})});else if("all"===G.sendMissingTo)for(var h=0,i=e.length;i>h;h++)g.push({lng:e[h],url:n(G.resPostPath,{lng:e[h],ns:b})});for(var j=0,k=g.length;k>j;j++){var l=g[j];K.ajax({url:l.url,type:G.sendType,data:f,success:function(){K.log("posted missing key '"+c+"' to: "+l.url);for(var a=c.split("."),e=0,f=C[l.lng][b];a[e];)f=f[a[e]]=e===a.length-1?d:f[a[e]]||{},e++},error:function(){K.log("failed posting missing key '"+c+"' to: "+l.url)},dataType:"json",async:G.postAsync})}}},M={rules:{ach:{name:"Acholi",numbers:[1,2],plurals:function(a){return Number(a>1)}},af:{name:"Afrikaans",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ak:{name:"Akan",numbers:[1,2],plurals:function(a){return Number(a>1)}},am:{name:"Amharic",numbers:[1,2],plurals:function(a){return Number(a>1)}},an:{name:"Aragonese",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ar:{name:"Arabic",numbers:[0,1,2,3,11,100],plurals:function(a){return Number(0===a?0:1==a?1:2==a?2:a%100>=3&&10>=a%100?3:a%100>=11?4:5)}},arn:{name:"Mapudungun",numbers:[1,2],plurals:function(a){return Number(a>1)}},ast:{name:"Asturian",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ay:{name:"Aymará",numbers:[1],plurals:function(){return 0}},az:{name:"Azerbaijani",numbers:[1,2],plurals:function(a){return Number(1!=a)}},be:{name:"Belarusian",numbers:[1,2,5],plurals:function(a){return Number(1==a%10&&11!=a%100?0:a%10>=2&&4>=a%10&&(10>a%100||a%100>=20)?1:2)}},bg:{name:"Bulgarian",numbers:[1,2],plurals:function(a){return Number(1!=a)}},bn:{name:"Bengali",numbers:[1,2],plurals:function(a){return Number(1!=a)}},bo:{name:"Tibetan",numbers:[1],plurals:function(){return 0}},br:{name:"Breton",numbers:[1,2],plurals:function(a){return Number(a>1)}},bs:{name:"Bosnian",numbers:[1,2,5],plurals:function(a){return Number(1==a%10&&11!=a%100?0:a%10>=2&&4>=a%10&&(10>a%100||a%100>=20)?1:2)}},ca:{name:"Catalan",numbers:[1,2],plurals:function(a){return Number(1!=a)}},cgg:{name:"Chiga",numbers:[1],plurals:function(){return 0}},cs:{name:"Czech",numbers:[1,2,5],plurals:function(a){return Number(1==a?0:a>=2&&4>=a?1:2)}},csb:{name:"Kashubian",numbers:[1,2,5],plurals:function(a){return Number(1==a?0:a%10>=2&&4>=a%10&&(10>a%100||a%100>=20)?1:2)}},cy:{name:"Welsh",numbers:[1,2,3,8],plurals:function(a){return Number(1==a?0:2==a?1:8!=a&&11!=a?2:3)}},da:{name:"Danish",numbers:[1,2],plurals:function(a){return Number(1!=a)}},de:{name:"German",numbers:[1,2],plurals:function(a){return Number(1!=a)}},dz:{name:"Dzongkha",numbers:[1],plurals:function(){return 0}},el:{name:"Greek",numbers:[1,2],plurals:function(a){return Number(1!=a)}},en:{name:"English",numbers:[1,2],plurals:function(a){return Number(1!=a)}},eo:{name:"Esperanto",numbers:[1,2],plurals:function(a){return Number(1!=a)}},es:{name:"Spanish",numbers:[1,2],plurals:function(a){return Number(1!=a)}},es_ar:{name:"Argentinean Spanish",numbers:[1,2],plurals:function(a){return Number(1!=a)}},et:{name:"Estonian",numbers:[1,2],plurals:function(a){return Number(1!=a)}},eu:{name:"Basque",numbers:[1,2],plurals:function(a){return Number(1!=a)}},fa:{name:"Persian",numbers:[1],plurals:function(){return 0}},fi:{name:"Finnish",numbers:[1,2],plurals:function(a){return Number(1!=a)}},fil:{name:"Filipino",numbers:[1,2],plurals:function(a){return Number(a>1)}},fo:{name:"Faroese",numbers:[1,2],plurals:function(a){return Number(1!=a)}},fr:{name:"French",numbers:[1,2],plurals:function(a){return Number(a>1)}},fur:{name:"Friulian",numbers:[1,2],plurals:function(a){return Number(1!=a)}},fy:{name:"Frisian",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ga:{name:"Irish",numbers:[1,2,3,7,11],plurals:function(a){return Number(1==a?0:2==a?1:7>a?2:11>a?3:4)}},gd:{name:"Scottish Gaelic",numbers:[1,2,3,20],plurals:function(a){return Number(1==a||11==a?0:2==a||12==a?1:a>2&&20>a?2:3)}},gl:{name:"Galician",numbers:[1,2],plurals:function(a){return Number(1!=a)}},gu:{name:"Gujarati",numbers:[1,2],plurals:function(a){return Number(1!=a)}},gun:{name:"Gun",numbers:[1,2],plurals:function(a){return Number(a>1)}},ha:{name:"Hausa",numbers:[1,2],plurals:function(a){return Number(1!=a)}},he:{name:"Hebrew",numbers:[1,2],plurals:function(a){return Number(1!=a)}},hi:{name:"Hindi",numbers:[1,2],plurals:function(a){return Number(1!=a)}},hr:{name:"Croatian",numbers:[1,2,5],plurals:function(a){return Number(1==a%10&&11!=a%100?0:a%10>=2&&4>=a%10&&(10>a%100||a%100>=20)?1:2)}},hu:{name:"Hungarian",numbers:[1,2],plurals:function(a){return Number(1!=a)}},hy:{name:"Armenian",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ia:{name:"Interlingua",numbers:[1,2],plurals:function(a){return Number(1!=a)}},id:{name:"Indonesian",numbers:[1],plurals:function(){return 0}},is:{name:"Icelandic",numbers:[1,2],plurals:function(a){return Number(1!=a%10||11==a%100)}},it:{name:"Italian",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ja:{name:"Japanese",numbers:[1],plurals:function(){return 0}},jbo:{name:"Lojban",numbers:[1],plurals:function(){return 0}},jv:{name:"Javanese",numbers:[0,1],plurals:function(a){return Number(0!==a)}},ka:{name:"Georgian",numbers:[1],plurals:function(){return 0}},kk:{name:"Kazakh",numbers:[1],plurals:function(){return 0}},km:{name:"Khmer",numbers:[1],plurals:function(){return 0}},kn:{name:"Kannada",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ko:{name:"Korean",numbers:[1],plurals:function(){return 0}},ku:{name:"Kurdish",numbers:[1,2],plurals:function(a){return Number(1!=a)}},kw:{name:"Cornish",numbers:[1,2,3,4],plurals:function(a){return Number(1==a?0:2==a?1:3==a?2:3)}},ky:{name:"Kyrgyz",numbers:[1],plurals:function(){return 0}},lb:{name:"Letzeburgesch",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ln:{name:"Lingala",numbers:[1,2],plurals:function(a){return Number(a>1)}},lo:{name:"Lao",numbers:[1],plurals:function(){return 0}},lt:{name:"Lithuanian",numbers:[1,2,10],plurals:function(a){return Number(1==a%10&&11!=a%100?0:a%10>=2&&(10>a%100||a%100>=20)?1:2)}},lv:{name:"Latvian",numbers:[0,1,2],plurals:function(a){return Number(1==a%10&&11!=a%100?0:0!==a?1:2)}},mai:{name:"Maithili",numbers:[1,2],plurals:function(a){return Number(1!=a)}},mfe:{name:"Mauritian Creole",numbers:[1,2],plurals:function(a){return Number(a>1)}},mg:{name:"Malagasy",numbers:[1,2],plurals:function(a){return Number(a>1)}},mi:{name:"Maori",numbers:[1,2],plurals:function(a){return Number(a>1)}},mk:{name:"Macedonian",numbers:[1,2],plurals:function(a){return Number(1==a||1==a%10?0:1)}},ml:{name:"Malayalam",numbers:[1,2],plurals:function(a){return Number(1!=a)}},mn:{name:"Mongolian",numbers:[1,2],plurals:function(a){return Number(1!=a)}},mnk:{name:"Mandinka",numbers:[0,1,2],plurals:function(a){return Number(1==a?1:2)}},mr:{name:"Marathi",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ms:{name:"Malay",numbers:[1],plurals:function(){return 0}},mt:{name:"Maltese",numbers:[1,2,11,20],plurals:function(a){return Number(1==a?0:0===a||a%100>1&&11>a%100?1:a%100>10&&20>a%100?2:3)}},nah:{name:"Nahuatl",numbers:[1,2],plurals:function(a){return Number(1!=a)}},nap:{name:"Neapolitan",numbers:[1,2],plurals:function(a){return Number(1!=a)}},nb:{name:"Norwegian Bokmal",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ne:{name:"Nepali",numbers:[1,2],plurals:function(a){return Number(1!=a)}},nl:{name:"Dutch",numbers:[1,2],plurals:function(a){return Number(1!=a)}},nn:{name:"Norwegian Nynorsk",numbers:[1,2],plurals:function(a){return Number(1!=a)}},no:{name:"Norwegian",numbers:[1,2],plurals:function(a){return Number(1!=a)}},nso:{name:"Northern Sotho",numbers:[1,2],plurals:function(a){return Number(1!=a)}},oc:{name:"Occitan",numbers:[1,2],plurals:function(a){return Number(a>1)}},or:{name:"Oriya",numbers:[2,1],plurals:function(a){return Number(1!=a)}},pa:{name:"Punjabi",numbers:[1,2],plurals:function(a){return Number(1!=a)}},pap:{name:"Papiamento",numbers:[1,2],plurals:function(a){return Number(1!=a)}},pl:{name:"Polish",numbers:[1,2,5],plurals:function(a){return Number(1==a?0:a%10>=2&&4>=a%10&&(10>a%100||a%100>=20)?1:2)}},pms:{name:"Piemontese",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ps:{name:"Pashto",numbers:[1,2],plurals:function(a){return Number(1!=a)}},pt:{name:"Portuguese",numbers:[1,2],plurals:function(a){return Number(1!=a)}},pt_br:{name:"Brazilian Portuguese",numbers:[1,2],plurals:function(a){return Number(1!=a)}},rm:{name:"Romansh",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ro:{name:"Romanian",numbers:[1,2,20],plurals:function(a){return Number(1==a?0:0===a||a%100>0&&20>a%100?1:2)}},ru:{name:"Russian",numbers:[1,2,5],plurals:function(a){return Number(1==a%10&&11!=a%100?0:a%10>=2&&4>=a%10&&(10>a%100||a%100>=20)?1:2)}},sah:{name:"Yakut",numbers:[1],plurals:function(){return 0}},sco:{name:"Scots",numbers:[1,2],plurals:function(a){return Number(1!=a)}},se:{name:"Northern Sami",numbers:[1,2],plurals:function(a){return Number(1!=a)}},si:{name:"Sinhala",numbers:[1,2],plurals:function(a){return Number(1!=a)}},sk:{name:"Slovak",numbers:[1,2,5],plurals:function(a){return Number(1==a?0:a>=2&&4>=a?1:2)}},sl:{name:"Slovenian",numbers:[5,1,2,3],plurals:function(a){return Number(1==a%100?1:2==a%100?2:3==a%100||4==a%100?3:0)}},so:{name:"Somali",numbers:[1,2],plurals:function(a){return Number(1!=a)}},son:{name:"Songhay",numbers:[1,2],plurals:function(a){return Number(1!=a)}},sq:{name:"Albanian",numbers:[1,2],plurals:function(a){return Number(1!=a)}},sr:{name:"Serbian",numbers:[1,2,5],plurals:function(a){return Number(1==a%10&&11!=a%100?0:a%10>=2&&4>=a%10&&(10>a%100||a%100>=20)?1:2)}},su:{name:"Sundanese",numbers:[1],plurals:function(){return 0}},sv:{name:"Swedish",numbers:[1,2],plurals:function(a){return Number(1!=a)}},sw:{name:"Swahili",numbers:[1,2],plurals:function(a){return Number(1!=a)}},ta:{name:"Tamil",numbers:[1,2],plurals:function(a){return Number(1!=a)}},te:{name:"Telugu",numbers:[1,2],plurals:function(a){return Number(1!=a)}},tg:{name:"Tajik",numbers:[1,2],plurals:function(a){return Number(a>1)}},th:{name:"Thai",numbers:[1],plurals:function(){return 0}},ti:{name:"Tigrinya",numbers:[1,2],plurals:function(a){return Number(a>1)}},tk:{name:"Turkmen",numbers:[1,2],plurals:function(a){return Number(1!=a)}},tr:{name:"Turkish",numbers:[1,2],plurals:function(a){return Number(a>1)}},tt:{name:"Tatar",numbers:[1],plurals:function(){return 0}},ug:{name:"Uyghur",numbers:[1],plurals:function(){return 0}},uk:{name:"Ukrainian",numbers:[1,2,5],plurals:function(a){return Number(1==a%10&&11!=a%100?0:a%10>=2&&4>=a%10&&(10>a%100||a%100>=20)?1:2)}},ur:{name:"Urdu",numbers:[1,2],plurals:function(a){return Number(1!=a)}},uz:{name:"Uzbek",numbers:[1,2],plurals:function(a){return Number(a>1)}},vi:{name:"Vietnamese",numbers:[1],plurals:function(){return 0}},wa:{name:"Walloon",numbers:[1,2],plurals:function(a){return Number(a>1)}},wo:{name:"Wolof",numbers:[1],plurals:function(){return 0}},yo:{name:"Yoruba",numbers:[1,2],plurals:function(a){return Number(1!=a)}},zh:{name:"Chinese",numbers:[1],plurals:function(){return 0}}},addRule:function(a,b){M.rules[a]=b},setCurrentLng:function(a){if(!M.currentRule||M.currentRule.lng!==a){var b=a.split("-");M.currentRule={lng:a,rule:M.rules[b[0]]}}},get:function(a,b){function c(b,c){var d;if(d=M.currentRule&&M.currentRule.lng===a?M.currentRule.rule:M.rules[b]){var e=d.plurals(c),f=d.numbers[e];return 2===d.numbers.length&&1===d.numbers[0]&&(2===f?f=-1:1===f&&(f=1)),f}return 1===c?"1":"-1"}var d=a.split("-");return c(d[0],b)}},N={},O=function(a,b){N[a]=b},P=function(){function a(a){return Object.prototype.toString.call(a).slice(8,-1).toLowerCase()}function b(a,b){for(var c=[];b>0;c[--b]=a);return c.join("")}var c=function(){return c.cache.hasOwnProperty(arguments[0])||(c.cache[arguments[0]]=c.parse(arguments[0])),c.format.call(null,c.cache[arguments[0]],arguments)};return c.format=function(c,d){var e,f,g,h,i,j,k,l=1,m=c.length,n="",o=[];for(f=0;m>f;f++)if(n=a(c[f]),"string"===n)o.push(c[f]);else if("array"===n){if(h=c[f],h[2])for(e=d[l],g=0;g=0?"+"+e:e,j=h[4]?"0"==h[4]?"0":h[4].charAt(1):" ",k=h[6]-String(e).length,i=h[6]?b(j,k):"",o.push(h[5]?e+i:i+e)}return o.join("")},c.cache={},c.parse=function(a){for(var b=a,c=[],d=[],e=0;b;){if(null!==(c=/^[^\x25]+/.exec(b)))d.push(c[0]);else if(null!==(c=/^\x25{2}/.exec(b)))d.push("%");else{if(null===(c=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(b)))throw"[sprintf] huh?";if(c[2]){e|=1;var f=[],g=c[2],h=[];if(null===(h=/^([a-z_][a-z_\d]*)/i.exec(g)))throw"[sprintf] huh?";for(f.push(h[1]);""!==(g=g.substring(h[0].length));)if(null!==(h=/^\.([a-z_][a-z_\d]*)/i.exec(g)))f.push(h[1]);else{if(null===(h=/^\[(\d+)\]/.exec(g)))throw"[sprintf] huh?";f.push(h[1])}c[2]=f}else e|=2;if(3===e)throw"[sprintf] mixing positional and named placeholders is not (yet) supported";d.push(c)}b=b.substring(c[0].length)}return d},c}(),Q=function(a,b){return b.unshift(a),P.apply(null,b)};O("sprintf",function(a,b,c){return c.sprintf?"[object Array]"===Object.prototype.toString.apply(c.sprintf)?Q(a,c.sprintf):"object"==typeof c.sprintf?P(a,c.sprintf):a:a}),B.init=e,B.setLng=k,B.preload=f,B.addResourceBundle=g,B.loadNamespace=i,B.loadNamespaces=j,B.setDefaultNamespace=h,B.t=s,B.translate=s,B.exists=r,B.detectLanguage=K.detectLanguage,B.pluralExtensions=M,B.sync=L,B.functions=K,B.lng=l,B.addPostProcessor=O,B.options=G}(); \ No newline at end of file diff --git a/Vocaluxe/Website/js/jquery-1.9.1.min.js b/Vocaluxe/Website/js/jquery-1.9.1.min.js new file mode 100644 index 00000000..006e9531 --- /dev/null +++ b/Vocaluxe/Website/js/jquery-1.9.1.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery.min.map +*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
            a",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="
            t
            ",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
            ",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj; +return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="
            ",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&>(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
            ","
            "],area:[1,"",""],param:[1,"",""],thead:[1,"","
            "],tr:[2,"","
            "],col:[2,"","
            "],td:[3,"","
            "],_default:b.support.htmlSerialize?[0,"",""]:[1,"X
            ","
            "]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l) +}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("