From 85f803239567ad9524c32ecd532bb91c2b447bc0 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Thu, 4 Jul 2019 20:00:49 +0300 Subject: [PATCH 001/554] optimize of NetPacketProcessor. --- LiteNetLib/Utils/NetPacketProcessor.cs | 58 ++++++++++---------- LiteNetLibSampleUnity/Assets/LiteNetLib.dll | Bin 93696 -> 93184 bytes 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/LiteNetLib/Utils/NetPacketProcessor.cs b/LiteNetLib/Utils/NetPacketProcessor.cs index 852b0f6a..2a4bb5d5 100644 --- a/LiteNetLib/Utils/NetPacketProcessor.cs +++ b/LiteNetLib/Utils/NetPacketProcessor.cs @@ -5,8 +5,13 @@ namespace LiteNetLib.Utils { public class NetPacketProcessor { + private static class HashCache + { + public static bool Initialized; + public static ulong Id; + } + protected delegate void SubscribeDelegate(NetDataReader reader, object userData); - private readonly Dictionary _hashCache = new Dictionary(); private readonly char[] _hashBuffer = new char[1024]; private readonly NetSerializer _netSerializer; private readonly Dictionary _callbacks = new Dictionary(); @@ -23,22 +28,21 @@ public NetPacketProcessor(int maxStringLength) } //FNV-1 64 bit hash - protected virtual ulong GetHash(Type type) + protected virtual ulong GetHash() { - ulong hash; - string typeName = type.FullName; - if (_hashCache.TryGetValue(typeName, out hash)) - { - return hash; - } - hash = 14695981039346656037UL; //offset + if(HashCache.Initialized) + return HashCache.Id; + + ulong hash = 14695981039346656037UL; //offset + string typeName = typeof(T).FullName; typeName.CopyTo(0, _hashBuffer, 0, typeName.Length); for (var i = 0; i < typeName.Length; i++) { hash = hash ^ _hashBuffer[i]; hash *= 1099511628211UL; //prime } - _hashCache.Add(typeName, hash); + HashCache.Initialized = true; + HashCache.Id = hash; return hash; } @@ -53,9 +57,9 @@ protected virtual SubscribeDelegate GetCallbackFromData(NetDataReader reader) return action; } - protected virtual void WriteHash(Type type, NetDataWriter writer) + protected virtual void WriteHash(NetDataWriter writer) { - writer.Put(GetHash(type)); + writer.Put(GetHash()); } /// @@ -96,9 +100,7 @@ public bool RegisterNestedType(Func constructor) where T : class, INetSeri public void ReadAllPackets(NetDataReader reader) { while (reader.AvailableBytes > 0) - { ReadPacket(reader); - } } /// @@ -110,9 +112,7 @@ public void ReadAllPackets(NetDataReader reader) public void ReadAllPackets(NetDataReader reader, object userData) { while (reader.AvailableBytes > 0) - { ReadPacket(reader, userData); - } } /// @@ -155,20 +155,20 @@ public void SendNetSerializable(NetManager manager, T packet, DeliveryMethod public void Write(NetDataWriter writer, T packet) where T : class, new() { - WriteHash(typeof(T), writer); + WriteHash(writer); _netSerializer.Serialize(writer, packet); } public void WriteNetSerializable(NetDataWriter writer, T packet) where T : INetSerializable { - WriteHash(typeof(T), writer); + WriteHash(writer); packet.Serialize(writer); } public byte[] Write(T packet) where T : class, new() { _netDataWriter.Reset(); - WriteHash(typeof(T), _netDataWriter); + WriteHash(_netDataWriter); _netSerializer.Serialize(_netDataWriter, packet); return _netDataWriter.CopyData(); } @@ -176,7 +176,7 @@ public void WriteNetSerializable(NetDataWriter writer, T packet) where T : IN public byte[] WriteNetSerializable(T packet) where T : INetSerializable { _netDataWriter.Reset(); - WriteHash(typeof(T), _netDataWriter); + WriteHash(_netDataWriter); packet.Serialize(_netDataWriter); return _netDataWriter.CopyData(); } @@ -201,7 +201,7 @@ public void ReadPacket(NetDataReader reader, object userData) public void Subscribe(Action onReceive, Func packetConstructor) where T : class, new() { _netSerializer.Register(); - _callbacks[GetHash(typeof(T))] = (reader, userData) => + _callbacks[GetHash()] = (reader, userData) => { var reference = packetConstructor(); _netSerializer.Deserialize(reader, reference); @@ -218,7 +218,7 @@ public void ReadPacket(NetDataReader reader, object userData) public void Subscribe(Action onReceive, Func packetConstructor) where T : class, new() { _netSerializer.Register(); - _callbacks[GetHash(typeof(T))] = (reader, userData) => + _callbacks[GetHash()] = (reader, userData) => { var reference = packetConstructor(); _netSerializer.Deserialize(reader, reference); @@ -236,7 +236,7 @@ public void ReadPacket(NetDataReader reader, object userData) { _netSerializer.Register(); var reference = new T(); - _callbacks[GetHash(typeof(T))] = (reader, userData) => + _callbacks[GetHash()] = (reader, userData) => { _netSerializer.Deserialize(reader, reference); onReceive(reference); @@ -253,7 +253,7 @@ public void ReadPacket(NetDataReader reader, object userData) { _netSerializer.Register(); var reference = new T(); - _callbacks[GetHash(typeof(T))] = (reader, userData) => + _callbacks[GetHash()] = (reader, userData) => { _netSerializer.Deserialize(reader, reference); onReceive(reference, (TUserData)userData); @@ -264,7 +264,7 @@ public void SubscribeNetSerializable( Action onReceive, Func packetConstructor) where T : INetSerializable { - _callbacks[GetHash(typeof(T))] = (reader, userData) => + _callbacks[GetHash()] = (reader, userData) => { var pkt = packetConstructor(); pkt.Deserialize(reader); @@ -276,7 +276,7 @@ public void SubscribeNetSerializable( Action onReceive, Func packetConstructor) where T : INetSerializable { - _callbacks[GetHash(typeof(T))] = (reader, userData) => + _callbacks[GetHash()] = (reader, userData) => { var pkt = packetConstructor(); pkt.Deserialize(reader); @@ -288,7 +288,7 @@ public void SubscribeNetSerializable( Action onReceive) where T : INetSerializable, new() { var reference = new T(); - _callbacks[GetHash(typeof(T))] = (reader, userData) => + _callbacks[GetHash()] = (reader, userData) => { reference.Deserialize(reader); onReceive(reference, (TUserData)userData); @@ -299,7 +299,7 @@ public void SubscribeNetSerializable( Action onReceive) where T : INetSerializable, new() { var reference = new T(); - _callbacks[GetHash(typeof(T))] = (reader, userData) => + _callbacks[GetHash()] = (reader, userData) => { reference.Deserialize(reader); onReceive(reference); @@ -313,7 +313,7 @@ public void SubscribeNetSerializable( /// true if remove is success public bool RemoveSubscription() { - return _callbacks.Remove(GetHash(typeof(T))); + return _callbacks.Remove(GetHash()); } } } diff --git a/LiteNetLibSampleUnity/Assets/LiteNetLib.dll b/LiteNetLibSampleUnity/Assets/LiteNetLib.dll index eee0a9737a9be09c0e57d54cf00588204ef1f786..3423284585df79a4454a22c7f04896b691dc11fc 100644 GIT binary patch delta 39452 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 F>;S~99Mk{+ From 086987bbeae74ab9c22b6dc17d07a8cc16e4bbf1 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Thu, 4 Jul 2019 20:03:26 +0300 Subject: [PATCH 002/554] more optimisations --- LiteNetLib/Utils/NetPacketProcessor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/LiteNetLib/Utils/NetPacketProcessor.cs b/LiteNetLib/Utils/NetPacketProcessor.cs index 2a4bb5d5..f5a78442 100644 --- a/LiteNetLib/Utils/NetPacketProcessor.cs +++ b/LiteNetLib/Utils/NetPacketProcessor.cs @@ -12,7 +12,6 @@ private static class HashCache } protected delegate void SubscribeDelegate(NetDataReader reader, object userData); - private readonly char[] _hashBuffer = new char[1024]; private readonly NetSerializer _netSerializer; private readonly Dictionary _callbacks = new Dictionary(); private readonly NetDataWriter _netDataWriter = new NetDataWriter(); @@ -35,10 +34,9 @@ protected virtual ulong GetHash() ulong hash = 14695981039346656037UL; //offset string typeName = typeof(T).FullName; - typeName.CopyTo(0, _hashBuffer, 0, typeName.Length); for (var i = 0; i < typeName.Length; i++) { - hash = hash ^ _hashBuffer[i]; + hash = hash ^ typeName[i]; hash *= 1099511628211UL; //prime } HashCache.Initialized = true; From 2b7350ab203dfe805b244d313e42de6bc00f0a6d Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Tue, 9 Jul 2019 20:25:17 +0300 Subject: [PATCH 003/554] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4bed5ce0..6bb604b6 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Lite reliable UDP library for .NET Framework 3.5, Mono, .NET Core 2.0, .NET Stan ( Warning! Master branch can be unstable! ) ### Donations are welcome and will help further development of this project. -[![Bountysource](https://img.shields.io/badge/bountysource-donate-green.svg)](https://salt.bountysource.com/checkout/amount?team=litenetlib) +[![](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=G9PDX5KLGKBA2¤cy_code=USD&source=url) ## Features From aac983810ef20650176015e95be252ee6573350e Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Tue, 9 Jul 2019 20:50:54 +0300 Subject: [PATCH 004/554] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6bb604b6..4bed5ce0 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Lite reliable UDP library for .NET Framework 3.5, Mono, .NET Core 2.0, .NET Stan ( Warning! Master branch can be unstable! ) ### Donations are welcome and will help further development of this project. -[![](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=G9PDX5KLGKBA2¤cy_code=USD&source=url) +[![Bountysource](https://img.shields.io/badge/bountysource-donate-green.svg)](https://salt.bountysource.com/checkout/amount?team=litenetlib) ## Features From df368c04d98960ab591acd7e505fc204ffba6311 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Fri, 12 Jul 2019 13:34:25 +0300 Subject: [PATCH 005/554] disable ConnectionReset message --- LiteNetLib/NetSocket.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/LiteNetLib/NetSocket.cs b/LiteNetLib/NetSocket.cs index 0b1e6db6..77b6aee3 100644 --- a/LiteNetLib/NetSocket.cs +++ b/LiteNetLib/NetSocket.cs @@ -26,6 +26,7 @@ internal sealed class NetSocket private Thread _threadv6; private volatile bool _running; private readonly INetSocketListener _listener; + private const int SioUdpConnreset = -1744830452; //SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12 private static readonly IPAddress MulticastAddressV6 = IPAddress.Parse("FF02:0:0:0:0:0:0:1"); internal static readonly bool IPv6Support; @@ -161,6 +162,15 @@ private bool BindSocket(Socket socket, IPEndPoint ep, bool reuseAddress) socket.SendTimeout = 500; socket.ReceiveBufferSize = NetConstants.SocketBufferSize; socket.SendBufferSize = NetConstants.SocketBufferSize; + try + { + socket.IOControl(SioUdpConnreset, new byte[] {0}, null); + } + catch + { + //ignored + } + try { socket.ExclusiveAddressUse = !reuseAddress; From 00b576405ce53d6c4a1d56ef0dd42dc3237c7428 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Sat, 20 Jul 2019 16:50:29 +0300 Subject: [PATCH 006/554] data reader skip --- LiteNetLib/Utils/NetDataReader.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/LiteNetLib/Utils/NetDataReader.cs b/LiteNetLib/Utils/NetDataReader.cs index 3960aa58..bc01475b 100644 --- a/LiteNetLib/Utils/NetDataReader.cs +++ b/LiteNetLib/Utils/NetDataReader.cs @@ -50,6 +50,11 @@ public int AvailableBytes { get { return _dataSize - _position; } } + + public void SkipBytes(int count) + { + _position += count; + } public void SetSource(NetDataWriter dataWriter) { From 96caf01bdae36f08eadbff15df52e1013ad47e15 Mon Sep 17 00:00:00 2001 From: Caspar Schutte Date: Thu, 25 Jul 2019 05:23:49 +0200 Subject: [PATCH 007/554] Updated comments for clarity as per issue #322. --- LiteNetLib/NetConstants.cs | 44 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/LiteNetLib/NetConstants.cs b/LiteNetLib/NetConstants.cs index 26bfc476..256efded 100644 --- a/LiteNetLib/NetConstants.cs +++ b/LiteNetLib/NetConstants.cs @@ -1,35 +1,35 @@ -namespace LiteNetLib +namespace LiteNetLib { /// /// Sending method type /// public enum DeliveryMethod { - /// - /// Unreliable. Packets can be dropped, duplicated or arrive without order - /// - Unreliable, + /// + /// Unreliable. Packets can be dropped, can be duplicated, can arrive without order. + /// + Unreliable, - /// - /// Reliable. All packets will be sent and received, but without order - /// - ReliableUnordered, + /// + /// Reliable. Packets won't be dropped, won't be duplicated, can arrive without order. + /// + ReliableUnordered, - /// - /// Unreliable. Packets can be dropped, but never duplicated and arrive in order - /// - Sequenced, + /// + /// Unreliable. Packets can be dropped, won't be duplicated, will arrive in order. + /// + Sequenced, - /// - /// Reliable and ordered. All packets will be sent and received in order - /// - ReliableOrdered, + /// + /// Reliable and ordered. Packets won't be dropped, won't be duplicated, will arrive in order. + /// + ReliableOrdered, - /// - /// Reliable only last packet - /// - ReliableSequenced - } + /// + /// Reliable only last packet. Packets can be dropped (except the last one), won't be duplicated, will arrive in order. + /// + ReliableSequenced + } /// /// Network constants. Can be tuned from sources for your purposes. From 7a7dffa3aada1d1516ba48f5724127bce018e1e1 Mon Sep 17 00:00:00 2001 From: Jasper Citi Date: Thu, 25 Jul 2019 16:28:27 +0200 Subject: [PATCH 008/554] Replaced spaces with tabs. --- LiteNetLib/NetConstants.cs | 114 ++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/LiteNetLib/NetConstants.cs b/LiteNetLib/NetConstants.cs index 256efded..df5a55c4 100644 --- a/LiteNetLib/NetConstants.cs +++ b/LiteNetLib/NetConstants.cs @@ -1,10 +1,10 @@ namespace LiteNetLib { - /// - /// Sending method type - /// - public enum DeliveryMethod - { + /// + /// Sending method type + /// + public enum DeliveryMethod + { /// /// Unreliable. Packets can be dropped, can be duplicated, can arrive without order. /// @@ -31,64 +31,64 @@ public enum DeliveryMethod ReliableSequenced } - /// - /// Network constants. Can be tuned from sources for your purposes. - /// - public static class NetConstants - { - internal static byte ChannelNumberToId(DeliveryMethod method, byte channelNumber, byte channelsCount) - { - int multiplier = 0; - switch (method) - { - case DeliveryMethod.Sequenced: multiplier = 1; break; - case DeliveryMethod.ReliableOrdered: multiplier = 2; break; - case DeliveryMethod.ReliableSequenced: multiplier = 3; break; - } - return (byte)(channelNumber + multiplier * channelsCount); - } + /// + /// Network constants. Can be tuned from sources for your purposes. + /// + public static class NetConstants + { + internal static byte ChannelNumberToId(DeliveryMethod method, byte channelNumber, byte channelsCount) + { + int multiplier = 0; + switch (method) + { + case DeliveryMethod.Sequenced: multiplier = 1; break; + case DeliveryMethod.ReliableOrdered: multiplier = 2; break; + case DeliveryMethod.ReliableSequenced: multiplier = 3; break; + } + return (byte)(channelNumber + multiplier * channelsCount); + } - internal static DeliveryMethod ChannelIdToDeliveryMethod(byte channelId, byte channelsCount) - { - switch (channelId / channelsCount) - { - case 1: return DeliveryMethod.Sequenced; - case 2: return DeliveryMethod.ReliableOrdered; - case 3: return DeliveryMethod.ReliableSequenced; - } - return DeliveryMethod.ReliableUnordered; - } + internal static DeliveryMethod ChannelIdToDeliveryMethod(byte channelId, byte channelsCount) + { + switch (channelId / channelsCount) + { + case 1: return DeliveryMethod.Sequenced; + case 2: return DeliveryMethod.ReliableOrdered; + case 3: return DeliveryMethod.ReliableSequenced; + } + return DeliveryMethod.ReliableUnordered; + } - //can be tuned - public const int DefaultWindowSize = 64; - public const int SocketBufferSize = 1024 * 1024; //1mb - public const int SocketTTL = 255; + //can be tuned + public const int DefaultWindowSize = 64; + public const int SocketBufferSize = 1024 * 1024; //1mb + public const int SocketTTL = 255; - public const int HeaderSize = 1; - public const int ChanneledHeaderSize = 4; - public const int FragmentHeaderSize = 6; - public const ushort MaxSequence = 32768; - public const ushort HalfMaxSequence = MaxSequence / 2; + public const int HeaderSize = 1; + public const int ChanneledHeaderSize = 4; + public const int FragmentHeaderSize = 6; + public const ushort MaxSequence = 32768; + public const ushort HalfMaxSequence = MaxSequence / 2; - //protocol - internal const int ProtocolId = 9; - internal const int MaxUdpHeaderSize = 68; + //protocol + internal const int ProtocolId = 9; + internal const int MaxUdpHeaderSize = 68; - internal static readonly int[] PossibleMtu = - { - 576 - MaxUdpHeaderSize, //minimal - 1232 - MaxUdpHeaderSize, - 1460 - MaxUdpHeaderSize, //google cloud - 1472 - MaxUdpHeaderSize, //VPN - 1492 - MaxUdpHeaderSize, //Ethernet with LLC and SNAP, PPPoE (RFC 1042) - 1500 - MaxUdpHeaderSize //Ethernet II (RFC 1191) - }; + internal static readonly int[] PossibleMtu = + { + 576 - MaxUdpHeaderSize, //minimal + 1232 - MaxUdpHeaderSize, + 1460 - MaxUdpHeaderSize, //google cloud + 1472 - MaxUdpHeaderSize, //VPN + 1492 - MaxUdpHeaderSize, //Ethernet with LLC and SNAP, PPPoE (RFC 1042) + 1500 - MaxUdpHeaderSize //Ethernet II (RFC 1191) + }; - internal static readonly int MaxPacketSize = PossibleMtu[PossibleMtu.Length - 1]; + internal static readonly int MaxPacketSize = PossibleMtu[PossibleMtu.Length - 1]; - //peer specific - public const byte MaxConnectionNumber = 4; + //peer specific + public const byte MaxConnectionNumber = 4; - public const int PacketPoolSize = 1000; - } + public const int PacketPoolSize = 1000; + } } From cc9c313cc6d54a2b25de80ba1ab75e20f1d6935d Mon Sep 17 00:00:00 2001 From: petris Date: Thu, 25 Jul 2019 17:30:41 +0200 Subject: [PATCH 009/554] Replace tabs with spaces --- LiteNetLib/NetPeer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LiteNetLib/NetPeer.cs b/LiteNetLib/NetPeer.cs index 951b4450..5f13b451 100644 --- a/LiteNetLib/NetPeer.cs +++ b/LiteNetLib/NetPeer.cs @@ -183,8 +183,8 @@ public DateTime RemoteUtcTime internal double ResendDelay { get { return _resendDelay; } } /// - /// Application defined object containing data about the connection - /// + /// Application defined object containing data about the connection + /// public object Tag; /// From 06b3b7d3deaeb0bcc49e39542981b6a0a58fa230 Mon Sep 17 00:00:00 2001 From: Jasper Citi Date: Fri, 26 Jul 2019 16:07:17 +0200 Subject: [PATCH 010/554] Replaced tabs with spaces. --- LiteNetLib/NetConstants.cs | 156 ++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/LiteNetLib/NetConstants.cs b/LiteNetLib/NetConstants.cs index df5a55c4..dc569dcf 100644 --- a/LiteNetLib/NetConstants.cs +++ b/LiteNetLib/NetConstants.cs @@ -1,94 +1,94 @@ namespace LiteNetLib { - /// - /// Sending method type - /// - public enum DeliveryMethod - { - /// - /// Unreliable. Packets can be dropped, can be duplicated, can arrive without order. - /// - Unreliable, + /// + /// Sending method type + /// + public enum DeliveryMethod + { + /// + /// Unreliable. Packets can be dropped, can be duplicated, can arrive without order. + /// + Unreliable, - /// - /// Reliable. Packets won't be dropped, won't be duplicated, can arrive without order. - /// - ReliableUnordered, + /// + /// Reliable. Packets won't be dropped, won't be duplicated, can arrive without order. + /// + ReliableUnordered, - /// - /// Unreliable. Packets can be dropped, won't be duplicated, will arrive in order. - /// - Sequenced, + /// + /// Unreliable. Packets can be dropped, won't be duplicated, will arrive in order. + /// + Sequenced, - /// - /// Reliable and ordered. Packets won't be dropped, won't be duplicated, will arrive in order. - /// - ReliableOrdered, + /// + /// Reliable and ordered. Packets won't be dropped, won't be duplicated, will arrive in order. + /// + ReliableOrdered, - /// - /// Reliable only last packet. Packets can be dropped (except the last one), won't be duplicated, will arrive in order. - /// - ReliableSequenced - } + /// + /// Reliable only last packet. Packets can be dropped (except the last one), won't be duplicated, will arrive in order. + /// + ReliableSequenced + } - /// - /// Network constants. Can be tuned from sources for your purposes. - /// - public static class NetConstants - { - internal static byte ChannelNumberToId(DeliveryMethod method, byte channelNumber, byte channelsCount) - { - int multiplier = 0; - switch (method) - { - case DeliveryMethod.Sequenced: multiplier = 1; break; - case DeliveryMethod.ReliableOrdered: multiplier = 2; break; - case DeliveryMethod.ReliableSequenced: multiplier = 3; break; - } - return (byte)(channelNumber + multiplier * channelsCount); - } + /// + /// Network constants. Can be tuned from sources for your purposes. + /// + public static class NetConstants + { + internal static byte ChannelNumberToId(DeliveryMethod method, byte channelNumber, byte channelsCount) + { + int multiplier = 0; + switch (method) + { + case DeliveryMethod.Sequenced: multiplier = 1; break; + case DeliveryMethod.ReliableOrdered: multiplier = 2; break; + case DeliveryMethod.ReliableSequenced: multiplier = 3; break; + } + return (byte)(channelNumber + multiplier * channelsCount); + } - internal static DeliveryMethod ChannelIdToDeliveryMethod(byte channelId, byte channelsCount) - { - switch (channelId / channelsCount) - { - case 1: return DeliveryMethod.Sequenced; - case 2: return DeliveryMethod.ReliableOrdered; - case 3: return DeliveryMethod.ReliableSequenced; - } - return DeliveryMethod.ReliableUnordered; - } + internal static DeliveryMethod ChannelIdToDeliveryMethod(byte channelId, byte channelsCount) + { + switch (channelId / channelsCount) + { + case 1: return DeliveryMethod.Sequenced; + case 2: return DeliveryMethod.ReliableOrdered; + case 3: return DeliveryMethod.ReliableSequenced; + } + return DeliveryMethod.ReliableUnordered; + } - //can be tuned - public const int DefaultWindowSize = 64; - public const int SocketBufferSize = 1024 * 1024; //1mb - public const int SocketTTL = 255; + //can be tuned + public const int DefaultWindowSize = 64; + public const int SocketBufferSize = 1024 * 1024; //1mb + public const int SocketTTL = 255; - public const int HeaderSize = 1; - public const int ChanneledHeaderSize = 4; - public const int FragmentHeaderSize = 6; - public const ushort MaxSequence = 32768; - public const ushort HalfMaxSequence = MaxSequence / 2; + public const int HeaderSize = 1; + public const int ChanneledHeaderSize = 4; + public const int FragmentHeaderSize = 6; + public const ushort MaxSequence = 32768; + public const ushort HalfMaxSequence = MaxSequence / 2; - //protocol - internal const int ProtocolId = 9; - internal const int MaxUdpHeaderSize = 68; + //protocol + internal const int ProtocolId = 9; + internal const int MaxUdpHeaderSize = 68; - internal static readonly int[] PossibleMtu = - { - 576 - MaxUdpHeaderSize, //minimal - 1232 - MaxUdpHeaderSize, - 1460 - MaxUdpHeaderSize, //google cloud - 1472 - MaxUdpHeaderSize, //VPN - 1492 - MaxUdpHeaderSize, //Ethernet with LLC and SNAP, PPPoE (RFC 1042) - 1500 - MaxUdpHeaderSize //Ethernet II (RFC 1191) - }; + internal static readonly int[] PossibleMtu = + { + 576 - MaxUdpHeaderSize, //minimal + 1232 - MaxUdpHeaderSize, + 1460 - MaxUdpHeaderSize, //google cloud + 1472 - MaxUdpHeaderSize, //VPN + 1492 - MaxUdpHeaderSize, //Ethernet with LLC and SNAP, PPPoE (RFC 1042) + 1500 - MaxUdpHeaderSize //Ethernet II (RFC 1191) + }; - internal static readonly int MaxPacketSize = PossibleMtu[PossibleMtu.Length - 1]; + internal static readonly int MaxPacketSize = PossibleMtu[PossibleMtu.Length - 1]; - //peer specific - public const byte MaxConnectionNumber = 4; + //peer specific + public const byte MaxConnectionNumber = 4; - public const int PacketPoolSize = 1000; - } + public const int PacketPoolSize = 1000; + } } From 9107e8fb2868af491d9346b39542014044306958 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Thu, 1 Aug 2019 21:05:46 +0300 Subject: [PATCH 011/554] Fix #329 (max channel count) --- LiteNetLib/NetPeer.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/LiteNetLib/NetPeer.cs b/LiteNetLib/NetPeer.cs index 5f13b451..b2f6d595 100644 --- a/LiteNetLib/NetPeer.cs +++ b/LiteNetLib/NetPeer.cs @@ -82,7 +82,6 @@ private set private readonly BaseChannel[] _channels; private BaseChannel _headChannel; private readonly byte _channelsCount; - private readonly int _channelsTotalCount; //MTU private int _mtu = NetConstants.PossibleMtu[0]; @@ -210,8 +209,7 @@ internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id) _holdedFragments = new Dictionary(); _channelsCount = netManager.ChannelsCount; - _channelsTotalCount = (byte)(_channelsCount * 4); - _channels = new BaseChannel[_channelsTotalCount]; + _channels = new BaseChannel[_channelsCount * 4]; } private BaseChannel CreateChannel(byte idx) @@ -400,7 +398,7 @@ public void Send(byte[] data, int start, int length, byte channelNumber, Deliver if (_connectionState == ConnectionState.ShutdownRequested || _connectionState == ConnectionState.Disconnected) return; - if (channelNumber >= _channelsTotalCount) + if (channelNumber >= _channels.Length) return; //Select channel @@ -834,7 +832,7 @@ internal void ProcessPacket(NetPacket packet) case PacketProperty.Ack: case PacketProperty.Channeled: - if (packet.ChannelId > _channelsTotalCount) + if (packet.ChannelId > _channels.Length) { _packetPool.Recycle(packet); break; From cabca601477426e091d9ce08593dc1fd3053cbd4 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Thu, 1 Aug 2019 22:02:42 +0300 Subject: [PATCH 012/554] remove travis build settings --- .travis.yml | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 99393544..00000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: csharp -solution: LiteNetLib.sln -install: - - nuget restore LiteNetLib.sln -script: - - xbuild /p:Configuration=Release /target:"LiteNetLib;LibSample" LiteNetLib.sln -notifications: - email: false \ No newline at end of file From b301895f5e156d307fe0124a3dfc66e01fe15c9d Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Mon, 5 Aug 2019 21:48:59 +0300 Subject: [PATCH 013/554] Create FUNDING.yml --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..e94b7a5e --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: ['https://salt.bountysource.com/checkout/amount?team=litenetlib'] From 8d2af860a0e4432914dc5e3f498ea8b93a616233 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Fri, 9 Aug 2019 01:51:57 +0300 Subject: [PATCH 014/554] simplify channels logic. --- LiteNetLib.Tests/ConnectionTest.cs | 45 ++++++++++++++++++++ LiteNetLib/NetConstants.cs | 37 +++------------- LiteNetLib/NetManager.cs | 13 ++---- LiteNetLib/NetPeer.cs | 40 +++++++++-------- LiteNetLibSampleUnity/Assets/LiteNetLib.dll | Bin 93184 -> 93184 bytes LiteNetLibSampleUnity/Assets/LiteNetLib.xml | 20 ++++----- 6 files changed, 84 insertions(+), 71 deletions(-) diff --git a/LiteNetLib.Tests/ConnectionTest.cs b/LiteNetLib.Tests/ConnectionTest.cs index 3c7c8fa7..8f533005 100644 --- a/LiteNetLib.Tests/ConnectionTest.cs +++ b/LiteNetLib.Tests/ConnectionTest.cs @@ -370,6 +370,51 @@ public void DisconnectFromClientTest() Assert.AreEqual(0, client.PeersCount); } + [Test, MaxTime(2000)] + public void ChannelsTest() + { + const int channelsCount = 64; + var server = ManagerStack.Server(1); + var client = ManagerStack.Client(1); + server.ChannelsCount = channelsCount; + client.ChannelsCount = channelsCount; + int messagesReceived = 0; + ManagerStack.ServerListener(1).NetworkReceiveEvent += (peer, reader, method) => + { + Assert.AreEqual(reader.GetByte(), (byte)method); + messagesReceived++; + }; + client.Connect("127.0.0.1", DefaultPort, DefaultAppKey); + NetDataWriter writer = new NetDataWriter(); + var methods = new[] + { + DeliveryMethod.Unreliable, + DeliveryMethod.Sequenced, + DeliveryMethod.ReliableOrdered, + DeliveryMethod.ReliableSequenced, + DeliveryMethod.ReliableUnordered + }; + for (int i = 0; i < channelsCount; i++) + { + foreach (var deliveryMethod in methods) + { + writer.Reset(); + writer.Put((byte)deliveryMethod); + client.FirstPeer.Send(writer, (byte)i, deliveryMethod); + } + } + + while (messagesReceived != methods.Length*channelsCount) + { + Thread.Sleep(15); + server.PollEvents(); + } + + Assert.AreEqual(methods.Length*channelsCount, messagesReceived); + Assert.AreEqual(1, server.PeersCount); + Assert.AreEqual(1, client.PeersCount); + } + [Test, MaxTime(2000)] public void ConnectionByIpV6() { diff --git a/LiteNetLib/NetConstants.cs b/LiteNetLib/NetConstants.cs index dc569dcf..608ab8aa 100644 --- a/LiteNetLib/NetConstants.cs +++ b/LiteNetLib/NetConstants.cs @@ -3,32 +3,32 @@ /// /// Sending method type /// - public enum DeliveryMethod + public enum DeliveryMethod : byte { /// /// Unreliable. Packets can be dropped, can be duplicated, can arrive without order. /// - Unreliable, + Unreliable = 4, /// /// Reliable. Packets won't be dropped, won't be duplicated, can arrive without order. /// - ReliableUnordered, + ReliableUnordered = 0, /// /// Unreliable. Packets can be dropped, won't be duplicated, will arrive in order. /// - Sequenced, + Sequenced = 1, /// /// Reliable and ordered. Packets won't be dropped, won't be duplicated, will arrive in order. /// - ReliableOrdered, + ReliableOrdered = 2, /// /// Reliable only last packet. Packets can be dropped (except the last one), won't be duplicated, will arrive in order. /// - ReliableSequenced + ReliableSequenced = 3 } /// @@ -36,29 +36,6 @@ public enum DeliveryMethod /// public static class NetConstants { - internal static byte ChannelNumberToId(DeliveryMethod method, byte channelNumber, byte channelsCount) - { - int multiplier = 0; - switch (method) - { - case DeliveryMethod.Sequenced: multiplier = 1; break; - case DeliveryMethod.ReliableOrdered: multiplier = 2; break; - case DeliveryMethod.ReliableSequenced: multiplier = 3; break; - } - return (byte)(channelNumber + multiplier * channelsCount); - } - - internal static DeliveryMethod ChannelIdToDeliveryMethod(byte channelId, byte channelsCount) - { - switch (channelId / channelsCount) - { - case 1: return DeliveryMethod.Sequenced; - case 2: return DeliveryMethod.ReliableOrdered; - case 3: return DeliveryMethod.ReliableSequenced; - } - return DeliveryMethod.ReliableUnordered; - } - //can be tuned public const int DefaultWindowSize = 64; public const int SocketBufferSize = 1024 * 1024; //1mb @@ -71,7 +48,7 @@ internal static DeliveryMethod ChannelIdToDeliveryMethod(byte channelId, byte ch public const ushort HalfMaxSequence = MaxSequence / 2; //protocol - internal const int ProtocolId = 9; + internal const int ProtocolId = 10; internal const int MaxUdpHeaderSize = 68; internal static readonly int[] PossibleMtu = diff --git a/LiteNetLib/NetManager.cs b/LiteNetLib/NetManager.cs index 5c73a3c2..964d7132 100644 --- a/LiteNetLib/NetManager.cs +++ b/LiteNetLib/NetManager.cs @@ -863,16 +863,9 @@ internal void ReceiveFromPeer(NetPacket packet, IPEndPoint remoteEndPoint) return; NetDebug.Write(NetLogLevel.Trace, "[NM] Received message"); - DeliveryMethod deliveryMethod; - switch (packet.Property) - { - default: //PacketProperty.Unreliable - deliveryMethod = DeliveryMethod.Unreliable; - break; - case PacketProperty.Channeled: - deliveryMethod = NetConstants.ChannelIdToDeliveryMethod(packet.ChannelId, _channelsCount); - break; - } + var deliveryMethod = packet.Property == PacketProperty.Channeled + ? (DeliveryMethod) (packet.ChannelId % 4) + : DeliveryMethod.Unreliable; CreateEvent(NetEvent.EType.Receive, fromPeer, deliveryMethod: deliveryMethod, readerSource: packet); } diff --git a/LiteNetLib/NetPeer.cs b/LiteNetLib/NetPeer.cs index b2f6d595..0ad31e1c 100644 --- a/LiteNetLib/NetPeer.cs +++ b/LiteNetLib/NetPeer.cs @@ -81,7 +81,6 @@ private set private readonly SimpleChannel _unreliableChannel; private readonly BaseChannel[] _channels; private BaseChannel _headChannel; - private readonly byte _channelsCount; //MTU private int _mtu = NetConstants.PossibleMtu[0]; @@ -208,8 +207,7 @@ internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id) _headChannel = _unreliableChannel; _holdedFragments = new Dictionary(); - _channelsCount = netManager.ChannelsCount; - _channels = new BaseChannel[_channelsCount * 4]; + _channels = new BaseChannel[netManager.ChannelsCount * 4]; } private BaseChannel CreateChannel(byte idx) @@ -217,7 +215,7 @@ private BaseChannel CreateChannel(byte idx) BaseChannel newChannel = _channels[idx]; if (newChannel != null) return newChannel; - switch (NetConstants.ChannelIdToDeliveryMethod(idx, _channelsCount)) + switch ((DeliveryMethod)(idx % 4)) { case DeliveryMethod.ReliableUnordered: newChannel = new ReliableChannel(this, false, idx); @@ -305,30 +303,30 @@ public int GetMaxSinglePacketSize(DeliveryMethod options) /// Send data to peer (channel - 0) /// /// Data - /// Send options (reliable, unreliable, etc.) + /// Send options (reliable, unreliable, etc.) /// /// If size exceeds maximum limit: /// MTU - headerSize bytes for Unreliable /// Fragment count exceeded ushort.MaxValue /// - public void Send(byte[] data, DeliveryMethod options) + public void Send(byte[] data, DeliveryMethod deliveryMethod) { - Send(data, 0, data.Length, 0, options); + Send(data, 0, data.Length, 0, deliveryMethod); } /// /// Send data to peer (channel - 0) /// /// DataWriter with data - /// Send options (reliable, unreliable, etc.) + /// Send options (reliable, unreliable, etc.) /// /// If size exceeds maximum limit: /// MTU - headerSize bytes for Unreliable /// Fragment count exceeded ushort.MaxValue /// - public void Send(NetDataWriter dataWriter, DeliveryMethod options) + public void Send(NetDataWriter dataWriter, DeliveryMethod deliveryMethod) { - Send(dataWriter.Data, 0, dataWriter.Length, 0, options); + Send(dataWriter.Data, 0, dataWriter.Length, 0, deliveryMethod); } /// @@ -353,15 +351,15 @@ public void Send(byte[] data, int start, int length, DeliveryMethod options) /// /// Data /// Number of channel (from 0 to channelsCount - 1) - /// Send options (reliable, unreliable, etc.) + /// Send options (reliable, unreliable, etc.) /// /// If size exceeds maximum limit: /// MTU - headerSize bytes for Unreliable /// Fragment count exceeded ushort.MaxValue /// - public void Send(byte[] data, byte channelNumber, DeliveryMethod options) + public void Send(byte[] data, byte channelNumber, DeliveryMethod deliveryMethod) { - Send(data, 0, data.Length, channelNumber, options); + Send(data, 0, data.Length, channelNumber, deliveryMethod); } /// @@ -369,15 +367,15 @@ public void Send(byte[] data, byte channelNumber, DeliveryMethod options) /// /// DataWriter with data /// Number of channel (from 0 to channelsCount - 1) - /// Send options (reliable, unreliable, etc.) + /// Send options (reliable, unreliable, etc.) /// /// If size exceeds maximum limit: /// MTU - headerSize bytes for Unreliable /// Fragment count exceeded ushort.MaxValue /// - public void Send(NetDataWriter dataWriter, byte channelNumber, DeliveryMethod options) + public void Send(NetDataWriter dataWriter, byte channelNumber, DeliveryMethod deliveryMethod) { - Send(dataWriter.Data, 0, dataWriter.Length, channelNumber, options); + Send(dataWriter.Data, 0, dataWriter.Length, channelNumber, deliveryMethod); } /// @@ -387,13 +385,13 @@ public void Send(NetDataWriter dataWriter, byte channelNumber, DeliveryMethod op /// Start of data /// Length of data /// Number of channel (from 0 to channelsCount - 1) - /// Send options (reliable, unreliable, etc.) + /// Delivery method (reliable, unreliable, etc.) /// /// If size exceeds maximum limit: /// MTU - headerSize bytes for Unreliable /// Fragment count exceeded ushort.MaxValue /// - public void Send(byte[] data, int start, int length, byte channelNumber, DeliveryMethod options) + public void Send(byte[] data, int start, int length, byte channelNumber, DeliveryMethod deliveryMethod) { if (_connectionState == ConnectionState.ShutdownRequested || _connectionState == ConnectionState.Disconnected) @@ -405,7 +403,7 @@ public void Send(byte[] data, int start, int length, byte channelNumber, Deliver PacketProperty property; BaseChannel channel; - if (options == DeliveryMethod.Unreliable) + if (deliveryMethod == DeliveryMethod.Unreliable) { property = PacketProperty.Unreliable; channel = _unreliableChannel; @@ -413,7 +411,7 @@ public void Send(byte[] data, int start, int length, byte channelNumber, Deliver else { property = PacketProperty.Channeled; - channel = CreateChannel(NetConstants.ChannelNumberToId(options, channelNumber, _channelsCount)); + channel = CreateChannel((byte)(channelNumber*4 + (byte)deliveryMethod)); } //Prepare @@ -426,7 +424,7 @@ public void Send(byte[] data, int start, int length, byte channelNumber, Deliver if (length + headerSize > mtu) { //if cannot be fragmented - if (options != DeliveryMethod.ReliableOrdered && options != DeliveryMethod.ReliableUnordered) + if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) throw new TooBigPacketException("Unreliable packet size exceeded maximum of " + (_mtu - headerSize) + " bytes"); int packetFullSize = mtu - headerSize; diff --git a/LiteNetLibSampleUnity/Assets/LiteNetLib.dll b/LiteNetLibSampleUnity/Assets/LiteNetLib.dll index 3423284585df79a4454a22c7f04896b691dc11fc..fbdf66db1bb8b8e80260f39cf3bd3e3e13aa574e 100644 GIT binary patch literal 93184 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 literal 93184 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

- Unreliable. Packets can be dropped, duplicated or arrive without order + Unreliable. Packets can be dropped, can be duplicated, can arrive without order. - Reliable. All packets will be sent and received, but without order + Reliable. Packets won't be dropped, won't be duplicated, can arrive without order. - Unreliable. Packets can be dropped, but never duplicated and arrive in order + Unreliable. Packets can be dropped, won't be duplicated, will arrive in order. - Reliable and ordered. All packets will be sent and received in order + Reliable and ordered. Packets won't be dropped, won't be duplicated, will arrive in order. - Reliable only last packet + Reliable only last packet. Packets can be dropped (except the last one), won't be duplicated, will arrive in order. @@ -650,7 +650,7 @@ Send data to peer (channel - 0)
Data - Send options (reliable, unreliable, etc.) + Send options (reliable, unreliable, etc.) If size exceeds maximum limit: MTU - headerSize bytes for Unreliable @@ -662,7 +662,7 @@ Send data to peer (channel - 0)
DataWriter with data - Send options (reliable, unreliable, etc.) + Send options (reliable, unreliable, etc.) If size exceeds maximum limit: MTU - headerSize bytes for Unreliable @@ -689,7 +689,7 @@
Data Number of channel (from 0 to channelsCount - 1) - Send options (reliable, unreliable, etc.) + Send options (reliable, unreliable, etc.) If size exceeds maximum limit: MTU - headerSize bytes for Unreliable @@ -702,7 +702,7 @@
DataWriter with data Number of channel (from 0 to channelsCount - 1) - Send options (reliable, unreliable, etc.) + Send options (reliable, unreliable, etc.) If size exceeds maximum limit: MTU - headerSize bytes for Unreliable @@ -717,7 +717,7 @@ Start of data Length of data Number of channel (from 0 to channelsCount - 1) - Send options (reliable, unreliable, etc.) + Delivery method (reliable, unreliable, etc.) If size exceeds maximum limit: MTU - headerSize bytes for Unreliable From a73b68f1e795c60fe584a3e50d030d9f37786b03 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Mon, 19 Aug 2019 01:07:38 +0300 Subject: [PATCH 015/554] fix NetSerializer behavior on private setters. Remove old netcore ifdefs --- LiteNetLib/Utils/NetSerializer.cs | 184 +++++++++----------- LiteNetLibSampleUnity/Assets/LiteNetLib.dll | Bin 93184 -> 93184 bytes 2 files changed, 80 insertions(+), 104 deletions(-) diff --git a/LiteNetLib/Utils/NetSerializer.cs b/LiteNetLib/Utils/NetSerializer.cs index 57476a48..531fea5e 100644 --- a/LiteNetLib/Utils/NetSerializer.cs +++ b/LiteNetLib/Utils/NetSerializer.cs @@ -3,10 +3,6 @@ using System.Collections.Generic; using System.Net; -#if NETSTANDARD2_0 || NETCOREAPP2_0 -using System.Linq; -#endif - namespace LiteNetLib.Utils { public class InvalidTypeException : ArgumentException @@ -75,11 +71,11 @@ private sealed class ClassInfo public readonly Action[] ReadDelegate; private readonly int _membersCount; - public ClassInfo(int membersCount) + public ClassInfo(List> readDelegates, List> writeDelegates) { - _membersCount = membersCount; - WriteDelegate = new Action[membersCount]; - ReadDelegate = new Action[membersCount]; + _membersCount = readDelegates.Count; + WriteDelegate = writeDelegates.ToArray(); + ReadDelegate = readDelegates.ToArray(); } public void Write(T obj, NetDataWriter writer) @@ -244,23 +240,14 @@ public bool RegisterNestedType(Action writeDelegate, Func ExtractGetDelegate(MethodInfo info) { - return (Func)CreateDelegate(typeof(Func), info); + return (Func)Delegate.CreateDelegate(typeof(Func), info); } private static Action ExtractSetDelegate(MethodInfo info) { - return (Action)CreateDelegate(typeof(Action), info); + return (Action)Delegate.CreateDelegate(typeof(Action), info); } private ClassInfo RegisterInternal() @@ -269,58 +256,47 @@ private ClassInfo RegisterInternal() return ClassInfo.Instance; Type t = typeof(T); -#if NETSTANDARD2_0 || NETCOREAPP2_0 - var props = t.GetRuntimeProperties().ToArray(); -#else var props = t.GetProperties( BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetProperty); -#endif - int propsCount = props.Length; - if (props == null) - throw new InvalidTypeException("Type does not contain acceptable fields"); - - var info = new ClassInfo(propsCount); - for (int i = 0; i < propsCount; i++) + var writeDelegates = new List>(); + var readDelegates = new List>(); + for (int i = 0; i < props.Length; i++) { var property = props[i]; var propertyType = property.PropertyType; - -#if NETSTANDARD2_0 || NETCOREAPP2_0 - bool isEnum = propertyType.GetTypeInfo().IsEnum; - var getMethod = property.GetMethod; - var setMethod = property.SetMethod; -#else bool isEnum = propertyType.IsEnum; var getMethod = property.GetGetMethod(); var setMethod = property.GetSetMethod(); -#endif + if (getMethod == null || setMethod == null) + continue; + if (isEnum) { var underlyingType = Enum.GetUnderlyingType(propertyType); if (underlyingType == typeof(byte)) { - info.ReadDelegate[i] = (inf, r) => + readDelegates.Add((inf, r) => { property.SetValue(inf, Enum.ToObject(propertyType, r.GetByte()), null); - }; - info.WriteDelegate[i] = (inf, w) => + }); + writeDelegates.Add((inf, w) => { w.Put((byte)property.GetValue(inf, null)); - }; + }); } else if (underlyingType == typeof(int)) { - info.ReadDelegate[i] = (inf, r) => + readDelegates.Add((inf, r) => { property.SetValue(inf, Enum.ToObject(propertyType, r.GetInt()), null); - }; - info.WriteDelegate[i] = (inf, w) => + }); + writeDelegates.Add((inf, w) => { w.Put((int)property.GetValue(inf, null)); - }; + }); } else { @@ -333,105 +309,105 @@ private ClassInfo RegisterInternal() var getDelegate = ExtractGetDelegate(getMethod); if (_maxStringLength <= 0) { - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetString()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetString())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else { - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetString(_maxStringLength)); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf), _maxStringLength); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetString(_maxStringLength))); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf), _maxStringLength)); } } else if (propertyType == typeof(bool)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetBool()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetBool())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(byte)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetByte()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetByte())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(sbyte)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetSByte()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetSByte())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(short)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetShort()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetShort())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(ushort)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetUShort()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetUShort())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(int)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetInt()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetInt())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(uint)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetUInt()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetUInt())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(long)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetLong()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetLong())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(ulong)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetULong()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetULong())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(float)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetFloat()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetFloat())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(double)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetDouble()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetDouble())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(char)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetChar()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetChar())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } else if (propertyType == typeof(IPEndPoint)) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetNetEndPoint()); - info.WriteDelegate[i] = (inf, w) => w.Put(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetNetEndPoint())); + writeDelegates.Add((inf, w) => w.Put(getDelegate(inf))); } // Array types else if (propertyType == typeof(string[])) @@ -440,84 +416,84 @@ private ClassInfo RegisterInternal() var getDelegate = ExtractGetDelegate(getMethod); if (_maxStringLength <= 0) { - info.ReadDelegate[i] = (inf, r) => setDelegate( inf, r.GetStringArray()); - info.WriteDelegate[i] = (inf, w) => w.PutArray(getDelegate( inf)); + readDelegates.Add((inf, r) => setDelegate( inf, r.GetStringArray())); + writeDelegates.Add((inf, w) => w.PutArray(getDelegate( inf))); } else { - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetStringArray(_maxStringLength)); - info.WriteDelegate[i] = (inf, w) => w.PutArray(getDelegate(inf), _maxStringLength); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetStringArray(_maxStringLength))); + writeDelegates.Add((inf, w) => w.PutArray(getDelegate(inf), _maxStringLength)); } } else if (propertyType == typeof(bool[])) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetBoolArray()); - info.WriteDelegate[i] = (inf, w) => w.PutArray(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetBoolArray())); + writeDelegates.Add((inf, w) => w.PutArray(getDelegate(inf))); } else if (propertyType == typeof(byte[])) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetBytesWithLength()); - info.WriteDelegate[i] = (inf, w) => w.PutBytesWithLength(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetBytesWithLength())); + writeDelegates.Add((inf, w) => w.PutBytesWithLength(getDelegate(inf))); } else if (propertyType == typeof(short[])) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetShortArray()); - info.WriteDelegate[i] = (inf, w) => w.PutArray(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetShortArray())); + writeDelegates.Add((inf, w) => w.PutArray(getDelegate(inf))); } else if (propertyType == typeof(ushort[])) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetUShortArray()); - info.WriteDelegate[i] = (inf, w) => w.PutArray(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetUShortArray())); + writeDelegates.Add((inf, w) => w.PutArray(getDelegate(inf))); } else if (propertyType == typeof(int[])) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetIntArray()); - info.WriteDelegate[i] = (inf, w) => w.PutArray(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetIntArray())); + writeDelegates.Add((inf, w) => w.PutArray(getDelegate(inf))); } else if (propertyType == typeof(uint[])) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetUIntArray()); - info.WriteDelegate[i] = (inf, w) => w.PutArray(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetUIntArray())); + writeDelegates.Add((inf, w) => w.PutArray(getDelegate(inf))); } else if (propertyType == typeof(long[])) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetLongArray()); - info.WriteDelegate[i] = (inf, w) => w.PutArray(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetLongArray())); + writeDelegates.Add((inf, w) => w.PutArray(getDelegate(inf))); } else if (propertyType == typeof(ulong[])) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetULongArray()); - info.WriteDelegate[i] = (inf, w) => w.PutArray(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetULongArray())); + writeDelegates.Add((inf, w) => w.PutArray(getDelegate(inf))); } else if (propertyType == typeof(float[])) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetFloatArray()); - info.WriteDelegate[i] = (inf, w) => w.PutArray(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetFloatArray())); + writeDelegates.Add((inf, w) => w.PutArray(getDelegate(inf))); } else if (propertyType == typeof(double[])) { var setDelegate = ExtractSetDelegate(setMethod); var getDelegate = ExtractGetDelegate(getMethod); - info.ReadDelegate[i] = (inf, r) => setDelegate(inf, r.GetDoubleArray()); - info.WriteDelegate[i] = (inf, w) => w.PutArray(getDelegate(inf)); + readDelegates.Add((inf, r) => setDelegate(inf, r.GetDoubleArray())); + writeDelegates.Add((inf, w) => w.PutArray(getDelegate(inf))); } else { @@ -534,13 +510,13 @@ private ClassInfo RegisterInternal() { if (array) //Array type serialize/deserialize { - info.ReadDelegate[i] = (inf, r) => property.SetValue(inf, registeredNestedType.ArrayReader(r), null); - info.WriteDelegate[i] = (inf, w) => registeredNestedType.ArrayWriter(w, property.GetValue(inf, null)); + readDelegates.Add((inf, r) => property.SetValue(inf, registeredNestedType.ArrayReader(r), null)); + writeDelegates.Add((inf, w) => registeredNestedType.ArrayWriter(w, property.GetValue(inf, null))); } else //Simple { - info.ReadDelegate[i] = (inf, r) => property.SetValue(inf, registeredNestedType.ReadDelegate(r), null); - info.WriteDelegate[i] = (inf, w) => registeredNestedType.WriteDelegate(w, property.GetValue(inf, null)); + readDelegates.Add((inf, r) => property.SetValue(inf, registeredNestedType.ReadDelegate(r), null)); + writeDelegates.Add((inf, w) => registeredNestedType.WriteDelegate(w, property.GetValue(inf, null))); } } else @@ -549,8 +525,8 @@ private ClassInfo RegisterInternal() } } } - ClassInfo.Instance = info; - return info; + ClassInfo.Instance = new ClassInfo(readDelegates, writeDelegates); + return ClassInfo.Instance; } /// 's fields are not supported, or it has no fields diff --git a/LiteNetLibSampleUnity/Assets/LiteNetLib.dll b/LiteNetLibSampleUnity/Assets/LiteNetLib.dll index fbdf66db1bb8b8e80260f39cf3bd3e3e13aa574e..1a5ff0674b6dbc92f80e24e18629e453cf7f970a 100644 GIT binary patch delta 29987 zcmdVDd3aM**EYWQIcb`tO_MZD)1>KKN;**J03B${JjpDB3{|EgpoKCiXo1sOz=1*V zFbIO8fFlYDf&(f(Ac!J@!h-@TXhnSlLB$#B?_T?yqygXOdcQw@*LPiCFS*aU@3rDgSWS^~)Zx4(-=fxY z#WUp|&gicv{z)v1^?Zgg-zSXm)o)kvqU{5uPGPOXBxcMSA=RcaX2`K>N7+zg*5!0v zrXyslx+mQ2agg&CsWyY0QQA>9gw?pzOX0C@4|#`5wSMwOYDc*yK}|6I9hah~&C=7- z5oud&FEmG)dDiwW(dTVEdwZMI_Ew&^y}I>>vApf}vhD`X3)D_MhVjDfYkO?6@J?!n z8+-Fk+ZWw0pSmJ+MY7pZRJI3$*p~PJN4dM`vXthItZ9Ofl!%H z4t!%m2Vkd(PSrlKjj*}^7fd|Ed#krjN&+sNl*#+6+a@Kq?vGBlsQZmE%ZwXfMrNm& zjZMZsh?C1<0Q)n*X566uJ?RdmHyn^T*Mne7Wb3*d(6x+Gt&1~5xT)qZq;Y4BIFig* zynif+R-3TD>K4jN6at*BV(<_CnFe} zVFqy;90qBw1s1w)UOP8JSPnxi88wlBxmF?7(xD~_;0z16ZNxBUE!a*h++i%a3&|bf zCDZ8;Ri}fy>X(%pbD~04nvbM8jcxGKuruFoFq(xWkxJXZa{H5 zr86Dra$UnXin_L;=h}wfTNqQOk2bQY4pWU6KL1KOL3=ne-i^M~xQ@_uBf8UZ5xP4g z9-7naFgpx$eK28!`(qi)o|~XCqu)&|5lpH@hYhi9Fbs2(F$qd&Zy+U;q%@D?7Ia6% zru;KDm89m-0)z&7I4aP?f_^j75azTvEa+7n^&=e|%;@(JYXN3*SelF(luer&1!g#D zElF#x@R7N>Lh~u{b1s~C^(qW--_5xU?xXQlW`cO3#kBUI7!VzFohJjt+{|QV+7)yE{6*haw+FX za4@64HL*%Clf%_yyqVI4RDg5~NzE0W3TvJuTXTgOqY&ndb;P1T8%jAE9L(s?15@UX z0W~>dn~Y;AT}TB;<49_*&^@F=yTG%YwlG&A(&=`%u`rK^2_xK}Pt|VKn9*NAYyw!w z!t8ERj1wV+mUTB7Cy~@#_K1NNX6U#5GxYXrLpLKdurL<~dWeO&8ez^jM;v-pNd1@$ z4rcT#ZHZ0+H96v%j5U-lWDX!rC8@bHT|+9AhE$k_FsH}iK?O`r_T1^rP@vsGT62Z334Pg?UVjS8vIHKf7=2y-Sn5>Wv|%bvRk z9L(s)txERX#b72!Vv}(RWeb@kNJ~j-F3`j=1pWT&NcWHm4X!$^;AK>k?I*zU{wxog3}jQ$?P9sx5sQksnG==_IP zfQC+oRyf6Q+xIA?OLe4Tb$JYCtTWA#T1%F8^Sc37PO>|wUgLZmPI0TO-M@$W9I11Z zC*ZExNC^fz(sKMJM{1LC6KH6!AZ;coIPUCTBJRn5#yxdyT*~xk>Gn3Xvv1-axA{i5 z=iO%aFss?PbW(?e%YXlE3ZL;bGSr0u#H)m?RLPH1mz|Nt;_(Us&!g;COt~gn{1&(( zjNx+4GwMsT%K0CnXI$2;It{7^M#-MBqd!`gl^c)}M&Tv2)+it) z{XR;jm<&yDFArF8%d@gH&9i(0&YRcY<1*^QO7sgOLrRMD|4tGtyZ=q;F* zN#bJqKgf*-s^tIQl5a!uh-mJA5y!aOM*3f(VlPQaZI+0u>;iftdHkp8;Ps!RgCAG3 zWyW^I`M&|rS|!ozIg7k>Qc|1N_UR|_=$T#-&Zf>t_y+RblI%Z0Vf~~Tl±n$~=$ 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 G_5T2eVk}$$ From 0045184314c9c414149e0c1a8aa790633dffd146 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Thu, 5 Sep 2019 23:34:17 +0300 Subject: [PATCH 016/554] Improve speed on receive. Also fix incoming DeliveryMethod (fix #332) --- LiteNetLib.Tests/ConnectionTest.cs | 4 +++- LiteNetLib/NetManager.cs | 7 +------ LiteNetLib/NetPeer.cs | 14 +++++++++----- LiteNetLib/Utils/NetSerializer.cs | 12 ++++++------ 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/LiteNetLib.Tests/ConnectionTest.cs b/LiteNetLib.Tests/ConnectionTest.cs index 8f533005..22fc01e3 100644 --- a/LiteNetLib.Tests/ConnectionTest.cs +++ b/LiteNetLib.Tests/ConnectionTest.cs @@ -381,7 +381,7 @@ public void ChannelsTest() int messagesReceived = 0; ManagerStack.ServerListener(1).NetworkReceiveEvent += (peer, reader, method) => { - Assert.AreEqual(reader.GetByte(), (byte)method); + Assert.AreEqual((DeliveryMethod)reader.GetByte(), method); messagesReceived++; }; client.Connect("127.0.0.1", DefaultPort, DefaultAppKey); @@ -400,6 +400,8 @@ public void ChannelsTest() { writer.Reset(); writer.Put((byte)deliveryMethod); + if(deliveryMethod == DeliveryMethod.ReliableOrdered || deliveryMethod == DeliveryMethod.ReliableUnordered) + writer.Put(new byte[506]); client.FirstPeer.Send(writer, (byte)i, deliveryMethod); } } diff --git a/LiteNetLib/NetManager.cs b/LiteNetLib/NetManager.cs index 964d7132..35d34aa3 100644 --- a/LiteNetLib/NetManager.cs +++ b/LiteNetLib/NetManager.cs @@ -856,13 +856,8 @@ private void DataReceived(byte[] reusableBuffer, int count, IPEndPoint remoteEnd } } - internal void ReceiveFromPeer(NetPacket packet, IPEndPoint remoteEndPoint) + internal void ReceiveFromPeer(NetPacket packet, NetPeer fromPeer) { - NetPeer fromPeer; - if (!TryGetPeer(remoteEndPoint, out fromPeer)) - return; - - NetDebug.Write(NetLogLevel.Trace, "[NM] Received message"); var deliveryMethod = packet.Property == PacketProperty.Channeled ? (DeliveryMethod) (packet.ChannelId % 4) : DeliveryMethod.Unreliable; diff --git a/LiteNetLib/NetPeer.cs b/LiteNetLib/NetPeer.cs index 0ad31e1c..398d535a 100644 --- a/LiteNetLib/NetPeer.cs +++ b/LiteNetLib/NetPeer.cs @@ -98,6 +98,7 @@ private class IncomingFragments public NetPacket[] Fragments; public int ReceivedCount; public int TotalSize; + public byte ChannelId; } private ushort _fragmentId; private readonly Dictionary _holdedFragments; @@ -585,7 +586,8 @@ internal void AddIncomingPacket(NetPacket p) { incomingFragments = new IncomingFragments { - Fragments = new NetPacket[p.FragmentsTotal] + Fragments = new NetPacket[p.FragmentsTotal], + ChannelId = p.ChannelId }; _holdedFragments.Add(packetFragId, incomingFragments); } @@ -594,7 +596,9 @@ internal void AddIncomingPacket(NetPacket p) var fragments = incomingFragments.Fragments; //Error check - if (p.FragmentPart >= fragments.Length || fragments[p.FragmentPart] != null) + if (p.FragmentPart >= fragments.Length || + fragments[p.FragmentPart] != null || + p.ChannelId != incomingFragments.ChannelId) { _packetPool.Recycle(p); NetDebug.WriteError("Invalid fragment packet"); @@ -614,8 +618,8 @@ internal void AddIncomingPacket(NetPacket p) if (incomingFragments.ReceivedCount != fragments.Length) return; - NetDebug.Write("Received all fragments!"); NetPacket resultingPacket = _packetPool.GetWithProperty( p.Property, incomingFragments.TotalSize ); + resultingPacket.ChannelId = incomingFragments.ChannelId; int resultingPacketOffset = resultingPacket.GetHeaderSize(); int firstFragmentSize = fragments[0].Size - dataOffset; @@ -636,14 +640,14 @@ internal void AddIncomingPacket(NetPacket p) } //Send to process - _netManager.ReceiveFromPeer(resultingPacket, _remoteEndPoint); + _netManager.ReceiveFromPeer(resultingPacket, this); //Clear memory _holdedFragments.Remove(packetFragId); } else //Just simple packet { - _netManager.ReceiveFromPeer(p, _remoteEndPoint); + _netManager.ReceiveFromPeer(p, this); } } diff --git a/LiteNetLib/Utils/NetSerializer.cs b/LiteNetLib/Utils/NetSerializer.cs index 531fea5e..3a61fc69 100644 --- a/LiteNetLib/Utils/NetSerializer.cs +++ b/LiteNetLib/Utils/NetSerializer.cs @@ -67,27 +67,27 @@ public NestedType(NestedTypeWriter writeDelegate, NestedTypeReader readDelegate, private sealed class ClassInfo { public static ClassInfo Instance; - public readonly Action[] WriteDelegate; - public readonly Action[] ReadDelegate; + private readonly Action[] _writeDelegate; + private readonly Action[] _readDelegate; private readonly int _membersCount; public ClassInfo(List> readDelegates, List> writeDelegates) { _membersCount = readDelegates.Count; - WriteDelegate = writeDelegates.ToArray(); - ReadDelegate = readDelegates.ToArray(); + _writeDelegate = writeDelegates.ToArray(); + _readDelegate = readDelegates.ToArray(); } public void Write(T obj, NetDataWriter writer) { for (int i = 0; i < _membersCount; i++) - WriteDelegate[i](obj, writer); + _writeDelegate[i](obj, writer); } public void Read(T obj, NetDataReader reader) { for (int i = 0; i < _membersCount; i++) - ReadDelegate[i](obj, reader); + _readDelegate[i](obj, reader); } } From 5cf47e0cf56c0da90f00199c881a5f200148a612 Mon Sep 17 00:00:00 2001 From: Andrii Vitiv <37713088+TheCubicNoobik@users.noreply.github.com> Date: Sun, 15 Sep 2019 01:31:19 +0300 Subject: [PATCH 017/554] Use IList instead of List for GetLocalIpList(...) --- LiteNetLib/NetUtils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LiteNetLib/NetUtils.cs b/LiteNetLib/NetUtils.cs index 510d8fee..39db2913 100644 --- a/LiteNetLib/NetUtils.cs +++ b/LiteNetLib/NetUtils.cs @@ -88,7 +88,7 @@ public static List GetLocalIpList(LocalAddrType addrType) /// /// result list /// type of address (IPv4, IPv6 or both) - public static void GetLocalIpList(List targetList, LocalAddrType addrType) + public static void GetLocalIpList(IList targetList, LocalAddrType addrType) { bool ipv4 = (addrType & LocalAddrType.IPv4) == LocalAddrType.IPv4; bool ipv6 = (addrType & LocalAddrType.IPv6) == LocalAddrType.IPv6; From cb82ddf267b9cde7a0a9b78203d16d1902d2f8eb Mon Sep 17 00:00:00 2001 From: Oleksandr Boiko Date: Sat, 28 Sep 2019 10:53:51 +0300 Subject: [PATCH 018/554] fixed few under/overflows --- LiteNetLib/NetPacket.cs | 3 ++- LiteNetLib/Utils/NetDataReader.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/LiteNetLib/NetPacket.cs b/LiteNetLib/NetPacket.cs index 2ff8e270..a28e1ba7 100644 --- a/LiteNetLib/NetPacket.cs +++ b/LiteNetLib/NetPacket.cs @@ -148,7 +148,8 @@ public bool FromBytes(byte[] data, int start, int packetSize) int headerSize = GetHeaderSize((PacketProperty) property); if (property > LastProperty || packetSize < headerSize || - (fragmented && packetSize < headerSize + NetConstants.FragmentHeaderSize)) + (fragmented && packetSize < headerSize + NetConstants.FragmentHeaderSize) || + data.Length < start + packetSize) { return false; } diff --git a/LiteNetLib/Utils/NetDataReader.cs b/LiteNetLib/Utils/NetDataReader.cs index bc01475b..6f789e37 100644 --- a/LiteNetLib/Utils/NetDataReader.cs +++ b/LiteNetLib/Utils/NetDataReader.cs @@ -685,7 +685,7 @@ public bool TryGetBytesWithLength(out byte[] result) if (AvailableBytes >= 4) { var length = PeekInt(); - if (AvailableBytes >= length + 4) + if (length > 0 && AvailableBytes >= length + 4) { result = GetBytesWithLength(); return true; From 3bc1c226464ecdcd6fe9ab7d6d679d6394b307d7 Mon Sep 17 00:00:00 2001 From: Oleksandr Boiko Date: Sun, 29 Sep 2019 15:22:19 +0300 Subject: [PATCH 019/554] zero byte length support --- LiteNetLib/Utils/NetDataReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LiteNetLib/Utils/NetDataReader.cs b/LiteNetLib/Utils/NetDataReader.cs index 6f789e37..f31e6f80 100644 --- a/LiteNetLib/Utils/NetDataReader.cs +++ b/LiteNetLib/Utils/NetDataReader.cs @@ -685,7 +685,7 @@ public bool TryGetBytesWithLength(out byte[] result) if (AvailableBytes >= 4) { var length = PeekInt(); - if (length > 0 && AvailableBytes >= length + 4) + if (length >= 0 && AvailableBytes >= length + 4) { result = GetBytesWithLength(); return true; From b0a4bf64689b30cb9631a1d386f2a89657fb2aea Mon Sep 17 00:00:00 2001 From: Jouni Mannonen Date: Fri, 4 Oct 2019 16:44:30 +0300 Subject: [PATCH 020/554] Added disconnect handling and DisconnectReason for NetworkUnreachable --- LiteNetLib/INetEventListener.cs | 1 + LiteNetLib/NetManager.cs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/LiteNetLib/INetEventListener.cs b/LiteNetLib/INetEventListener.cs index 7589041a..ceac218c 100644 --- a/LiteNetLib/INetEventListener.cs +++ b/LiteNetLib/INetEventListener.cs @@ -20,6 +20,7 @@ public enum DisconnectReason ConnectionFailed, Timeout, HostUnreachable, + NetworkUnreachable, RemoteConnectionClose, DisconnectPeerCalled, ConnectionRejected, diff --git a/LiteNetLib/NetManager.cs b/LiteNetLib/NetManager.cs index 35d34aa3..f9e931e5 100644 --- a/LiteNetLib/NetManager.cs +++ b/LiteNetLib/NetManager.cs @@ -384,6 +384,11 @@ internal int SendRaw(byte[] message, int start, int length, IPEndPoint remoteEnd DisconnectPeerForce(fromPeer, DisconnectReason.HostUnreachable, errorCode, null); CreateEvent(NetEvent.EType.Error, remoteEndPoint: remoteEndPoint, errorCode: errorCode); return -1; + case SocketError.NetworkUnreachable: + if (TryGetPeer(remoteEndPoint, out fromPeer)) + DisconnectPeerForce(fromPeer, DisconnectReason.NetworkUnreachable, errorCode, null); + CreateEvent(NetEvent.EType.Error, remoteEndPoint: remoteEndPoint, errorCode: errorCode); + return -1; case SocketError.ConnectionReset: //connection reset (connection closed) if (TryGetPeer(remoteEndPoint, out fromPeer)) DisconnectPeerForce(fromPeer, DisconnectReason.RemoteConnectionClose, errorCode, null); From c4d3670c0640c93dd1e3520d0c41f9b42f1289c3 Mon Sep 17 00:00:00 2001 From: Jouni Mannonen Date: Fri, 4 Oct 2019 17:31:56 +0300 Subject: [PATCH 021/554] Fix to change; tabs to spaces --- LiteNetLib/INetEventListener.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LiteNetLib/INetEventListener.cs b/LiteNetLib/INetEventListener.cs index ceac218c..ba915407 100644 --- a/LiteNetLib/INetEventListener.cs +++ b/LiteNetLib/INetEventListener.cs @@ -20,7 +20,7 @@ public enum DisconnectReason ConnectionFailed, Timeout, HostUnreachable, - NetworkUnreachable, + NetworkUnreachable, RemoteConnectionClose, DisconnectPeerCalled, ConnectionRejected, From 354baba6a8f6b1aa18491ef24dc2b71f97d266ea Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Sat, 5 Oct 2019 13:26:41 +0300 Subject: [PATCH 022/554] fix broadcast sample program --- LibSample/BroadcastTest.cs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/LibSample/BroadcastTest.cs b/LibSample/BroadcastTest.cs index 2b6973fd..ec94045b 100644 --- a/LibSample/BroadcastTest.cs +++ b/LibSample/BroadcastTest.cs @@ -50,7 +50,7 @@ public void OnNetworkLatencyUpdate(NetPeer peer, int latency) public void OnConnectionRequest(ConnectionRequest request) { - request.AcceptIfKey("key"); + request.Reject(); } } @@ -98,7 +98,7 @@ public void OnNetworkLatencyUpdate(NetPeer peer, int latency) public void OnConnectionRequest(ConnectionRequest request) { - + request.AcceptIfKey("key"); } } @@ -125,10 +125,13 @@ public void Run() //Client _clientListener1 = new ClientListener(); - NetManager client1 = new NetManager(_clientListener1); + NetManager client1 = new NetManager(_clientListener1) + { + UnconnectedMessagesEnabled = true, + SimulateLatency = true, + SimulationMaxLatency = 1500 + }; _clientListener1.Client = client1; - client1.SimulateLatency = true; - client1.SimulationMaxLatency = 1500; if (!client1.Start()) { Console.WriteLine("Client1 start failed"); @@ -137,10 +140,14 @@ public void Run() } _clientListener2 = new ClientListener(); - NetManager client2 = new NetManager(_clientListener2); + NetManager client2 = new NetManager(_clientListener2) + { + UnconnectedMessagesEnabled = true, + SimulateLatency = true, + SimulationMaxLatency = 1500 + }; + _clientListener2.Client = client2; - client2.SimulateLatency = true; - client2.SimulationMaxLatency = 1500; client2.Start(); //Send broadcast From a69d9ac4cb401e6e40b2ef311a4ebc1f5804a2ad Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Sat, 5 Oct 2019 13:37:00 +0300 Subject: [PATCH 023/554] Fix Ntp request (fix #283) --- LiteNetLib/Utils/NtpRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LiteNetLib/Utils/NtpRequest.cs b/LiteNetLib/Utils/NtpRequest.cs index 3b3c9170..59cef854 100644 --- a/LiteNetLib/Utils/NtpRequest.cs +++ b/LiteNetLib/Utils/NtpRequest.cs @@ -38,7 +38,7 @@ private NtpRequest(IPEndPoint endPoint, Action onRequestComplete) // Create and start socket _socket = new NetSocket(this); - _socket.Bind(IPAddress.Any, IPAddress.IPv6Any, 0, false, true); + _socket.Bind(IPAddress.Any, IPAddress.IPv6Any, 0, false, endPoint.AddressFamily == AddressFamily.InterNetworkV6); } /// From 33e1bbae5d4d2c74a5d72048c55d3ac9bc299992 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Wed, 16 Oct 2019 01:02:54 +0300 Subject: [PATCH 024/554] improve foreach in NetManager speed (struct optimize) --- LibSample/EchoMessagesTest.cs | 6 ++--- LiteNetLib/NetManager.cs | 47 +++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/LibSample/EchoMessagesTest.cs b/LibSample/EchoMessagesTest.cs index 5adb0755..1aff58fc 100644 --- a/LibSample/EchoMessagesTest.cs +++ b/LibSample/EchoMessagesTest.cs @@ -104,10 +104,10 @@ private class ServerListener : INetEventListener public void OnPeerConnected(NetPeer peer) { Console.WriteLine("[Server] Peer connected: " + peer.EndPoint); - var peers = Server.GetPeers(ConnectionState.Connected); - foreach (var netPeer in peers) + foreach (var netPeer in Server) { - Console.WriteLine("ConnectedPeersList: id={0}, ep={1}", netPeer.Id, netPeer.EndPoint); + if(netPeer.ConnectionState == ConnectionState.Connected) + Console.WriteLine("ConnectedPeersList: id={0}, ep={1}", netPeer.Id, netPeer.EndPoint); } } diff --git a/LiteNetLib/NetManager.cs b/LiteNetLib/NetManager.cs index f9e931e5..fc0ed0fe 100644 --- a/LiteNetLib/NetManager.cs +++ b/LiteNetLib/NetManager.cs @@ -91,6 +91,44 @@ public int GetHashCode(IPEndPoint obj) } } + private struct NetPeerEnumerator : IEnumerator + { + private readonly NetPeer _initialPeer; + private NetPeer _p; + + public NetPeerEnumerator(NetPeer p) + { + _initialPeer = p; + _p = null; + } + + public void Dispose() + { + + } + + public bool MoveNext() + { + _p = _p == null ? _initialPeer : _p.NextPeer; + return _p != null; + } + + public void Reset() + { + throw new NotSupportedException(); + } + + public NetPeer Current + { + get { return _p; } + } + + object IEnumerator.Current + { + get { return _p; } + } + } + #if DEBUG private struct IncomingData { @@ -1420,17 +1458,12 @@ public void DisconnectPeer(NetPeer peer, byte[] data, int start, int count) public IEnumerator GetEnumerator() { - var peer = _headPeer; - while (peer != null) - { - yield return peer; - peer = peer.NextPeer; - } + return new NetPeerEnumerator(_headPeer); } IEnumerator IEnumerable.GetEnumerator() { - return GetEnumerator(); + return new NetPeerEnumerator(_headPeer); } } } From 118c982ea5f0ea77d76e6671dc42b7f18048797a Mon Sep 17 00:00:00 2001 From: petris Date: Wed, 16 Oct 2019 15:35:38 +0200 Subject: [PATCH 025/554] Remove IEnumerator boxing --- LiteNetLib/NetManager.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/LiteNetLib/NetManager.cs b/LiteNetLib/NetManager.cs index fc0ed0fe..61124bd1 100644 --- a/LiteNetLib/NetManager.cs +++ b/LiteNetLib/NetManager.cs @@ -91,7 +91,7 @@ public int GetHashCode(IPEndPoint obj) } } - private struct NetPeerEnumerator : IEnumerator + public struct NetPeerEnumerator : IEnumerator { private readonly NetPeer _initialPeer; private NetPeer _p; @@ -423,10 +423,10 @@ internal int SendRaw(byte[] message, int start, int length, IPEndPoint remoteEnd CreateEvent(NetEvent.EType.Error, remoteEndPoint: remoteEndPoint, errorCode: errorCode); return -1; case SocketError.NetworkUnreachable: - if (TryGetPeer(remoteEndPoint, out fromPeer)) - DisconnectPeerForce(fromPeer, DisconnectReason.NetworkUnreachable, errorCode, null); - CreateEvent(NetEvent.EType.Error, remoteEndPoint: remoteEndPoint, errorCode: errorCode); - return -1; + if (TryGetPeer(remoteEndPoint, out fromPeer)) + DisconnectPeerForce(fromPeer, DisconnectReason.NetworkUnreachable, errorCode, null); + CreateEvent(NetEvent.EType.Error, remoteEndPoint: remoteEndPoint, errorCode: errorCode); + return -1; case SocketError.ConnectionReset: //connection reset (connection closed) if (TryGetPeer(remoteEndPoint, out fromPeer)) DisconnectPeerForce(fromPeer, DisconnectReason.RemoteConnectionClose, errorCode, null); @@ -1456,7 +1456,12 @@ public void DisconnectPeer(NetPeer peer, byte[] data, int start, int count) null); } - public IEnumerator GetEnumerator() + public NetPeerEnumerator GetEnumerator() + { + return new NetPeerEnumerator(_headPeer); + } + + IEnumerator IEnumerable.GetEnumerator() { return new NetPeerEnumerator(_headPeer); } From 10ff3b33e4c007256776bcf04ce1493882050d34 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Thu, 24 Oct 2019 02:31:55 +0300 Subject: [PATCH 026/554] Implement "Expose a way to know if data has been received by a peer #248", optimize some things. --- LiteNetLib.Tests/ConnectionTest.cs | 59 ++++-- LiteNetLib.Tests/LiteNetLib.Tests.csproj | 5 +- LiteNetLib/INetEventListener.cs | 26 ++- LiteNetLib/NetConstants.cs | 1 + LiteNetLib/NetManager.cs | 39 +++- LiteNetLib/NetPacket.cs | 13 +- LiteNetLib/NetPeer.cs | 241 +++++++++++++++-------- LiteNetLib/ReliableChannel.cs | 2 +- LiteNetLib/SequencedChannel.cs | 2 +- LiteNetLib/SimpleChannel.cs | 2 +- 10 files changed, 277 insertions(+), 113 deletions(-) diff --git a/LiteNetLib.Tests/ConnectionTest.cs b/LiteNetLib.Tests/ConnectionTest.cs index 22fc01e3..f87515e4 100644 --- a/LiteNetLib.Tests/ConnectionTest.cs +++ b/LiteNetLib.Tests/ConnectionTest.cs @@ -31,7 +31,7 @@ public void TearDown() public NetManagerStack ManagerStack { get; set; } - [Test, MaxTime(2000)] + [Test, Timeout(2000)] public void ConnectionByIpV4() { var server = ManagerStack.Server(1); @@ -48,7 +48,44 @@ public void ConnectionByIpV4() Assert.AreEqual(1, client.PeersCount); } - [Test, MaxTime(2000)] + [Test, Timeout(2000)] + public void DeliveryTest() + { + var server = ManagerStack.Server(1); + var client = ManagerStack.Client(1); + bool msgDelivered = false; + bool msgReceived = false; + + ManagerStack.ClientListener(1).DeliveryEvent += (peer, obj) => + { + Assert.AreEqual(5, (int)obj); + msgDelivered = true; + }; + ManagerStack.ClientListener(1).PeerConnectedEvent += peer => + { + int testData = 5; + peer.SendWithDeliveryEvent(new byte[12500], 0, DeliveryMethod.ReliableUnordered, testData); + }; + ManagerStack.ServerListener(1).NetworkReceiveEvent += (peer, reader, method) => + { + Assert.AreEqual(12500, reader.UserDataSize); + msgReceived = true; + }; + + client.Connect("127.0.0.1", DefaultPort, DefaultAppKey); + + while (server.PeersCount != 1 || client.PeersCount != 1 || !msgDelivered || !msgReceived) + { + Thread.Sleep(15); + server.PollEvents(); + client.PollEvents(); + } + + Assert.AreEqual(1, server.PeersCount); + Assert.AreEqual(1, client.PeersCount); + } + + [Test, Timeout(2000)] public void PeerNotFoundTest() { var server = ManagerStack.Server(1); @@ -76,7 +113,7 @@ public void PeerNotFoundTest() Assert.AreEqual(DisconnectReason.RemoteConnectionClose, disconnectInfo.Value.Reason); } - [Test, MaxTime(10000)] + [Test, Timeout(10000)] public void ConnectionFailedTest() { NetManager client = ManagerStack.Client(1); @@ -106,7 +143,7 @@ public void ConnectionFailedTest() Assert.AreEqual(DisconnectReason.ConnectionFailed, disconnectInfo.Reason); } - [Test, MaxTime(10000)] + [Test, Timeout(10000)] public void NetPeerDisconnectTimeout() { NetManager client = ManagerStack.Client(1); @@ -215,7 +252,7 @@ public void RejectTest() Assert.AreEqual(0, client.PeersCount); } - [Test, MaxTime(10000)] + [Test, Timeout(10000)] public void NetPeerDisconnectAll() { NetManager client = ManagerStack.Client(1); @@ -262,7 +299,7 @@ public void NetPeerDisconnectAll() Assert.AreEqual(ConnectionState.Disconnected, clientServerPeer.ConnectionState); } - [Test, MaxTime(2000)] + [Test, Timeout(2000)] public void DisconnectFromServerTest() { NetManager server = ManagerStack.Server(1); @@ -297,7 +334,7 @@ public void DisconnectFromServerTest() Assert.AreEqual(0, client.PeersCount); } - [Test, MaxTime(5000)] + [Test, Timeout(5000)] public void ConnectAfterDisconnectWithSamePort() { NetManager server = ManagerStack.Server(1); @@ -333,7 +370,7 @@ public void ConnectAfterDisconnectWithSamePort() Assert.AreEqual(1, client.PeersCount); } - [Test, MaxTime(2000)] + [Test, Timeout(2000)] public void DisconnectFromClientTest() { NetManager server = ManagerStack.Server(1); @@ -370,7 +407,7 @@ public void DisconnectFromClientTest() Assert.AreEqual(0, client.PeersCount); } - [Test, MaxTime(2000)] + [Test, Timeout(2000)] public void ChannelsTest() { const int channelsCount = 64; @@ -417,7 +454,7 @@ public void ChannelsTest() Assert.AreEqual(1, client.PeersCount); } - [Test, MaxTime(2000)] + [Test, Timeout(2000)] public void ConnectionByIpV6() { var server = ManagerStack.Server(1); @@ -434,7 +471,7 @@ public void ConnectionByIpV6() Assert.AreEqual(1, client.PeersCount); } - [Test, MaxTime(2000)] + [Test, Timeout(2000)] public void DiscoveryBroadcastTest() { var server = ManagerStack.Server(1); diff --git a/LiteNetLib.Tests/LiteNetLib.Tests.csproj b/LiteNetLib.Tests/LiteNetLib.Tests.csproj index 6492c448..5d50d206 100644 --- a/LiteNetLib.Tests/LiteNetLib.Tests.csproj +++ b/LiteNetLib.Tests/LiteNetLib.Tests.csproj @@ -8,9 +8,8 @@ - - - + + diff --git a/LiteNetLib/INetEventListener.cs b/LiteNetLib/INetEventListener.cs index ba915407..1ebe5b01 100644 --- a/LiteNetLib/INetEventListener.cs +++ b/LiteNetLib/INetEventListener.cs @@ -101,7 +101,17 @@ public interface INetEventListener void OnConnectionRequest(ConnectionRequest request); } - public class EventBasedNetListener : INetEventListener + public interface IDeliveryEventListener + { + /// + /// On reliable message delivered + /// + /// + /// + void OnMessageDelivered(NetPeer peer, object userData); + } + + public class EventBasedNetListener : INetEventListener, IDeliveryEventListener { public delegate void OnPeerConnected(NetPeer peer); public delegate void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo); @@ -109,8 +119,8 @@ public class EventBasedNetListener : INetEventListener public delegate void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod); public delegate void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType); public delegate void OnNetworkLatencyUpdate(NetPeer peer, int latency); - public delegate void OnConnectionRequest(ConnectionRequest request); + public delegate void OnDeliveryEvent(NetPeer peer, object userData); public event OnPeerConnected PeerConnectedEvent; public event OnPeerDisconnected PeerDisconnectedEvent; @@ -119,6 +129,7 @@ public class EventBasedNetListener : INetEventListener public event OnNetworkReceiveUnconnected NetworkReceiveUnconnectedEvent; public event OnNetworkLatencyUpdate NetworkLatencyUpdateEvent; public event OnConnectionRequest ConnectionRequestEvent; + public event OnDeliveryEvent DeliveryEvent; public void ClearPeerConnectedEvent() { @@ -155,6 +166,11 @@ public void ClearConnectionRequestEvent() ConnectionRequestEvent = null; } + public void ClearDeliveryEvent() + { + DeliveryEvent = null; + } + void INetEventListener.OnPeerConnected(NetPeer peer) { if (PeerConnectedEvent != null) @@ -196,5 +212,11 @@ void INetEventListener.OnConnectionRequest(ConnectionRequest request) if (ConnectionRequestEvent != null) ConnectionRequestEvent(request); } + + void IDeliveryEventListener.OnMessageDelivered(NetPeer peer, object userData) + { + if (DeliveryEvent != null) + DeliveryEvent(peer, userData); + } } } diff --git a/LiteNetLib/NetConstants.cs b/LiteNetLib/NetConstants.cs index 608ab8aa..81a4db43 100644 --- a/LiteNetLib/NetConstants.cs +++ b/LiteNetLib/NetConstants.cs @@ -44,6 +44,7 @@ public static class NetConstants public const int HeaderSize = 1; public const int ChanneledHeaderSize = 4; public const int FragmentHeaderSize = 6; + public const int FragmentTotalSize = ChanneledHeaderSize + FragmentHeaderSize; public const ushort MaxSequence = 32768; public const ushort HalfMaxSequence = MaxSequence / 2; diff --git a/LiteNetLib/NetManager.cs b/LiteNetLib/NetManager.cs index 61124bd1..b2049b93 100644 --- a/LiteNetLib/NetManager.cs +++ b/LiteNetLib/NetManager.cs @@ -54,12 +54,14 @@ public enum EType Error, ConnectionLatencyUpdated, Broadcast, - ConnectionRequest + ConnectionRequest, + MessageDelivered } public EType Type; public NetPeer Peer; public IPEndPoint RemoteEndPoint; + public object UserData; public int Latency; public SocketError ErrorCode; public DisconnectReason DisconnectReason; @@ -147,6 +149,7 @@ private struct IncomingData private readonly Queue _netEventsQueue; private readonly Stack _netEventsPool; private readonly INetEventListener _netEventListener; + private readonly IDeliveryEventListener _deliveryEventListener; private readonly Dictionary _peersDict; private readonly ReaderWriterLockSlim _peersLock; @@ -216,6 +219,11 @@ private struct IncomingData /// public bool UnsyncedEvents = false; + /// + /// If true - delivery event will be called from "receive" thread otherwise on PollEvents call + /// + public bool UnsyncedDeliveryEvent = false; + /// /// Allows receive broadcast packets /// @@ -358,24 +366,26 @@ private void RemovePeerInternal(NetPeer peer) return; if (peer == _headPeer) _headPeer = peer.NextPeer; + if (peer.PrevPeer != null) peer.PrevPeer.NextPeer = peer.NextPeer; if (peer.NextPeer != null) peer.NextPeer.PrevPeer = peer.PrevPeer; peer.PrevPeer = null; - peer.NextPeer = null; - lock(_peerIds) + + lock (_peerIds) _peerIds.Enqueue(peer.Id); } /// /// NetManager constructor /// - /// Network events listener + /// Network events listener (also can implement IDeliveryEventListener) public NetManager(INetEventListener listener) { _socket = new NetSocket(this); _netEventListener = listener; + _deliveryEventListener = listener as IDeliveryEventListener; _netEventsQueue = new Queue(); _netEventsPool = new Stack(); NetPacketPool = new NetPacketPool(); @@ -392,6 +402,12 @@ internal void ConnectionLatencyUpdated(NetPeer fromPeer, int latency) CreateEvent(NetEvent.EType.ConnectionLatencyUpdated, fromPeer, latency: latency); } + internal void MessageDelivered(NetPeer fromPeer, object userData) + { + if(_deliveryEventListener != null) + CreateEvent(NetEvent.EType.MessageDelivered, fromPeer, userData: userData); + } + internal int SendRawAndRecycle(NetPacket packet, IPEndPoint remoteEndPoint) { var result = SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint); @@ -481,11 +497,17 @@ private void CreateEvent( DisconnectReason disconnectReason = DisconnectReason.ConnectionFailed, ConnectionRequest connectionRequest = null, DeliveryMethod deliveryMethod = DeliveryMethod.Unreliable, - NetPacket readerSource = null) + NetPacket readerSource = null, + object userData = null) { NetEvent evt = null; + bool unsyncEvent = UnsyncedEvents; + if (type == NetEvent.EType.Connect) _connectedPeersCount++; + else if (type == NetEvent.EType.MessageDelivered) + unsyncEvent = UnsyncedDeliveryEvent; + lock (_netEventsPool) { if (_netEventsPool.Count > 0) @@ -502,7 +524,9 @@ private void CreateEvent( evt.DisconnectReason = disconnectReason; evt.ConnectionRequest = connectionRequest; evt.DeliveryMethod = deliveryMethod; - if (UnsyncedEvents) + evt.UserData = userData; + + if (unsyncEvent) { ProcessEvent(evt); } @@ -549,6 +573,9 @@ private void ProcessEvent(NetEvent evt) case NetEvent.EType.ConnectionRequest: _netEventListener.OnConnectionRequest(evt.ConnectionRequest); break; + case NetEvent.EType.MessageDelivered: + _deliveryEventListener.OnMessageDelivered(evt.Peer, evt.UserData); + break; } //Recycle if not message if (emptyData) diff --git a/LiteNetLib/NetPacket.cs b/LiteNetLib/NetPacket.cs index a28e1ba7..9574f3e4 100644 --- a/LiteNetLib/NetPacket.cs +++ b/LiteNetLib/NetPacket.cs @@ -84,12 +84,15 @@ public ushort FragmentsTotal //Data public byte[] RawData; - public int Size; + public ushort Size; + + //Delivery + public object UserData; public NetPacket(int size) { RawData = new byte[size]; - Size = size; + Size = (ushort)size; } public NetPacket(PacketProperty property, int size) @@ -97,12 +100,12 @@ public NetPacket(PacketProperty property, int size) size += GetHeaderSize(property); RawData = new byte[size]; Property = property; - Size = size; + Size = (ushort)size; } public void Realloc(int toSize, bool clear) { - Size = toSize; + Size = (ushort)toSize; if (RawData.Length < toSize) { RawData = new byte[toSize]; @@ -155,7 +158,7 @@ public bool FromBytes(byte[] data, int start, int packetSize) } Buffer.BlockCopy(data, start, RawData, 0, packetSize); - Size = packetSize; + Size = (ushort)packetSize; return true; } } diff --git a/LiteNetLib/NetPeer.cs b/LiteNetLib/NetPeer.cs index 398d535a..2f13ac2b 100644 --- a/LiteNetLib/NetPeer.cs +++ b/LiteNetLib/NetPeer.cs @@ -55,14 +55,12 @@ public class NetPeer private long _remoteDelta; //Common - private readonly IPEndPoint _remoteEndPoint; - private readonly NetManager _netManager; private readonly NetPacketPool _packetPool; private readonly object _flushLock = new object(); private readonly object _sendLock = new object(); private readonly object _shutdownLock = new object(); - internal NetPeer NextPeer; + internal volatile NetPeer NextPeer; internal NetPeer PrevPeer; internal byte ConnectionNum @@ -102,6 +100,7 @@ private class IncomingFragments } private ushort _fragmentId; private readonly Dictionary _holdedFragments; + private readonly Dictionary _deliveredFramgnets; //Merging private readonly NetPacket _mergeData; @@ -122,6 +121,16 @@ private class IncomingFragments private readonly NetPacket _connectRequestPacket; private NetPacket _connectAcceptPacket; + /// + /// Peer ip address and port + /// + public readonly IPEndPoint EndPoint; + + /// + /// Peer parent NetManager + /// + public readonly NetManager NetManager; + /// /// Current connection state /// @@ -137,11 +146,6 @@ private class IncomingFragments /// public readonly int Id; - /// - /// Peer ip address and port - /// - public IPEndPoint EndPoint { get { return _remoteEndPoint; } } - /// /// Current ping in milliseconds /// @@ -174,11 +178,6 @@ public DateTime RemoteUtcTime /// public int TimeSinceLastPacket { get { return _timeSinceLastPacket; } } - /// - /// Peer parent NetManager - /// - public NetManager NetManager { get { return _netManager; } } - internal double ResendDelay { get { return _resendDelay; } } /// @@ -197,8 +196,8 @@ internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id) Id = id; Statistics = new NetStatistics(); _packetPool = netManager.NetPacketPool; - _netManager = netManager; - _remoteEndPoint = remoteEndPoint; + NetManager = netManager; + EndPoint = remoteEndPoint; _connectionState = ConnectionState.Incoming; _mergeData = new NetPacket(PacketProperty.Merged, NetConstants.MaxPacketSize); _pongPacket = new NetPacket(PacketProperty.Pong, 0); @@ -207,7 +206,8 @@ internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id) _unreliableChannel = new SimpleChannel(this); _headChannel = _unreliableChannel; _holdedFragments = new Dictionary(); - + _deliveredFramgnets = new Dictionary(); + _channels = new BaseChannel[netManager.ChannelsCount * 4]; } @@ -250,7 +250,7 @@ internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id, byte _connectRequestPacket.ConnectionNumber = connectNum; //Send request - _netManager.SendRaw(_connectRequestPacket, _remoteEndPoint); + NetManager.SendRaw(_connectRequestPacket, EndPoint); NetDebug.Write(NetLogLevel.Trace, "[CC] ConnectId: {0}, ConnectNum: {1}", _connectTime, connectNum); } @@ -265,7 +265,7 @@ internal void Accept(long connectId, byte connectNum) //Make initial packet _connectAcceptPacket = NetConnectAcceptPacket.Make(_connectTime, connectNum, false); //Send - _netManager.SendRaw(_connectAcceptPacket, _remoteEndPoint); + NetManager.SendRaw(_connectAcceptPacket, EndPoint); NetDebug.Write(NetLogLevel.Trace, "[CC] ConnectId: {0}", _connectTime); } @@ -300,6 +300,59 @@ public int GetMaxSinglePacketSize(DeliveryMethod options) return _mtu - NetPacket.GetHeaderSize(options == DeliveryMethod.Unreliable ? PacketProperty.Unreliable : PacketProperty.Channeled); } + /// + /// Send data to peer with delivery event called + /// + /// Data + /// Number of channel (from 0 to channelsCount - 1) + /// Delivery method (reliable, unreliable, etc.) + /// User data that will be received in DeliveryEvent + /// + /// If you trying to send unreliable packet type + /// + public void SendWithDeliveryEvent(byte[] data, byte channelNumber, DeliveryMethod deliveryMethod, object userData) + { + if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) + throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets"); + SendInternal(data, 0, data.Length, channelNumber, deliveryMethod, userData); + } + + /// + /// Send data to peer with delivery event called + /// + /// Data + /// Start of data + /// Length of data + /// Number of channel (from 0 to channelsCount - 1) + /// Delivery method (reliable, unreliable, etc.) + /// User data that will be received in DeliveryEvent + /// + /// If you trying to send unreliable packet type + /// + public void SendWithDeliveryEvent(byte[] data, int start, int length, byte channelNumber, DeliveryMethod deliveryMethod, object userData) + { + if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) + throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets"); + SendInternal(data, start, length, channelNumber, deliveryMethod, userData); + } + + /// + /// Send data to peer with delivery event called + /// + /// Data + /// Number of channel (from 0 to channelsCount - 1) + /// Delivery method (reliable, unreliable, etc.) + /// User data that will be received in DeliveryEvent + /// + /// If you trying to send unreliable packet type + /// + public void SendWithDeliveryEvent(NetDataWriter dataWriter, byte channelNumber, DeliveryMethod deliveryMethod, object userData) + { + if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) + throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets"); + SendInternal(dataWriter.Data, 0, dataWriter.Length, channelNumber, deliveryMethod, userData); + } + /// /// Send data to peer (channel - 0) /// @@ -312,7 +365,7 @@ public int GetMaxSinglePacketSize(DeliveryMethod options) /// public void Send(byte[] data, DeliveryMethod deliveryMethod) { - Send(data, 0, data.Length, 0, deliveryMethod); + SendInternal(data, 0, data.Length, 0, deliveryMethod, null); } /// @@ -327,7 +380,7 @@ public void Send(byte[] data, DeliveryMethod deliveryMethod) /// public void Send(NetDataWriter dataWriter, DeliveryMethod deliveryMethod) { - Send(dataWriter.Data, 0, dataWriter.Length, 0, deliveryMethod); + SendInternal(dataWriter.Data, 0, dataWriter.Length, 0, deliveryMethod, null); } /// @@ -344,7 +397,7 @@ public void Send(NetDataWriter dataWriter, DeliveryMethod deliveryMethod) /// public void Send(byte[] data, int start, int length, DeliveryMethod options) { - Send(data, start, length, 0, options); + SendInternal(data, start, length, 0, options, null); } /// @@ -360,7 +413,7 @@ public void Send(byte[] data, int start, int length, DeliveryMethod options) /// public void Send(byte[] data, byte channelNumber, DeliveryMethod deliveryMethod) { - Send(data, 0, data.Length, channelNumber, deliveryMethod); + SendInternal(data, 0, data.Length, channelNumber, deliveryMethod, null); } /// @@ -376,7 +429,7 @@ public void Send(byte[] data, byte channelNumber, DeliveryMethod deliveryMethod) /// public void Send(NetDataWriter dataWriter, byte channelNumber, DeliveryMethod deliveryMethod) { - Send(dataWriter.Data, 0, dataWriter.Length, channelNumber, deliveryMethod); + SendInternal(dataWriter.Data, 0, dataWriter.Length, channelNumber, deliveryMethod, null); } /// @@ -393,6 +446,17 @@ public void Send(NetDataWriter dataWriter, byte channelNumber, DeliveryMethod de /// Fragment count exceeded ushort.MaxValue /// public void Send(byte[] data, int start, int length, byte channelNumber, DeliveryMethod deliveryMethod) + { + SendInternal(data, start, length, channelNumber, deliveryMethod, null); + } + + private void SendInternal( + byte[] data, + int start, + int length, + byte channelNumber, + DeliveryMethod deliveryMethod, + object userData) { if (_connectionState == ConnectionState.ShutdownRequested || _connectionState == ConnectionState.Disconnected) @@ -430,49 +494,37 @@ public void Send(byte[] data, int start, int length, byte channelNumber, Deliver int packetFullSize = mtu - headerSize; int packetDataSize = packetFullSize - NetConstants.FragmentHeaderSize; - - int fullPacketsCount = length / packetDataSize; - int lastPacketSize = length % packetDataSize; - int totalPackets = fullPacketsCount + (lastPacketSize == 0 ? 0 : 1); + int totalPackets = length / packetDataSize + (length % packetDataSize == 0 ? 0 : 1); NetDebug.Write("FragmentSend:\n" + " MTU: {0}\n" + " headerSize: {1}\n" + " packetFullSize: {2}\n" + " packetDataSize: {3}\n" + - " fullPacketsCount: {4}\n" + - " lastPacketSize: {5}\n" + - " totalPackets: {6}", - mtu, headerSize, packetFullSize, packetDataSize, fullPacketsCount, lastPacketSize, totalPackets); + " totalPackets: {4}", + mtu, headerSize, packetFullSize, packetDataSize, totalPackets); if (totalPackets > ushort.MaxValue) - { throw new TooBigPacketException("Data was split in " + totalPackets + " fragments, which exceeds " + ushort.MaxValue); - } - - int dataOffset = headerSize + NetConstants.FragmentHeaderSize; lock (_sendLock) { - for (ushort i = 0; i < fullPacketsCount; i++) - { - NetPacket p = _packetPool.GetWithProperty(property, packetFullSize); - p.FragmentId = _fragmentId; - p.FragmentPart = i; - p.FragmentsTotal = (ushort)totalPackets; - p.MarkFragmented(); - Buffer.BlockCopy(data, i * packetDataSize, p.RawData, dataOffset, packetDataSize); - channel.AddToQueue(p); - } - if (lastPacketSize > 0) + for(ushort partIdx = 0; partIdx < totalPackets; partIdx++) { - NetPacket p = _packetPool.GetWithProperty(property, lastPacketSize + NetConstants.FragmentHeaderSize); + int sendLength = length > packetDataSize ? packetDataSize : length; + + NetPacket p = _packetPool.GetWithProperty(property, sendLength + NetConstants.FragmentHeaderSize); + p.UserData = userData; p.FragmentId = _fragmentId; - p.FragmentPart = (ushort)fullPacketsCount; //last + p.FragmentPart = partIdx; p.FragmentsTotal = (ushort)totalPackets; p.MarkFragmented(); - Buffer.BlockCopy(data, fullPacketsCount * packetDataSize, p.RawData, dataOffset, lastPacketSize); + + + Buffer.BlockCopy(data, partIdx * packetDataSize, p.RawData, NetConstants.FragmentTotalSize, sendLength); channel.AddToQueue(p); + + length -= sendLength; } _fragmentId++; } @@ -481,27 +533,28 @@ public void Send(byte[] data, int start, int length, byte channelNumber, Deliver //Else just send NetPacket packet = _packetPool.GetWithData(property, data, start, length); + packet.UserData = userData; channel.AddToQueue(packet); } public void Disconnect(byte[] data) { - _netManager.DisconnectPeer(this, data); + NetManager.DisconnectPeer(this, data); } public void Disconnect(NetDataWriter writer) { - _netManager.DisconnectPeer(this, writer); + NetManager.DisconnectPeer(this, writer); } public void Disconnect(byte[] data, int start, int count) { - _netManager.DisconnectPeer(this, data, start, count); + NetManager.DisconnectPeer(this, data, start, count); } public void Disconnect() { - _netManager.DisconnectPeer(this); + NetManager.DisconnectPeer(this); } internal DisconnectResult ProcessDisconnect(NetPacket packet) @@ -561,7 +614,7 @@ internal bool Shutdown(byte[] data, int start, int length, bool force) } _connectionState = ConnectionState.ShutdownRequested; NetDebug.Write("[Peer] Send disconnect"); - _netManager.SendRaw(_shutdownPacket, _remoteEndPoint); + NetManager.SendRaw(_shutdownPacket, EndPoint); return true; } } @@ -611,8 +664,7 @@ internal void AddIncomingPacket(NetPacket p) incomingFragments.ReceivedCount++; //Increase total size - int dataOffset = p.GetHeaderSize() + NetConstants.FragmentHeaderSize; - incomingFragments.TotalSize += p.Size - dataOffset; + incomingFragments.TotalSize += p.Size - NetConstants.FragmentTotalSize; //Check for finish if (incomingFragments.ReceivedCount != fragments.Length) @@ -622,14 +674,14 @@ internal void AddIncomingPacket(NetPacket p) resultingPacket.ChannelId = incomingFragments.ChannelId; int resultingPacketOffset = resultingPacket.GetHeaderSize(); - int firstFragmentSize = fragments[0].Size - dataOffset; + int firstFragmentSize = fragments[0].Size - NetConstants.FragmentTotalSize; for (int i = 0; i < incomingFragments.ReceivedCount; i++) { //Create resulting big packet - int fragmentSize = fragments[i].Size - dataOffset; + int fragmentSize = fragments[i].Size - NetConstants.FragmentTotalSize; Buffer.BlockCopy( fragments[i].RawData, - dataOffset, + NetConstants.FragmentTotalSize, resultingPacket.RawData, resultingPacketOffset + firstFragmentSize * i, fragmentSize); @@ -640,14 +692,14 @@ internal void AddIncomingPacket(NetPacket p) } //Send to process - _netManager.ReceiveFromPeer(resultingPacket, this); + NetManager.ReceiveFromPeer(resultingPacket, this); //Clear memory _holdedFragments.Remove(packetFragId); } else //Just simple packet { - _netManager.ReceiveFromPeer(p, this); + NetManager.ReceiveFromPeer(p, this); } } @@ -671,7 +723,7 @@ private void ProcessMtuPacket(NetPacket packet) _mtuCheckAttempts = 0; NetDebug.Write("[MTU] check. send back: " + receivedMtu); packet.Property = PacketProperty.MtuOk; - _netManager.SendRawAndRecycle(packet, _remoteEndPoint); + NetManager.SendRawAndRecycle(packet, EndPoint); } else if(receivedMtu > _mtu && !_finishMtu) //MtuOk { @@ -721,7 +773,7 @@ private void UpdateMtuLogic(int deltaTime) FastBitConverter.GetBytes(p.RawData, p.Size - 4, newMtu);//and end of packet //Must check result for MTU fix - if (_netManager.SendRawAndRecycle(p, _remoteEndPoint) <= 0) + if (NetManager.SendRawAndRecycle(p, EndPoint) <= 0) _finishMtu = true; } } @@ -750,7 +802,7 @@ internal ConnectRequestResult ProcessConnectRequest(NetConnectRequestPacket conn if (connRequest.ConnectionTime == _connectTime) { //just reply accept - _netManager.SendRaw(_connectAcceptPacket, _remoteEndPoint); + NetManager.SendRaw(_connectAcceptPacket, EndPoint); } //New connect request else if (connRequest.ConnectionTime > _connectTime) @@ -813,7 +865,7 @@ internal void ProcessPacket(NetPacket packet) NetDebug.Write("[PP]Ping receive, send pong"); FastBitConverter.GetBytes(_pongPacket.RawData, 3, DateTime.UtcNow.Ticks); _pongPacket.Sequence = packet.Sequence; - _netManager.SendRaw(_pongPacket, _remoteEndPoint); + NetManager.SendRaw(_pongPacket, EndPoint); } _packetPool.Recycle(packet); break; @@ -826,7 +878,7 @@ internal void ProcessPacket(NetPacket packet) int elapsedMs = (int)_pingTimer.ElapsedMilliseconds; _remoteDelta = BitConverter.ToInt64(packet.RawData, 3) + (elapsedMs * TimeSpan.TicksPerMillisecond ) / 2 - DateTime.UtcNow.Ticks; UpdateRoundTripTime(elapsedMs); - _netManager.ConnectionLatencyUpdated(this, elapsedMs / 2); + NetManager.ConnectionLatencyUpdated(this, elapsedMs / 2); NetDebug.Write("[PP]Ping: {0} - {1} - {2}", packet.Sequence, elapsedMs, _remoteDelta); } _packetPool.Recycle(packet); @@ -877,12 +929,12 @@ private void SendMerged() if (_mergeCount > 1) { NetDebug.Write("[P]Send merged: " + _mergePos + ", count: " + _mergeCount); - bytesSent = _netManager.SendRaw(_mergeData.RawData, 0, NetConstants.HeaderSize + _mergePos, _remoteEndPoint); + bytesSent = NetManager.SendRaw(_mergeData.RawData, 0, NetConstants.HeaderSize + _mergePos, EndPoint); } else { //Send without length information and merging - bytesSent = _netManager.SendRaw(_mergeData.RawData, NetConstants.HeaderSize + 2, _mergePos - 2, _remoteEndPoint); + bytesSent = NetManager.SendRaw(_mergeData.RawData, NetConstants.HeaderSize + 2, _mergePos - 2, EndPoint); } #if STATS_ENABLED Statistics.PacketsSent++; @@ -900,7 +952,7 @@ internal void SendUserData(NetPacket packet) if (mergedPacketSize + sizeTreshold >= _mtu) { NetDebug.Write(NetLogLevel.Trace, "[P]SendingPacket: " + packet.Property); - int bytesSent = _netManager.SendRaw(packet, _remoteEndPoint); + int bytesSent = NetManager.SendRaw(packet, EndPoint); #if STATS_ENABLED Statistics.PacketsSent++; Statistics.BytesSent += (ulong)bytesSent; @@ -942,19 +994,19 @@ internal void Update(int deltaTime) switch (_connectionState) { case ConnectionState.Connected: - if (_timeSinceLastPacket > _netManager.DisconnectTimeout) + if (_timeSinceLastPacket > NetManager.DisconnectTimeout) { NetDebug.Write( "[UPDATE] Disconnect by timeout: {0} > {1}", _timeSinceLastPacket, - _netManager.DisconnectTimeout); - _netManager.DisconnectPeerForce(this, DisconnectReason.Timeout, 0, null); + NetManager.DisconnectTimeout); + NetManager.DisconnectPeerForce(this, DisconnectReason.Timeout, 0, null); return; } break; case ConnectionState.ShutdownRequested: - if (_timeSinceLastPacket > _netManager.DisconnectTimeout) + if (_timeSinceLastPacket > NetManager.DisconnectTimeout) { _connectionState = ConnectionState.Disconnected; } @@ -964,25 +1016,25 @@ internal void Update(int deltaTime) if (_shutdownTimer >= ShutdownDelay) { _shutdownTimer = 0; - _netManager.SendRaw(_shutdownPacket, _remoteEndPoint); + NetManager.SendRaw(_shutdownPacket, EndPoint); } } return; case ConnectionState.Outcoming: _connectTimer += deltaTime; - if (_connectTimer > _netManager.ReconnectDelay) + if (_connectTimer > NetManager.ReconnectDelay) { _connectTimer = 0; _connectAttempts++; - if (_connectAttempts > _netManager.MaxConnectAttempts) + if (_connectAttempts > NetManager.MaxConnectAttempts) { - _netManager.DisconnectPeerForce(this, DisconnectReason.ConnectionFailed, 0, null); + NetManager.DisconnectPeerForce(this, DisconnectReason.ConnectionFailed, 0, null); return; } //else send connect again - _netManager.SendRaw(_connectRequestPacket, _remoteEndPoint); + NetManager.SendRaw(_connectRequestPacket, EndPoint); } return; @@ -993,7 +1045,7 @@ internal void Update(int deltaTime) //Send ping _pingSendTimer += deltaTime; - if (_pingSendTimer >= _netManager.PingInterval) + if (_pingSendTimer >= NetManager.PingInterval) { NetDebug.Write("[PP] Send ping..."); //reset timer @@ -1005,12 +1057,12 @@ internal void Update(int deltaTime) UpdateRoundTripTime((int)_pingTimer.ElapsedMilliseconds); _pingTimer.Reset(); _pingTimer.Start(); - _netManager.SendRaw(_pingPacket, _remoteEndPoint); + NetManager.SendRaw(_pingPacket, EndPoint); } //RTT - round trip time _rttResetTimer += deltaTime; - if (_rttResetTimer >= _netManager.PingInterval * 3) + if (_rttResetTimer >= NetManager.PingInterval * 3) { _rttResetTimer = 0; _rtt = _avgRtt; @@ -1023,9 +1075,32 @@ internal void Update(int deltaTime) Flush(); } - //For channels - internal void Recycle(NetPacket packet) + //For reliable channel + internal void RecycleAndDeliver(NetPacket packet) { + if (packet.UserData != null) + { + if (packet.IsFragmented) + { + ushort fragCount; + _deliveredFramgnets.TryGetValue(packet.FragmentId, out fragCount); + fragCount++; + if (fragCount == packet.FragmentsTotal) + { + NetManager.MessageDelivered(this, packet.UserData); + _deliveredFramgnets.Remove(packet.FragmentId); + } + else + { + _deliveredFramgnets[packet.FragmentId] = fragCount; + } + } + else + { + NetManager.MessageDelivered(this, packet.UserData); + } + packet.UserData = null; + } _packetPool.Recycle(packet); } } diff --git a/LiteNetLib/ReliableChannel.cs b/LiteNetLib/ReliableChannel.cs index 08252dd8..0634e806 100644 --- a/LiteNetLib/ReliableChannel.cs +++ b/LiteNetLib/ReliableChannel.cs @@ -42,7 +42,7 @@ public bool Clear(NetPeer peer) { if (_packet != null) { - peer.Recycle(_packet); + peer.RecycleAndDeliver(_packet); _packet = null; return true; } diff --git a/LiteNetLib/SequencedChannel.cs b/LiteNetLib/SequencedChannel.cs index f013b9e2..0cc67930 100644 --- a/LiteNetLib/SequencedChannel.cs +++ b/LiteNetLib/SequencedChannel.cs @@ -41,7 +41,7 @@ public override void SendNextPackets() if (_reliable && OutgoingQueue.Count == 0) _lastPacket = packet; else - Peer.Recycle(packet); + Peer.NetManager.NetPacketPool.Recycle(packet); } } } diff --git a/LiteNetLib/SimpleChannel.cs b/LiteNetLib/SimpleChannel.cs index 005ccfad..eb9c862b 100644 --- a/LiteNetLib/SimpleChannel.cs +++ b/LiteNetLib/SimpleChannel.cs @@ -15,7 +15,7 @@ public override void SendNextPackets() { NetPacket packet = OutgoingQueue.Dequeue(); Peer.SendUserData(packet); - Peer.Recycle(packet); + Peer.NetManager.NetPacketPool.Recycle(packet); } } } From 1ef3e9afc18eef84af2f450704f22cdd2beae750 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Wed, 4 Dec 2019 21:06:37 +0200 Subject: [PATCH 027/554] improve connect logic and speed --- LiteNetLib/NetManager.cs | 94 ++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/LiteNetLib/NetManager.cs b/LiteNetLib/NetManager.cs index b2049b93..44907606 100644 --- a/LiteNetLib/NetManager.cs +++ b/LiteNetLib/NetManager.cs @@ -84,7 +84,7 @@ private class IPEndPointComparer : IEqualityComparer { public bool Equals(IPEndPoint x, IPEndPoint y) { - return x.Equals(y); + return x.Address.Equals(y.Address) && x.Port == y.Port; } public int GetHashCode(IPEndPoint obj) @@ -327,19 +327,8 @@ private bool TryGetPeer(IPEndPoint endPoint, out NetPeer peer) return result; } - private NetPeer TryAddPeer(NetPeer peer) + private void AddPeer(NetPeer peer) { - _peersLock.EnterUpgradeableReadLock(); - NetPeer existingPeer; - if (_peersDict.TryGetValue(peer.EndPoint, out existingPeer)) - { - //return back unused peerId - lock (_peerIds) - _peerIds.Enqueue(peer.Id); - - _peersLock.ExitUpgradeableReadLock(); - return existingPeer; - } _peersLock.EnterWriteLock(); if (_headPeer != null) { @@ -349,8 +338,6 @@ private NetPeer TryAddPeer(NetPeer peer) _headPeer = peer; _peersDict.Add(peer.EndPoint, peer); _peersLock.ExitWriteLock(); - _peersLock.ExitUpgradeableReadLock(); - return peer; } private void RemovePeer(NetPeer peer) @@ -751,8 +738,13 @@ private void ProcessConnectRequest( //if we have peer if (netPeer != null) { - NetDebug.Write("ConnectRequest LastId: {0}, NewId: {1}, EP: {2}", netPeer.ConnectTime, connRequest.ConnectionTime, remoteEndPoint); var processResult = netPeer.ProcessConnectRequest(connRequest); + NetDebug.Write("ConnectRequest LastId: {0}, NewId: {1}, EP: {2}, Result: {3}", + netPeer.ConnectTime, + connRequest.ConnectionTime, + remoteEndPoint, + processResult); + switch (processResult) { case ConnectRequestResult.Reconnection: @@ -792,16 +784,14 @@ private void ProcessConnectRequest( //Add new peer and craete ConnectRequest event NetDebug.Write("[NM] Creating request event: " + connRequest.ConnectionTime); netPeer = new NetPeer(this, remoteEndPoint, GetNextPeerId()); - if (TryAddPeer(netPeer) == netPeer) - { - CreateEvent(NetEvent.EType.ConnectionRequest, connectionRequest: new ConnectionRequest( - connRequest.ConnectionTime, - connectionNumber, - ConnectionRequestType.Incoming, - connRequest.Data, - netPeer, - this)); - } + AddPeer(netPeer); + CreateEvent(NetEvent.EType.ConnectionRequest, connectionRequest: new ConnectionRequest( + connRequest.ConnectionTime, + connectionNumber, + ConnectionRequestType.Incoming, + connRequest.Data, + netPeer, + this)); } private void DataReceived(byte[] reusableBuffer, int count, IPEndPoint remoteEndPoint) @@ -819,13 +809,33 @@ private void DataReceived(byte[] reusableBuffer, int count, IPEndPoint remoteEnd return; } - //get peer - //Check normal packets NetPeer netPeer; - //old packets protection - bool peerFound = TryGetPeer(remoteEndPoint, out netPeer); - //Check unconnected + //special case connect request + if (packet.Property == PacketProperty.ConnectRequest) + { + if (NetConnectRequestPacket.GetProtocolId(packet) != NetConstants.ProtocolId) + { + SendRawAndRecycle(NetPacketPool.GetWithProperty(PacketProperty.InvalidProtocol, 0), remoteEndPoint); + return; + } + var connRequest = NetConnectRequestPacket.FromData(packet); + if (connRequest != null) + { + _peersLock.EnterUpgradeableReadLock(); + _peersDict.TryGetValue(remoteEndPoint, out netPeer); + //here new peer can be created + ProcessConnectRequest(remoteEndPoint, netPeer, connRequest); + _peersLock.ExitUpgradeableReadLock(); + } + return; + } + + _peersLock.EnterReadLock(); + bool peerFound = _peersDict.TryGetValue(remoteEndPoint, out netPeer); + _peersLock.ExitReadLock(); + + //Check normal packets switch (packet.Property) { case PacketProperty.PeerNotFound: @@ -907,16 +917,6 @@ private void DataReceived(byte[] reusableBuffer, int count, IPEndPoint remoteEnd if (connAccept != null && peerFound && netPeer.ProcessConnectAccept(connAccept)) CreateEvent(NetEvent.EType.Connect, netPeer); break; - case PacketProperty.ConnectRequest: - if (NetConnectRequestPacket.GetProtocolId(packet) != NetConstants.ProtocolId) - { - SendRawAndRecycle(NetPacketPool.GetWithProperty(PacketProperty.InvalidProtocol, 0), remoteEndPoint); - break; - } - var connRequest = NetConnectRequestPacket.FromData(packet); - if (connRequest != null) - ProcessConnectRequest(remoteEndPoint, netPeer, connRequest); - break; default: if(peerFound) netPeer.ProcessPacket(packet); @@ -1279,7 +1279,9 @@ public NetPeer Connect(IPEndPoint target, NetDataWriter connectionData) NetPeer peer; byte connectionNumber = 0; - if (TryGetPeer(target, out peer)) + + _peersLock.EnterUpgradeableReadLock(); + if (_peersDict.TryGetValue(target, out peer)) { switch (peer.ConnectionState) { @@ -1287,15 +1289,21 @@ public NetPeer Connect(IPEndPoint target, NetDataWriter connectionData) case ConnectionState.Connected: case ConnectionState.Outcoming: case ConnectionState.Incoming: + _peersLock.ExitUpgradeableReadLock(); return peer; } //else reconnect connectionNumber = (byte)((peer.ConnectionNum + 1) % NetConstants.MaxConnectionNumber); RemovePeer(peer); } + //Create reliable connection //And send connection request - return TryAddPeer(new NetPeer(this, target, GetNextPeerId(), connectionNumber, connectionData)); + peer = new NetPeer(this, target, GetNextPeerId(), connectionNumber, connectionData); + AddPeer(peer); + _peersLock.ExitUpgradeableReadLock(); + + return peer; } /// From 61ee9ada764bb4bab57fa1c269b87488a0672f0a Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Wed, 4 Dec 2019 22:50:02 +0200 Subject: [PATCH 028/554] Added RejectForce (disables reliable reject message) --- LiteNetLib/ConnectionRequest.cs | 50 ++++++++++++++++++++++++--------- LiteNetLib/NetManager.cs | 9 ++++-- LiteNetLib/NetPeer.cs | 4 ++- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/LiteNetLib/ConnectionRequest.cs b/LiteNetLib/ConnectionRequest.cs index 8bdbc7d4..d06f9715 100644 --- a/LiteNetLib/ConnectionRequest.cs +++ b/LiteNetLib/ConnectionRequest.cs @@ -14,17 +14,13 @@ internal enum ConnectionRequestResult { None, Accept, - Reject - } - - internal interface IConnectionRequestListener - { - void OnConnectionSolved(ConnectionRequest request, byte[] rejectData, int start, int length); + Reject, + RejectForce } public class ConnectionRequest { - private readonly IConnectionRequestListener _listener; + private readonly NetManager _listener; private int _used; public IPEndPoint RemoteEndPoint { get { return Peer.EndPoint; } } @@ -47,7 +43,7 @@ internal ConnectionRequest( ConnectionRequestType type, NetDataReader netDataReader, NetPeer peer, - IConnectionRequestListener listener) + NetManager listener) { ConnectionId = connectionId; ConnectionNumber = connectionNumber; @@ -91,28 +87,54 @@ public NetPeer Accept() _listener.OnConnectionSolved(this, null, 0, 0); return Peer; } - - public void Reject(byte[] rejectData, int start, int length) + + public void Reject(byte[] rejectData, int start, int length, bool force) { if (!TryActivate()) return; - Result = ConnectionRequestResult.Reject; + Result = force ? ConnectionRequestResult.RejectForce : ConnectionRequestResult.Reject; _listener.OnConnectionSolved(this, rejectData, start, length); } + public void Reject(byte[] rejectData, int start, int length) + { + Reject(rejectData, start, length, false); + } + + + public void RejectForce(byte[] rejectData, int start, int length) + { + Reject(rejectData, start, length, true); + } + + public void RejectForce() + { + Reject(null, 0, 0, true); + } + + public void RejectForce(byte[] rejectData) + { + Reject(rejectData, 0, rejectData.Length, true); + } + + public void RejectForce(NetDataWriter rejectData) + { + Reject(rejectData.Data, 0, rejectData.Length, true); + } + public void Reject() { - Reject(null, 0, 0); + Reject(null, 0, 0, false); } public void Reject(byte[] rejectData) { - Reject(rejectData, 0, rejectData.Length); + Reject(rejectData, 0, rejectData.Length, false); } public void Reject(NetDataWriter rejectData) { - Reject(rejectData.Data, 0, rejectData.Length); + Reject(rejectData.Data, 0, rejectData.Length, false); } } } diff --git a/LiteNetLib/NetManager.cs b/LiteNetLib/NetManager.cs index 44907606..dfbe42e0 100644 --- a/LiteNetLib/NetManager.cs +++ b/LiteNetLib/NetManager.cs @@ -698,12 +698,17 @@ void INetSocketListener.OnMessageReceived(byte[] data, int length, SocketError e } } - void IConnectionRequestListener.OnConnectionSolved(ConnectionRequest request, byte[] rejectData, int start, int length) + internal void OnConnectionSolved(ConnectionRequest request, byte[] rejectData, int start, int length) { if (request.Result == ConnectionRequestResult.Reject) { NetDebug.Write(NetLogLevel.Trace, "[NM] Peer connect reject."); - request.Peer.Reject(request.ConnectionId, request.ConnectionNumber, rejectData, start, length); + request.Peer.Reject(request.ConnectionId, request.ConnectionNumber, rejectData, start, length, false); + } + else if (request.Result == ConnectionRequestResult.RejectForce) + { + NetDebug.Write(NetLogLevel.Trace, "[NM] Peer connect reject force."); + request.Peer.Reject(request.ConnectionId, request.ConnectionNumber, rejectData, start, length, true); } else { diff --git a/LiteNetLib/NetPeer.cs b/LiteNetLib/NetPeer.cs index 2f13ac2b..ff301943 100644 --- a/LiteNetLib/NetPeer.cs +++ b/LiteNetLib/NetPeer.cs @@ -571,11 +571,13 @@ internal DisconnectResult ProcessDisconnect(NetPacket packet) return DisconnectResult.None; } - internal void Reject(long connectionId, byte connectionNumber, byte[] data, int start, int length) + internal void Reject(long connectionId, byte connectionNumber, byte[] data, int start, int length, bool force) { _connectTime = connectionId; _connectNum = connectionNumber; Shutdown(data, start, length, false); + if (force) + _connectionState = ConnectionState.Disconnected; } internal bool Shutdown(byte[] data, int start, int length, bool force) From c4b6a5022895045ab9adaacbe56dd3e416b4d476 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Wed, 4 Dec 2019 22:52:51 +0200 Subject: [PATCH 029/554] fix build --- LiteNetLib/NetManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LiteNetLib/NetManager.cs b/LiteNetLib/NetManager.cs index dfbe42e0..ce3d3692 100644 --- a/LiteNetLib/NetManager.cs +++ b/LiteNetLib/NetManager.cs @@ -78,7 +78,7 @@ public NetEvent(NetManager manager) /// /// Main class for all network operations. Can be used as client and/or server. /// - public class NetManager : INetSocketListener, IConnectionRequestListener, IEnumerable + public class NetManager : INetSocketListener, IEnumerable { private class IPEndPointComparer : IEqualityComparer { From ec40545ddd64c54a27d95a08e4ef1da05a0c1dc3 Mon Sep 17 00:00:00 2001 From: Ruslan Pyrch Date: Sun, 8 Dec 2019 20:43:47 +0200 Subject: [PATCH 030/554] Add docs --- docfx_project/articles/intro.md | 1 - docfx_project/articles/netserializerusage.md | 135 + docfx_project/articles/toc.yml | 4 +- docfx_project/index.md | 145 +- docs/api/LiteNetLib.ConnectionRequest.html | 517 ++ .../LiteNetLib.ConnectionRequestResult.html | 143 + .../api/LiteNetLib.ConnectionRequestType.html | 139 + docs/api/LiteNetLib.ConnectionState.html | 157 + docs/api/LiteNetLib.DeliveryMethod.html | 157 + docs/api/LiteNetLib.DisconnectInfo.html | 197 + docs/api/LiteNetLib.DisconnectReason.html | 168 + ...LiteNetLib.EventBasedNatPunchListener.html | 253 + .../api/LiteNetLib.EventBasedNetListener.html | 670 +++ .../LiteNetLib.IDeliveryEventListener.html | 154 + docs/api/LiteNetLib.INatPunchListener.html | 190 + docs/api/LiteNetLib.INetEventListener.html | 366 ++ docs/api/LiteNetLib.INetLogger.html | 159 + .../LiteNetLib.InvalidPacketException.html | 253 + docs/api/LiteNetLib.LocalAddrType.html | 145 + docs/api/LiteNetLib.NatPunchModule.html | 269 + docs/api/LiteNetLib.NetConstants.html | 391 ++ docs/api/LiteNetLib.NetDebug.html | 152 + docs/api/LiteNetLib.NetLogLevel.html | 147 + ...teNetLib.NetManager.NetPeerEnumerator.html | 265 + docs/api/LiteNetLib.NetManager.html | 2667 +++++++++ docs/api/LiteNetLib.NetPacketReader.html | 377 ++ docs/api/LiteNetLib.NetPeer.html | 1131 ++++ docs/api/LiteNetLib.NetStatistics.html | 336 ++ docs/api/LiteNetLib.NetUtils.html | 341 ++ .../api/LiteNetLib.TooBigPacketException.html | 253 + .../LiteNetLib.UnconnectedMessageType.html | 140 + .../LiteNetLib.Utils.FastBitConverter.html | 459 ++ .../LiteNetLib.Utils.INetSerializable.html | 175 + ...LiteNetLib.Utils.InvalidTypeException.html | 321 ++ docs/api/LiteNetLib.Utils.NetDataReader.html | 2562 +++++++++ docs/api/LiteNetLib.Utils.NetDataWriter.html | 1508 +++++ .../LiteNetLib.Utils.NetPacketProcessor.html | 1557 ++++++ docs/api/LiteNetLib.Utils.NetSerializer.html | 663 +++ .../LiteNetLib.Utils.NtpLeapIndicator.html | 156 + docs/api/LiteNetLib.Utils.NtpMode.html | 146 + docs/api/LiteNetLib.Utils.NtpPacket.html | 758 +++ docs/api/LiteNetLib.Utils.NtpRequest.html | 393 ++ docs/api/LiteNetLib.Utils.ParseException.html | 247 + docs/api/LiteNetLib.Utils.html | 158 + docs/api/LiteNetLib.html | 187 + docs/api/index.html | 107 + docs/api/toc.html | 147 + docs/articles/intro.html | 107 + docs/articles/netserializerusage.html | 234 + docs/articles/toc.html | 22 + docs/favicon.ico | Bin 0 -> 99678 bytes docs/fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes docs/fonts/glyphicons-halflings-regular.svg | 288 + docs/fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes docs/fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes docs/fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes docs/index.html | 285 + docs/logo.svg | 25 + docs/manifest.json | 618 +++ docs/search-stopwords.json | 121 + docs/styles/docfx.css | 962 ++++ docs/styles/docfx.js | 1175 ++++ docs/styles/docfx.vendor.css | 1464 +++++ docs/styles/docfx.vendor.js | 55 + docs/styles/lunr.js | 2924 ++++++++++ docs/styles/lunr.min.js | 1 + docs/styles/main.css | 0 docs/styles/main.js | 1 + docs/styles/search-worker.js | 80 + docs/toc.html | 25 + docs/xrefmap.yml | 4893 +++++++++++++++++ 71 files changed, 33239 insertions(+), 7 deletions(-) delete mode 100644 docfx_project/articles/intro.md create mode 100644 docfx_project/articles/netserializerusage.md create mode 100644 docs/api/LiteNetLib.ConnectionRequest.html create mode 100644 docs/api/LiteNetLib.ConnectionRequestResult.html create mode 100644 docs/api/LiteNetLib.ConnectionRequestType.html create mode 100644 docs/api/LiteNetLib.ConnectionState.html create mode 100644 docs/api/LiteNetLib.DeliveryMethod.html create mode 100644 docs/api/LiteNetLib.DisconnectInfo.html create mode 100644 docs/api/LiteNetLib.DisconnectReason.html create mode 100644 docs/api/LiteNetLib.EventBasedNatPunchListener.html create mode 100644 docs/api/LiteNetLib.EventBasedNetListener.html create mode 100644 docs/api/LiteNetLib.IDeliveryEventListener.html create mode 100644 docs/api/LiteNetLib.INatPunchListener.html create mode 100644 docs/api/LiteNetLib.INetEventListener.html create mode 100644 docs/api/LiteNetLib.INetLogger.html create mode 100644 docs/api/LiteNetLib.InvalidPacketException.html create mode 100644 docs/api/LiteNetLib.LocalAddrType.html create mode 100644 docs/api/LiteNetLib.NatPunchModule.html create mode 100644 docs/api/LiteNetLib.NetConstants.html create mode 100644 docs/api/LiteNetLib.NetDebug.html create mode 100644 docs/api/LiteNetLib.NetLogLevel.html create mode 100644 docs/api/LiteNetLib.NetManager.NetPeerEnumerator.html create mode 100644 docs/api/LiteNetLib.NetManager.html create mode 100644 docs/api/LiteNetLib.NetPacketReader.html create mode 100644 docs/api/LiteNetLib.NetPeer.html create mode 100644 docs/api/LiteNetLib.NetStatistics.html create mode 100644 docs/api/LiteNetLib.NetUtils.html create mode 100644 docs/api/LiteNetLib.TooBigPacketException.html create mode 100644 docs/api/LiteNetLib.UnconnectedMessageType.html create mode 100644 docs/api/LiteNetLib.Utils.FastBitConverter.html create mode 100644 docs/api/LiteNetLib.Utils.INetSerializable.html create mode 100644 docs/api/LiteNetLib.Utils.InvalidTypeException.html create mode 100644 docs/api/LiteNetLib.Utils.NetDataReader.html create mode 100644 docs/api/LiteNetLib.Utils.NetDataWriter.html create mode 100644 docs/api/LiteNetLib.Utils.NetPacketProcessor.html create mode 100644 docs/api/LiteNetLib.Utils.NetSerializer.html create mode 100644 docs/api/LiteNetLib.Utils.NtpLeapIndicator.html create mode 100644 docs/api/LiteNetLib.Utils.NtpMode.html create mode 100644 docs/api/LiteNetLib.Utils.NtpPacket.html create mode 100644 docs/api/LiteNetLib.Utils.NtpRequest.html create mode 100644 docs/api/LiteNetLib.Utils.ParseException.html create mode 100644 docs/api/LiteNetLib.Utils.html create mode 100644 docs/api/LiteNetLib.html create mode 100644 docs/api/index.html create mode 100644 docs/api/toc.html create mode 100644 docs/articles/intro.html create mode 100644 docs/articles/netserializerusage.html create mode 100644 docs/articles/toc.html create mode 100644 docs/favicon.ico create mode 100644 docs/fonts/glyphicons-halflings-regular.eot create mode 100644 docs/fonts/glyphicons-halflings-regular.svg create mode 100644 docs/fonts/glyphicons-halflings-regular.ttf create mode 100644 docs/fonts/glyphicons-halflings-regular.woff create mode 100644 docs/fonts/glyphicons-halflings-regular.woff2 create mode 100644 docs/index.html create mode 100644 docs/logo.svg create mode 100644 docs/manifest.json create mode 100644 docs/search-stopwords.json create mode 100644 docs/styles/docfx.css create mode 100644 docs/styles/docfx.js create mode 100644 docs/styles/docfx.vendor.css create mode 100644 docs/styles/docfx.vendor.js create mode 100644 docs/styles/lunr.js create mode 100644 docs/styles/lunr.min.js create mode 100644 docs/styles/main.css create mode 100644 docs/styles/main.js create mode 100644 docs/styles/search-worker.js create mode 100644 docs/toc.html create mode 100644 docs/xrefmap.yml diff --git a/docfx_project/articles/intro.md b/docfx_project/articles/intro.md deleted file mode 100644 index c0478ced..00000000 --- a/docfx_project/articles/intro.md +++ /dev/null @@ -1 +0,0 @@ -# Add your introductions here! diff --git a/docfx_project/articles/netserializerusage.md b/docfx_project/articles/netserializerusage.md new file mode 100644 index 00000000..b5d0c6ba --- /dev/null +++ b/docfx_project/articles/netserializerusage.md @@ -0,0 +1,135 @@ +**NetPacketProcessor** - fast specialized for network purposes serializer.
+It supports **classes** with **public properties with "get" and "set"** methods or **classes/structs with implemented `INetSerializable`**.
+Serializer adds some overhead in size: 64 bit hash of class name and namespace (8 bytes). All other class fields will be as is in resulting packet. +### Supported property types +```csharp +byte sbyte short ushort int uint long ulong float double bool string char IPEndPoint +byte[] short[] ushort[] int[] uint[] long[] ulong[] float[] double[] bool[] string[] +``` +### Serialization speed comparsion +Serialization 100_000 times of simple structure from [example](https://github.com/RevenantX/LiteNetLib/blob/master/LibSample/SerializerBenchmark.cs): +``` +BinaryFormatter time: 3418 ms +NetSerializer first run time: 127 ms +NetSerializer second run time: 99 ms +DataWriter (raw put method calls) time: 24 ms +``` +### Packet Example +```csharp +class SamplePacket +{ + public string SomeString { get; set; } + public float SomeFloat { get; set; } + public int[] SomeIntArray { get; set; } +} +``` +### Nested structs or classes +It does not supports nested structs or classes.
+But you can register custom type processor.
+That usefull for game engine types such as Vector3 and Quaternion (in Unity3d). +```csharp +//Your packet that will be sent over network +class SamplePacket +{ + public MyType SomeMyType { get; set; } + + //Arrays of custom types supported too + public MyType[] SomeMyTypes { get; set; } +} + +//Some custom type (variant 1) +struct MyType +{ + public int Value1; + public string Value2; + + public static void Serialize(NetDataWriter writer, SomeMyType mytype) + { + writer.Put(mytype.Value1); + writer.Put(mytype.Value2); + } + + public static MyType Deserialize(NetDataReader reader) + { + MyType res = new MyType(); + res.Value1 = reader.GetInt(); + res.Value2 = reader.GetString(); + return res; + } +} +... +netPacketProcessor = new NetPacketProcessor(); +netPacketProcessor.RegisterNestedType( MyType.Serialize, MyType.Deserialize ); +``` +Another variant you can implement INetSerializable interface: +```csharp +//Some custom type (variant 2) +struct SomeMyType : INetSerializable +{ + public int Value1; + public string Value2; + + public void Serialize(NetDataWriter writer) + { + writer.Put(Value1); + writer.Put(Value2); + } + + public void Deserialize(NetDataReader reader) + { + Value1 = reader.GetInt(); + Value2 = reader.GetString(); + } +} +... +netPacketProcessor = new NetPacketProcessor(); +netPacketProcessor.RegisterNestedType(); +``` +Or if you want use struct instead of class (and implement INetSerializable interface) +you must provide constructor: +```csharp +netPacketProcessor.RegisterNestedType(() => { return new SomeMyType(); }); +``` +# Usage example (for full example look at source [SerializerBenchmark](https://github.com/RevenantX/LiteNetLib/blob/master/LibSample/SerializerBenchmark.cs)) +```csharp +//First side +class SomeClientListener : INetEventListener +{ + private readonly NetPacketProcessor _netPacketProcessor = new NetPacketProcessor(); +... + public void OnPeerConnected(NetPeer peer) + { + SamplePacket sp = new SamplePacket + { + SomeFloat = 3.42f, + SomeIntArray = new[] {6, 5, 4}, + SomeString = "Test String", + } + peer.Send(_netPacketProcessor.Write(sp), DeliveryMethod.ReliableOrdered); + //or you can use _netPacketProcessor.Send(peer, sp, DeliveryMethod.ReliableOrdered); + } +} + +//Other side +class SomeServerListener : INetEventListener +{ + private readonly NetPacketProcessor _netPacketProcessor = new NetPacketProcessor(); + + public SomeServerListener() + { + //Subscribe to packet receiving + _netPacketProcessor.SubscribeReusable(OnSamplePacketReceived); + } + + private void OnSamplePacketReceived(SamplePacket samplePacket, NetPeer peer) + { + Console.WriteLine("[Server] ReceivedPacket:\n" + samplePacket.SomeString); + } + + public void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod) + { + Console.WriteLine("[Server] received data. Processing..."); + _netPacketProcessor.ReadAllPackets(reader, peer); + } +} +``` \ No newline at end of file diff --git a/docfx_project/articles/toc.yml b/docfx_project/articles/toc.yml index ff89ef1f..8be02d89 100644 --- a/docfx_project/articles/toc.yml +++ b/docfx_project/articles/toc.yml @@ -1,2 +1,2 @@ -- name: Introduction - href: intro.md +- name: NetSerializer usage + href: netserializerusage.md diff --git a/docfx_project/index.md b/docfx_project/index.md index 3ae25063..e56e5f61 100644 --- a/docfx_project/index.md +++ b/docfx_project/index.md @@ -1,4 +1,141 @@ -# This is the **HOMEPAGE**. -Refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files. -## Quick Start Notes: -1. Add images to the *images* folder if the file is referencing an image. +# LiteNetLib + +Lite reliable UDP library for .NET Framework 3.5, Mono, .NET Core 2.0, .NET Standard 2.0. + +[![Discord](https://img.shields.io/discord/501682175930925058.svg)](https://discord.gg/FATFPdy) + +[Little Game Example on Unity](https://github.com/RevenantX/NetGameExample) + +## Features + +* Lightweight + * Small CPU and RAM usage + * Small packet size overhead ( 1 byte for unreliable, 3 bytes for reliable packets ) +* Simple connection handling +* Peer to peer connections +* Helper classes for sending and reading messages +* Multiple data channels +* Different send mechanics + * Reliable with order + * Reliable without order + * Reliable sequenced (realiable only last packet) + * Ordered but unreliable with duplication prevention + * Simple UDP packets without order and reliability +* Fast packet serializer [(Usage manual)](https://github.com/RevenantX/LiteNetLib/wiki/NetSerializer-usage) +* Automatic small packets merging +* Automatic fragmentation of reliable packets +* Automatic MTU detection +* UDP NAT hole punching +* NTP time requests +* Packet loss and latency simulation +* IPv6 support (dual mode) +* Connection statisitcs (need DEBUG or STATS_ENABLED flag) +* Multicasting (for discovering hosts in local network) +* Unity support +* Supported platforms: + * Windows/Mac/Linux (.NET Framework, Mono, .NET Core) + * Android (Unity) + * iOS (Unity) + * UWP Windows 10 including phones + * Lumin OS (Magic Leap) + +## Unity notes!!! +* Always use library sources instead of precompiled DLL files ( because there are platform specific #ifdefs and workarounds for unity bugs ) + +## Usage samples + +### Client +```csharp +EventBasedNetListener listener = new EventBasedNetListener(); +NetManager client = new NetManager(listener); +client.Start(); +client.Connect("localhost" /* host ip or name */, 9050 /* port */, "SomeConnectionKey" /* text key or NetDataWriter */); +listener.NetworkReceiveEvent += (fromPeer, dataReader, deliveryMethod) => +{ + Console.WriteLine("We got: {0}", dataReader.GetString(100 /* max length of string */)); + dataReader.Recycle(); +}; + +while (!Console.KeyAvailable) +{ + client.PollEvents(); + Thread.Sleep(15); +} + +client.Stop(); +``` +### Server +```csharp +EventBasedNetListener listener = new EventBasedNetListener(); +NetManager server = new NetManager(listener); +server.Start(9050 /* port */); + +listener.ConnectionRequestEvent += request => +{ + if(server.PeersCount < 10 /* max connections */) + request.AcceptIfKey("SomeConnectionKey"); + else + request.Reject(); +}; + +listener.PeerConnectedEvent += peer => +{ + Console.WriteLine("We got connection: {0}", peer.EndPoint); // Show peer ip + NetDataWriter writer = new NetDataWriter(); // Create writer class + writer.Put("Hello client!"); // Put some string + peer.Send(writer, DeliveryMethod.ReliableOrdered); // Send with reliability +}; + +while (!Console.KeyAvailable) +{ + server.PollEvents(); + Thread.Sleep(15); +} +server.Stop(); +``` + +## NetManager settings description + +* **UnconnectedMessagesEnabled** + * enable messages receiving without connection. (with SendUnconnectedMessage method) + * default value: **false** +* **NatPunchEnabled** + * enable NAT punch messages + * default value: **false** +* **UpdateTime** + * library logic update (and send) period in milliseconds + * default value: **15 msec**. +* **PingInterval** + * Interval for latency detection and checking connection + * default value: **1000 msec**. +* **DisconnectTimeout** + * if client or server doesn't receive any packet from remote peer during this time then connection will be closed + * (including library internal keepalive packets) + * default value: **5000 msec**. +* **SimulatePacketLoss** + * simulate packet loss by dropping random amout of packets. (Works only in DEBUG mode) + * default value: **false** +* **SimulateLatency** + * simulate latency by holding packets for random time. (Works only in DEBUG mode) + * default value: **false** +* **SimulationPacketLossChance** + * chance of packet loss when simulation enabled. value in percents. + * default value: **10 (%)** +* **SimulationMinLatency** + * minimum simulated latency + * default value: **30 msec** +* **SimulationMaxLatency** + * maximum simulated latency + * default value: **100 msec** +* **BroadcastEnabled** + * Allows receive Broadcast packets + * default value: **false** +* **ReconnectDelay** + * delay betwen connection attempts + * default value: **500 msec** +* **MaxConnectAttempts** + * maximum connection attempts before client stops and call disconnect event. + * default value: **10** +* **UnsyncedEvents** + * Experimental feature. Events automatically will be called without PollEvents method from another thread + * default value: **false** diff --git a/docs/api/LiteNetLib.ConnectionRequest.html b/docs/api/LiteNetLib.ConnectionRequest.html new file mode 100644 index 00000000..3d333731 --- /dev/null +++ b/docs/api/LiteNetLib.ConnectionRequest.html @@ -0,0 +1,517 @@ + + + + + + + + Class ConnectionRequest + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + +
+ + + + + + diff --git a/docs/api/LiteNetLib.ConnectionRequestResult.html b/docs/api/LiteNetLib.ConnectionRequestResult.html new file mode 100644 index 00000000..96ed06c2 --- /dev/null +++ b/docs/api/LiteNetLib.ConnectionRequestResult.html @@ -0,0 +1,143 @@ + + + + + + + + Enum ConnectionRequestResult + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.ConnectionRequestType.html b/docs/api/LiteNetLib.ConnectionRequestType.html new file mode 100644 index 00000000..cdfc310b --- /dev/null +++ b/docs/api/LiteNetLib.ConnectionRequestType.html @@ -0,0 +1,139 @@ + + + + + + + + Enum ConnectionRequestType + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.ConnectionState.html b/docs/api/LiteNetLib.ConnectionState.html new file mode 100644 index 00000000..ed80de15 --- /dev/null +++ b/docs/api/LiteNetLib.ConnectionState.html @@ -0,0 +1,157 @@ + + + + + + + + Enum ConnectionState + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.DeliveryMethod.html b/docs/api/LiteNetLib.DeliveryMethod.html new file mode 100644 index 00000000..3f60f679 --- /dev/null +++ b/docs/api/LiteNetLib.DeliveryMethod.html @@ -0,0 +1,157 @@ + + + + + + + + Enum DeliveryMethod + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.DisconnectInfo.html b/docs/api/LiteNetLib.DisconnectInfo.html new file mode 100644 index 00000000..2a1a6c7e --- /dev/null +++ b/docs/api/LiteNetLib.DisconnectInfo.html @@ -0,0 +1,197 @@ + + + + + + + + Struct DisconnectInfo + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.DisconnectReason.html b/docs/api/LiteNetLib.DisconnectReason.html new file mode 100644 index 00000000..7549bad1 --- /dev/null +++ b/docs/api/LiteNetLib.DisconnectReason.html @@ -0,0 +1,168 @@ + + + + + + + + Enum DisconnectReason + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.EventBasedNatPunchListener.html b/docs/api/LiteNetLib.EventBasedNatPunchListener.html new file mode 100644 index 00000000..8c866fca --- /dev/null +++ b/docs/api/LiteNetLib.EventBasedNatPunchListener.html @@ -0,0 +1,253 @@ + + + + + + + + Class EventBasedNatPunchListener + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.EventBasedNetListener.html b/docs/api/LiteNetLib.EventBasedNetListener.html new file mode 100644 index 00000000..094b597c --- /dev/null +++ b/docs/api/LiteNetLib.EventBasedNetListener.html @@ -0,0 +1,670 @@ + + + + + + + + Class EventBasedNetListener + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.IDeliveryEventListener.html b/docs/api/LiteNetLib.IDeliveryEventListener.html new file mode 100644 index 00000000..dc0f4d8b --- /dev/null +++ b/docs/api/LiteNetLib.IDeliveryEventListener.html @@ -0,0 +1,154 @@ + + + + + + + + Interface IDeliveryEventListener + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.INatPunchListener.html b/docs/api/LiteNetLib.INatPunchListener.html new file mode 100644 index 00000000..97133048 --- /dev/null +++ b/docs/api/LiteNetLib.INatPunchListener.html @@ -0,0 +1,190 @@ + + + + + + + + Interface INatPunchListener + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.INetEventListener.html b/docs/api/LiteNetLib.INetEventListener.html new file mode 100644 index 00000000..7b4a732f --- /dev/null +++ b/docs/api/LiteNetLib.INetEventListener.html @@ -0,0 +1,366 @@ + + + + + + + + Interface INetEventListener + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.INetLogger.html b/docs/api/LiteNetLib.INetLogger.html new file mode 100644 index 00000000..d75535c6 --- /dev/null +++ b/docs/api/LiteNetLib.INetLogger.html @@ -0,0 +1,159 @@ + + + + + + + + Interface INetLogger + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.InvalidPacketException.html b/docs/api/LiteNetLib.InvalidPacketException.html new file mode 100644 index 00000000..ea78a9ee --- /dev/null +++ b/docs/api/LiteNetLib.InvalidPacketException.html @@ -0,0 +1,253 @@ + + + + + + + + Class InvalidPacketException + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.LocalAddrType.html b/docs/api/LiteNetLib.LocalAddrType.html new file mode 100644 index 00000000..f5b1e2e6 --- /dev/null +++ b/docs/api/LiteNetLib.LocalAddrType.html @@ -0,0 +1,145 @@ + + + + + + + + Enum LocalAddrType + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.NatPunchModule.html b/docs/api/LiteNetLib.NatPunchModule.html new file mode 100644 index 00000000..de98fc0a --- /dev/null +++ b/docs/api/LiteNetLib.NatPunchModule.html @@ -0,0 +1,269 @@ + + + + + + + + Class NatPunchModule + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.NetConstants.html b/docs/api/LiteNetLib.NetConstants.html new file mode 100644 index 00000000..540e1206 --- /dev/null +++ b/docs/api/LiteNetLib.NetConstants.html @@ -0,0 +1,391 @@ + + + + + + + + Class NetConstants + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.NetDebug.html b/docs/api/LiteNetLib.NetDebug.html new file mode 100644 index 00000000..b17ee377 --- /dev/null +++ b/docs/api/LiteNetLib.NetDebug.html @@ -0,0 +1,152 @@ + + + + + + + + Class NetDebug + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.NetLogLevel.html b/docs/api/LiteNetLib.NetLogLevel.html new file mode 100644 index 00000000..a580348f --- /dev/null +++ b/docs/api/LiteNetLib.NetLogLevel.html @@ -0,0 +1,147 @@ + + + + + + + + Enum NetLogLevel + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.NetManager.NetPeerEnumerator.html b/docs/api/LiteNetLib.NetManager.NetPeerEnumerator.html new file mode 100644 index 00000000..a56b9112 --- /dev/null +++ b/docs/api/LiteNetLib.NetManager.NetPeerEnumerator.html @@ -0,0 +1,265 @@ + + + + + + + + Struct NetManager.NetPeerEnumerator + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.NetManager.html b/docs/api/LiteNetLib.NetManager.html new file mode 100644 index 00000000..9b3d048d --- /dev/null +++ b/docs/api/LiteNetLib.NetManager.html @@ -0,0 +1,2667 @@ + + + + + + + + Class NetManager + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.NetPacketReader.html b/docs/api/LiteNetLib.NetPacketReader.html new file mode 100644 index 00000000..e5ae4145 --- /dev/null +++ b/docs/api/LiteNetLib.NetPacketReader.html @@ -0,0 +1,377 @@ + + + + + + + + Class NetPacketReader + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.NetPeer.html b/docs/api/LiteNetLib.NetPeer.html new file mode 100644 index 00000000..604d0368 --- /dev/null +++ b/docs/api/LiteNetLib.NetPeer.html @@ -0,0 +1,1131 @@ + + + + + + + + Class NetPeer + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.NetStatistics.html b/docs/api/LiteNetLib.NetStatistics.html new file mode 100644 index 00000000..e0c8c492 --- /dev/null +++ b/docs/api/LiteNetLib.NetStatistics.html @@ -0,0 +1,336 @@ + + + + + + + + Class NetStatistics + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.NetUtils.html b/docs/api/LiteNetLib.NetUtils.html new file mode 100644 index 00000000..961d6121 --- /dev/null +++ b/docs/api/LiteNetLib.NetUtils.html @@ -0,0 +1,341 @@ + + + + + + + + Class NetUtils + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.TooBigPacketException.html b/docs/api/LiteNetLib.TooBigPacketException.html new file mode 100644 index 00000000..811eaeae --- /dev/null +++ b/docs/api/LiteNetLib.TooBigPacketException.html @@ -0,0 +1,253 @@ + + + + + + + + Class TooBigPacketException + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.UnconnectedMessageType.html b/docs/api/LiteNetLib.UnconnectedMessageType.html new file mode 100644 index 00000000..e47ecdb0 --- /dev/null +++ b/docs/api/LiteNetLib.UnconnectedMessageType.html @@ -0,0 +1,140 @@ + + + + + + + + Enum UnconnectedMessageType + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.FastBitConverter.html b/docs/api/LiteNetLib.Utils.FastBitConverter.html new file mode 100644 index 00000000..17c45cfb --- /dev/null +++ b/docs/api/LiteNetLib.Utils.FastBitConverter.html @@ -0,0 +1,459 @@ + + + + + + + + Class FastBitConverter + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.INetSerializable.html b/docs/api/LiteNetLib.Utils.INetSerializable.html new file mode 100644 index 00000000..737d0262 --- /dev/null +++ b/docs/api/LiteNetLib.Utils.INetSerializable.html @@ -0,0 +1,175 @@ + + + + + + + + Interface INetSerializable + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.InvalidTypeException.html b/docs/api/LiteNetLib.Utils.InvalidTypeException.html new file mode 100644 index 00000000..c7fe920c --- /dev/null +++ b/docs/api/LiteNetLib.Utils.InvalidTypeException.html @@ -0,0 +1,321 @@ + + + + + + + + Class InvalidTypeException + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.NetDataReader.html b/docs/api/LiteNetLib.Utils.NetDataReader.html new file mode 100644 index 00000000..d1110a74 --- /dev/null +++ b/docs/api/LiteNetLib.Utils.NetDataReader.html @@ -0,0 +1,2562 @@ + + + + + + + + Class NetDataReader + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.NetDataWriter.html b/docs/api/LiteNetLib.Utils.NetDataWriter.html new file mode 100644 index 00000000..244e45ba --- /dev/null +++ b/docs/api/LiteNetLib.Utils.NetDataWriter.html @@ -0,0 +1,1508 @@ + + + + + + + + Class NetDataWriter + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.NetPacketProcessor.html b/docs/api/LiteNetLib.Utils.NetPacketProcessor.html new file mode 100644 index 00000000..50fedead --- /dev/null +++ b/docs/api/LiteNetLib.Utils.NetPacketProcessor.html @@ -0,0 +1,1557 @@ + + + + + + + + Class NetPacketProcessor + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.NetSerializer.html b/docs/api/LiteNetLib.Utils.NetSerializer.html new file mode 100644 index 00000000..3eb938d3 --- /dev/null +++ b/docs/api/LiteNetLib.Utils.NetSerializer.html @@ -0,0 +1,663 @@ + + + + + + + + Class NetSerializer + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.NtpLeapIndicator.html b/docs/api/LiteNetLib.Utils.NtpLeapIndicator.html new file mode 100644 index 00000000..fc7a842f --- /dev/null +++ b/docs/api/LiteNetLib.Utils.NtpLeapIndicator.html @@ -0,0 +1,156 @@ + + + + + + + + Enum NtpLeapIndicator + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.NtpMode.html b/docs/api/LiteNetLib.Utils.NtpMode.html new file mode 100644 index 00000000..60f4446c --- /dev/null +++ b/docs/api/LiteNetLib.Utils.NtpMode.html @@ -0,0 +1,146 @@ + + + + + + + + Enum NtpMode + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.NtpPacket.html b/docs/api/LiteNetLib.Utils.NtpPacket.html new file mode 100644 index 00000000..647e8897 --- /dev/null +++ b/docs/api/LiteNetLib.Utils.NtpPacket.html @@ -0,0 +1,758 @@ + + + + + + + + Class NtpPacket + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.NtpRequest.html b/docs/api/LiteNetLib.Utils.NtpRequest.html new file mode 100644 index 00000000..12754597 --- /dev/null +++ b/docs/api/LiteNetLib.Utils.NtpRequest.html @@ -0,0 +1,393 @@ + + + + + + + + Class NtpRequest + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.ParseException.html b/docs/api/LiteNetLib.Utils.ParseException.html new file mode 100644 index 00000000..10003b93 --- /dev/null +++ b/docs/api/LiteNetLib.Utils.ParseException.html @@ -0,0 +1,247 @@ + + + + + + + + Class ParseException + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.Utils.html b/docs/api/LiteNetLib.Utils.html new file mode 100644 index 00000000..780abae5 --- /dev/null +++ b/docs/api/LiteNetLib.Utils.html @@ -0,0 +1,158 @@ + + + + + + + + Namespace LiteNetLib.Utils + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/LiteNetLib.html b/docs/api/LiteNetLib.html new file mode 100644 index 00000000..d06203db --- /dev/null +++ b/docs/api/LiteNetLib.html @@ -0,0 +1,187 @@ + + + + + + + + Namespace LiteNetLib + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/index.html b/docs/api/index.html new file mode 100644 index 00000000..a420ade7 --- /dev/null +++ b/docs/api/index.html @@ -0,0 +1,107 @@ + + + + + + + + LiteNetLib + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/api/toc.html b/docs/api/toc.html new file mode 100644 index 00000000..c99347b1 --- /dev/null +++ b/docs/api/toc.html @@ -0,0 +1,147 @@ + + \ No newline at end of file diff --git a/docs/articles/intro.html b/docs/articles/intro.html new file mode 100644 index 00000000..71539329 --- /dev/null +++ b/docs/articles/intro.html @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/articles/netserializerusage.html b/docs/articles/netserializerusage.html new file mode 100644 index 00000000..a20e802a --- /dev/null +++ b/docs/articles/netserializerusage.html @@ -0,0 +1,234 @@ + + + + + + + + Supported property types + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/articles/toc.html b/docs/articles/toc.html new file mode 100644 index 00000000..2c8288e9 --- /dev/null +++ b/docs/articles/toc.html @@ -0,0 +1,22 @@ + +
+
+
+
+ + + +
+
+
+
+ + +
+
+
+
\ No newline at end of file diff --git a/docs/favicon.ico b/docs/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..71570f61efd250abdc3bffd77a96c6986109bb85 GIT binary patch literal 99678 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 IhS>=GA3>?ZjsO4v literal 0 HcmV?d00001 diff --git a/docs/fonts/glyphicons-halflings-regular.eot b/docs/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000000000000000000000000000000000000..b93a4953fff68df523aa7656497ee339d6026d64 GIT binary patch literal 20127 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/glyphicons-halflings-regular.ttf b/docs/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1413fc609ab6f21774de0cb7e01360095584f65b GIT binary patch literal 45404 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 G`u_lkUM?>H literal 0 HcmV?d00001 diff --git a/docs/fonts/glyphicons-halflings-regular.woff2 b/docs/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..64539b54c3751a6d9adb44c8e3a45ba5a73b77f0 GIT binary patch literal 18028 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 literal 0 HcmV?d00001 diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..bb884d30 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,285 @@ + + + + + + + + LiteNetLib + + + + + + + + + + + + + + + +
+
+ + + + +
+ + + +
+ + + + + + diff --git a/docs/logo.svg b/docs/logo.svg new file mode 100644 index 00000000..ccb2d7bc --- /dev/null +++ b/docs/logo.svg @@ -0,0 +1,25 @@ + + + + +Created by Docfx + + + + + + + diff --git a/docs/manifest.json b/docs/manifest.json new file mode 100644 index 00000000..8dd8d31d --- /dev/null +++ b/docs/manifest.json @@ -0,0 +1,618 @@ +{ + "homepages": [], + "source_base_path": "E:/Projects/LiteNetLib/docfx_project", + "xrefmap": "xrefmap.yml", + "files": [ + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.ConnectionRequest.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.ConnectionRequest.html", + "hash": "vGAmCz0sDrRmix4QOrDLew==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.ConnectionRequestType.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.ConnectionRequestType.html", + "hash": "aGcKDl1caOliCmYFbLIqyg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.ConnectionState.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.ConnectionState.html", + "hash": "VG64pBOi/xM9cK5NM/uzyQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.DeliveryMethod.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.DeliveryMethod.html", + "hash": "JzdHBSzdib2JBHFz7SdWjQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.DisconnectInfo.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.DisconnectInfo.html", + "hash": "7gidP7cD1PDPfFGaeCuzAA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.DisconnectReason.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.DisconnectReason.html", + "hash": "tF5XlVYs2sNZp42XCR+aOQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.EventBasedNatPunchListener.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.EventBasedNatPunchListener.html", + "hash": "Oc1p0EyPt9hAWQMNJQ3XqA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.EventBasedNetListener.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.EventBasedNetListener.html", + "hash": "/ia/VpfYfpSqri4pzYqqfw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.IDeliveryEventListener.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.IDeliveryEventListener.html", + "hash": "RW6qK9AlKkkT+zWW+O7WWA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.INatPunchListener.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.INatPunchListener.html", + "hash": "INiuEicsC6zqQKhA58X4Ag==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.INetEventListener.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.INetEventListener.html", + "hash": "VOVA1Ujfd191BX5fX1pXDA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.INetLogger.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.INetLogger.html", + "hash": "RUdfvdsH5AcIypIcWalYVA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.InvalidPacketException.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.InvalidPacketException.html", + "hash": "hTaG2y8/5r4lZ+BLmaAkhA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.LocalAddrType.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.LocalAddrType.html", + "hash": "rovQ0FpjP1OuZpgk5CqJMA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.NatPunchModule.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.NatPunchModule.html", + "hash": "mgnUj5uiJV3t50JyQNbR6g==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.NetConstants.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.NetConstants.html", + "hash": "JRyBwCUltaUgqs6io2ymjg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.NetDebug.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.NetDebug.html", + "hash": "XYpKs2q3BU5M6RCVaIwgbQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.NetLogLevel.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.NetLogLevel.html", + "hash": "35fiG6+iusCnnVU0gBZHuQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.NetManager.NetPeerEnumerator.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.NetManager.NetPeerEnumerator.html", + "hash": "LfWEuOYi6xDLjZL01HoYTA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.NetManager.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.NetManager.html", + "hash": "/nA/ADgjmXsX+FgKmMkA0A==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.NetPacketReader.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.NetPacketReader.html", + "hash": "9dHh5XxlcCeb2K83pKQM4A==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.NetPeer.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.NetPeer.html", + "hash": "CfUMKFtp7TivsbHT7bmgzQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.NetStatistics.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.NetStatistics.html", + "hash": "36Vu/8cw1P8aKCSM9uIn3A==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.NetUtils.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.NetUtils.html", + "hash": "rQ3lJcl+QO007jMcZjPFJw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.TooBigPacketException.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.TooBigPacketException.html", + "hash": "ocHTVNxcxoIFvQfhkHwsJw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.UnconnectedMessageType.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.UnconnectedMessageType.html", + "hash": "2CjTODzoL4TI7MrCZtzvLg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.FastBitConverter.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.FastBitConverter.html", + "hash": "YAVWfLPP78SCAjuH/Usw1g==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.INetSerializable.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.INetSerializable.html", + "hash": "MF30tbH6EK9WddtcnqXBEQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.InvalidTypeException.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.InvalidTypeException.html", + "hash": "qVgSY6t2rO6+Cy7x7/VcRw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.NetDataReader.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.NetDataReader.html", + "hash": "u3NxtM096n9W5eoVjgznLw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.NetDataWriter.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.NetDataWriter.html", + "hash": "dntvdmGb76rrffkkf+lHxg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.NetPacketProcessor.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.NetPacketProcessor.html", + "hash": "MJL8DRl5UmTRMLEVhIXseg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.NetSerializer.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.NetSerializer.html", + "hash": "gXBlw7I4Za5HvTIhpig1kg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.NtpLeapIndicator.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.NtpLeapIndicator.html", + "hash": "Ti0tKqozAR1ko45p7oxmpQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.NtpMode.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.NtpMode.html", + "hash": "kJBpz8QEtoQrcJpmNp6fAw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.NtpPacket.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.NtpPacket.html", + "hash": "inXgcaLJcmZGmJu86oI84w==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.NtpRequest.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.NtpRequest.html", + "hash": "nC+q8AZc4aJ+/q30bRE0yg==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.ParseException.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.ParseException.html", + "hash": "J1zoAtjAtr8jzzucv6Sulw==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.Utils.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.Utils.html", + "hash": "JT5tZ1XYchhDMBqzu/nI+g==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "api/LiteNetLib.yml", + "output": { + ".html": { + "relative_path": "api/LiteNetLib.html", + "hash": "f2iu4i46zDCC/ELQSFDx+w==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "Conceptual", + "source_relative_path": "api/index.md", + "output": { + ".html": { + "relative_path": "api/index.html", + "hash": "p/U6XZXuE/M9TtqgP/nhmQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "Toc", + "source_relative_path": "api/toc.yml", + "output": { + ".html": { + "relative_path": "api/toc.html", + "hash": "xXBEinm+vky9fW9pCxQuPQ==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "Conceptual", + "source_relative_path": "articles/intro.md", + "output": { + ".html": { + "relative_path": "articles/intro.html", + "hash": "HjhdRbhgXLuu+xvFYgnObQ==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "Conceptual", + "source_relative_path": "articles/netserializerusage.md", + "output": { + ".html": { + "relative_path": "articles/netserializerusage.html", + "hash": "Gn8+mHuqmY02c2YD1YxLGA==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "Toc", + "source_relative_path": "articles/toc.yml", + "output": { + ".html": { + "relative_path": "articles/toc.html", + "hash": "qzqDYS06xf+AljnrgcmZiw==" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "Conceptual", + "source_relative_path": "index.md", + "output": { + ".html": { + "relative_path": "index.html", + "hash": "vxwBs/uutHU5S2OaVcsZbQ==" + } + }, + "is_incremental": true, + "version": "" + }, + { + "type": "Toc", + "source_relative_path": "toc.yml", + "output": { + ".html": { + "relative_path": "toc.html", + "hash": "W7jy2EhK8cjyrdOBaz/Y7w==" + } + }, + "is_incremental": false, + "version": "" + } + ], + "incremental_info": [ + { + "status": { + "can_incremental": true, + "incrementalPhase": "build", + "total_file_count": 0, + "skipped_file_count": 0 + }, + "processors": { + "TocDocumentProcessor": { + "can_incremental": false, + "details": "Processor TocDocumentProcessor cannot support incremental build because the processor doesn't implement ISupportIncrementalDocumentProcessor interface.", + "incrementalPhase": "build", + "total_file_count": 0, + "skipped_file_count": 0 + }, + "ConceptualDocumentProcessor": { + "can_incremental": true, + "incrementalPhase": "build", + "total_file_count": 4, + "skipped_file_count": 3 + }, + "ManagedReferenceDocumentProcessor": { + "can_incremental": true, + "incrementalPhase": "build", + "total_file_count": 40, + "skipped_file_count": 40 + } + } + }, + { + "status": { + "can_incremental": true, + "details": "Can support incremental post processing.", + "incrementalPhase": "postProcessing", + "total_file_count": 0, + "skipped_file_count": 0 + }, + "processors": {} + } + ], + "version_info": {}, + "groups": [ + { + "xrefmap": "xrefmap.yml" + } + ] +} \ No newline at end of file diff --git a/docs/search-stopwords.json b/docs/search-stopwords.json new file mode 100644 index 00000000..0bdcc2c0 --- /dev/null +++ b/docs/search-stopwords.json @@ -0,0 +1,121 @@ +[ + "a", + "able", + "about", + "across", + "after", + "all", + "almost", + "also", + "am", + "among", + "an", + "and", + "any", + "are", + "as", + "at", + "be", + "because", + "been", + "but", + "by", + "can", + "cannot", + "could", + "dear", + "did", + "do", + "does", + "either", + "else", + "ever", + "every", + "for", + "from", + "get", + "got", + "had", + "has", + "have", + "he", + "her", + "hers", + "him", + "his", + "how", + "however", + "i", + "if", + "in", + "into", + "is", + "it", + "its", + "just", + "least", + "let", + "like", + "likely", + "may", + "me", + "might", + "most", + "must", + "my", + "neither", + "no", + "nor", + "not", + "of", + "off", + "often", + "on", + "only", + "or", + "other", + "our", + "own", + "rather", + "said", + "say", + "says", + "she", + "should", + "since", + "so", + "some", + "than", + "that", + "the", + "their", + "them", + "then", + "there", + "these", + "they", + "this", + "tis", + "to", + "too", + "twas", + "us", + "wants", + "was", + "we", + "were", + "what", + "when", + "where", + "which", + "while", + "who", + "whom", + "why", + "will", + "with", + "would", + "yet", + "you", + "your" +] diff --git a/docs/styles/docfx.css b/docs/styles/docfx.css new file mode 100644 index 00000000..dc00b040 --- /dev/null +++ b/docs/styles/docfx.css @@ -0,0 +1,962 @@ +/* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. */ +html, +body { + font-family: 'Segoe UI', Tahoma, Helvetica, sans-serif; + height: 100%; +} +button, +a { + color: #337ab7; + cursor: pointer; +} +button:hover, +button:focus, +a:hover, +a:focus { + color: #23527c; + text-decoration: none; +} +a.disable, +a.disable:hover { + text-decoration: none; + cursor: default; + color: #000000; +} + +h1, h2, h3, h4, h5, h6, .text-break { + word-wrap: break-word; + word-break: break-word; +} + +h1 mark, +h2 mark, +h3 mark, +h4 mark, +h5 mark, +h6 mark { + padding: 0; +} + +.inheritance .level0:before, +.inheritance .level1:before, +.inheritance .level2:before, +.inheritance .level3:before, +.inheritance .level4:before, +.inheritance .level5:before { + content: '↳'; + margin-right: 5px; +} + +.inheritance .level0 { + margin-left: 0em; +} + +.inheritance .level1 { + margin-left: 1em; +} + +.inheritance .level2 { + margin-left: 2em; +} + +.inheritance .level3 { + margin-left: 3em; +} + +.inheritance .level4 { + margin-left: 4em; +} + +.inheritance .level5 { + margin-left: 5em; +} + +span.parametername, +span.paramref, +span.typeparamref { + font-style: italic; +} +span.languagekeyword{ + font-weight: bold; +} + +svg:hover path { + fill: #ffffff; +} + +.hljs { + display: inline; + background-color: inherit; + padding: 0; +} +/* additional spacing fixes */ +.btn + .btn { + margin-left: 10px; +} +.btn.pull-right { + margin-left: 10px; + margin-top: 5px; +} +.table { + margin-bottom: 10px; +} +table p { + margin-bottom: 0; +} +table a { + display: inline-block; +} + +/* Make hidden attribute compatible with old browser.*/ +[hidden] { + display: none !important; +} + +h1, +.h1, +h2, +.h2, +h3, +.h3 { + margin-top: 15px; + margin-bottom: 10px; + font-weight: 400; +} +h4, +.h4, +h5, +.h5, +h6, +.h6 { + margin-top: 10px; + margin-bottom: 5px; +} +.navbar { + margin-bottom: 0; +} +#wrapper { + min-height: 100%; + position: relative; +} +/* blends header footer and content together with gradient effect */ +.grad-top { + /* For Safari 5.1 to 6.0 */ + /* For Opera 11.1 to 12.0 */ + /* For Firefox 3.6 to 15 */ + background: linear-gradient(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0)); + /* Standard syntax */ + height: 5px; +} +.grad-bottom { + /* For Safari 5.1 to 6.0 */ + /* For Opera 11.1 to 12.0 */ + /* For Firefox 3.6 to 15 */ + background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.05)); + /* Standard syntax */ + height: 5px; +} +.divider { + margin: 0 5px; + color: #cccccc; +} +hr { + border-color: #cccccc; +} +header { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; +} +header .navbar { + border-width: 0 0 1px; + border-radius: 0; +} +.navbar-brand { + font-size: inherit; + padding: 0; +} +.navbar-collapse { + margin: 0 -15px; +} +.subnav { + min-height: 40px; +} + +.inheritance h5, .inheritedMembers h5{ + padding-bottom: 5px; + border-bottom: 1px solid #ccc; +} + +article h1, article h2, article h3, article h4{ + margin-top: 25px; +} + +article h4{ + border-bottom: 1px solid #ccc; +} + +article span.small.pull-right{ + margin-top: 20px; +} + +article section { + margin-left: 1em; +} + +/*.expand-all { + padding: 10px 0; +}*/ +.breadcrumb { + margin: 0; + padding: 10px 0; + background-color: inherit; + white-space: nowrap; +} +.breadcrumb > li + li:before { + content: "\00a0/"; +} +#autocollapse.collapsed .navbar-header { + float: none; +} +#autocollapse.collapsed .navbar-toggle { + display: block; +} +#autocollapse.collapsed .navbar-collapse { + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); +} +#autocollapse.collapsed .navbar-collapse.collapse { + display: none !important; +} +#autocollapse.collapsed .navbar-nav { + float: none !important; + margin: 7.5px -15px; +} +#autocollapse.collapsed .navbar-nav > li { + float: none; +} +#autocollapse.collapsed .navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; +} +#autocollapse.collapsed .collapse.in, +#autocollapse.collapsed .collapsing { + display: block !important; +} +#autocollapse.collapsed .collapse.in .navbar-right, +#autocollapse.collapsed .collapsing .navbar-right { + float: none !important; +} +#autocollapse .form-group { + width: 100%; +} +#autocollapse .form-control { + width: 100%; +} +#autocollapse .navbar-header { + margin-left: 0; + margin-right: 0; +} +#autocollapse .navbar-brand { + margin-left: 0; +} +.collapse.in, +.collapsing { + text-align: center; +} +.collapsing .navbar-form { + margin: 0 auto; + max-width: 400px; + padding: 10px 15px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); +} +.collapsed .collapse.in .navbar-form { + margin: 0 auto; + max-width: 400px; + padding: 10px 15px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); +} +.navbar .navbar-nav { + display: inline-block; +} +.docs-search { + background: white; + vertical-align: middle; +} +.docs-search > .search-query { + font-size: 14px; + border: 0; + width: 120%; + color: #555; +} +.docs-search > .search-query:focus { + outline: 0; +} +.search-results-frame { + clear: both; + display: table; + width: 100%; +} +.search-results.ng-hide { + display: none; +} +.search-results-container { + padding-bottom: 1em; + border-top: 1px solid #111; + background: rgba(25, 25, 25, 0.5); +} +.search-results-container .search-results-group { + padding-top: 50px !important; + padding: 10px; +} +.search-results-group-heading { + font-family: "Open Sans"; + padding-left: 10px; + color: white; +} +.search-close { + position: absolute; + left: 50%; + margin-left: -100px; + color: white; + text-align: center; + padding: 5px; + background: #333; + border-top-right-radius: 5px; + border-top-left-radius: 5px; + width: 200px; + box-shadow: 0 0 10px #111; +} +#search { + display: none; +} + +/* Search results display*/ +#search-results { + max-width: 960px !important; + margin-top: 120px; + margin-bottom: 115px; + margin-left: auto; + margin-right: auto; + line-height: 1.8; + display: none; +} + +#search-results>.search-list { + text-align: center; + font-size: 2.5rem; + margin-bottom: 50px; +} + +#search-results p { + text-align: center; +} + +#search-results p .index-loading { + animation: index-loading 1.5s infinite linear; + -webkit-animation: index-loading 1.5s infinite linear; + -o-animation: index-loading 1.5s infinite linear; + font-size: 2.5rem; +} + +@keyframes index-loading { + from { transform: scale(1) rotate(0deg);} + to { transform: scale(1) rotate(360deg);} +} + +@-webkit-keyframes index-loading { + from { -webkit-transform: rotate(0deg);} + to { -webkit-transform: rotate(360deg);} +} + +@-o-keyframes index-loading { + from { -o-transform: rotate(0deg);} + to { -o-transform: rotate(360deg);} +} + +#search-results .sr-items { + font-size: 24px; +} + +.sr-item { + margin-bottom: 25px; +} + +.sr-item>.item-href { + font-size: 14px; + color: #093; +} + +.sr-item>.item-brief { + font-size: 13px; +} + +.pagination>li>a { + color: #47A7A0 +} + +.pagination>.active>a { + background-color: #47A7A0; + border-color: #47A7A0; +} + +.fixed_header { + position: fixed; + width: 100%; + padding-bottom: 10px; + padding-top: 10px; + margin: 0px; + top: 0; + z-index: 9999; + left: 0; +} + +.fixed_header+.toc{ + margin-top: 50px; + margin-left: 0; +} + +.sidenav, .fixed_header, .toc { + background-color: #f1f1f1; +} + +.sidetoc { + position: fixed; + width: 260px; + top: 150px; + bottom: 0; + overflow-x: hidden; + overflow-y: auto; + background-color: #f1f1f1; + border-left: 1px solid #e7e7e7; + border-right: 1px solid #e7e7e7; + z-index: 1; +} + +.sidetoc.shiftup { + bottom: 70px; +} + +body .toc{ + background-color: #f1f1f1; + overflow-x: hidden; +} + +.sidetoggle.ng-hide { + display: block !important; +} +.sidetoc-expand > .caret { + margin-left: 0px; + margin-top: -2px; +} +.sidetoc-expand > .caret-side { + border-left: 4px solid; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + margin-left: 4px; + margin-top: -4px; +} +.sidetoc-heading { + font-weight: 500; +} + +.toc { + margin: 0px 0 0 10px; + padding: 0 10px; +} +.expand-stub { + position: absolute; + left: -10px; +} +.toc .nav > li > a.sidetoc-expand { + position: absolute; + top: 0; + left: 0; +} +.toc .nav > li > a { + color: #666666; + margin-left: 5px; + display: block; + padding: 0; +} +.toc .nav > li > a:hover, +.toc .nav > li > a:focus { + color: #000000; + background: none; + text-decoration: inherit; +} +.toc .nav > li.active > a { + color: #337ab7; +} +.toc .nav > li.active > a:hover, +.toc .nav > li.active > a:focus { + color: #23527c; +} + +.toc .nav > li> .expand-stub { + cursor: pointer; +} + +.toc .nav > li.active > .expand-stub::before, +.toc .nav > li.in > .expand-stub::before, +.toc .nav > li.in.active > .expand-stub::before, +.toc .nav > li.filtered > .expand-stub::before { + content: "-"; +} + +.toc .nav > li > .expand-stub::before, +.toc .nav > li.active > .expand-stub::before { + content: "+"; +} + +.toc .nav > li.filtered > ul, +.toc .nav > li.in > ul { + display: block; +} + +.toc .nav > li > ul { + display: none; +} + +.toc ul{ + font-size: 12px; + margin: 0 0 0 3px; +} + +.toc .level1 > li { + font-weight: bold; + margin-top: 10px; + position: relative; + font-size: 16px; +} +.toc .level2 { + font-weight: normal; + margin: 5px 0 0 15px; + font-size: 14px; +} +.toc-toggle { + display: none; + margin: 0 15px 0px 15px; +} +.sidefilter { + position: fixed; + top: 90px; + width: 260px; + background-color: #f1f1f1; + padding: 15px; + border-left: 1px solid #e7e7e7; + border-right: 1px solid #e7e7e7; + z-index: 1; +} +.toc-filter { + border-radius: 5px; + background: #fff; + color: #666666; + padding: 5px; + position: relative; + margin: 0 5px 0 5px; +} +.toc-filter > input { + border: 0; + color: #666666; + padding-left: 20px; + padding-right: 20px; + width: 100%; +} +.toc-filter > input:focus { + outline: 0; +} +.toc-filter > .filter-icon { + position: absolute; + top: 10px; + left: 5px; +} +.toc-filter > .clear-icon { + position: absolute; + top: 10px; + right: 5px; +} +.article { + margin-top: 120px; + margin-bottom: 115px; +} + +#_content>a{ + margin-top: 105px; +} + +.article.grid-right { + margin-left: 280px; +} + +.inheritance hr { + margin-top: 5px; + margin-bottom: 5px; +} +.article img { + max-width: 100%; +} +.sideaffix { + margin-top: 50px; + font-size: 12px; + max-height: 100%; + overflow: hidden; + top: 100px; + bottom: 10px; + position: fixed; +} +.sideaffix.shiftup { + bottom: 70px; +} +.affix { + position: relative; + height: 100%; +} +.sideaffix > div.contribution { + margin-bottom: 20px; +} +.sideaffix > div.contribution > ul > li > a.contribution-link { + padding: 6px 10px; + font-weight: bold; + font-size: 14px; +} +.sideaffix > div.contribution > ul > li > a.contribution-link:hover { + background-color: #ffffff; +} +.sideaffix ul.nav > li > a:focus { + background: none; +} +.affix h5 { + font-weight: bold; + text-transform: uppercase; + padding-left: 10px; + font-size: 12px; +} +.affix > ul.level1 { + overflow: hidden; + padding-bottom: 10px; + height: calc(100% - 100px); +} +.affix ul > li > a:before { + color: #cccccc; + position: absolute; +} +.affix ul > li > a:hover { + background: none; + color: #666666; +} +.affix ul > li.active > a, +.affix ul > li.active > a:before { + color: #337ab7; +} +.affix ul > li > a { + padding: 5px 12px; + color: #666666; +} +.affix > ul > li.active:last-child { + margin-bottom: 50px; +} +.affix > ul > li > a:before { + content: "|"; + font-size: 16px; + top: 1px; + left: 0; +} +.affix > ul > li.active > a, +.affix > ul > li.active > a:before { + color: #337ab7; + font-weight: bold; +} +.affix ul ul > li > a { + padding: 2px 15px; +} +.affix ul ul > li > a:before { + content: ">"; + font-size: 14px; + top: -1px; + left: 5px; +} +.affix ul > li > a:before, +.affix ul ul { + display: none; +} +.affix ul > li.active > ul, +.affix ul > li.active > a:before, +.affix ul > li > a:hover:before { + display: block; + white-space: nowrap; +} +.codewrapper { + position: relative; +} +.trydiv { + height: 0px; +} +.tryspan { + position: absolute; + top: 0px; + right: 0px; + border-style: solid; + border-radius: 0px 4px; + box-sizing: border-box; + border-width: 1px; + border-color: #cccccc; + text-align: center; + padding: 2px 8px; + background-color: white; + font-size: 12px; + cursor: pointer; + z-index: 100; + display: none; + color: #767676; +} +.tryspan:hover { + background-color: #3b8bd0; + color: white; + border-color: #3b8bd0; +} +.codewrapper:hover .tryspan { + display: block; +} +.sample-response .response-content{ + max-height: 200px; +} +footer { + position: absolute; + left: 0; + right: 0; + bottom: 0; + z-index: 1000; +} +.footer { + border-top: 1px solid #e7e7e7; + background-color: #f8f8f8; + padding: 15px 0; +} +@media (min-width: 768px) { + #sidetoggle.collapse { + display: block; + } + .topnav .navbar-nav { + float: none; + white-space: nowrap; + } + .topnav .navbar-nav > li { + float: none; + display: inline-block; + } +} +@media only screen and (max-width: 768px) { + #mobile-indicator { + display: block; + } + /* TOC display for responsive */ + .article { + margin-top: 30px !important; + } + header { + position: static; + } + .topnav { + text-align: center; + } + .sidenav { + padding: 15px 0; + margin-left: -15px; + margin-right: -15px; + } + .sidefilter { + position: static; + width: auto; + float: none; + border: none; + } + .sidetoc { + position: static; + width: auto; + float: none; + padding-bottom: 0px; + border: none; + } + .toc .nav > li, .toc .nav > li >a { + display: inline-block; + } + .toc li:after { + margin-left: -3px; + margin-right: 5px; + content: ", "; + color: #666666; + } + .toc .level1 > li { + display: block; + } + + .toc .level1 > li:after { + display: none; + } + .article.grid-right { + margin-left: 0; + } + .grad-top, + .grad-bottom { + display: none; + } + .toc-toggle { + display: block; + } + .sidetoggle.ng-hide { + display: none !important; + } + /*.expand-all { + display: none; + }*/ + .sideaffix { + display: none; + } + .mobile-hide { + display: none; + } + .breadcrumb { + white-space: inherit; + } + + /* workaround for #hashtag url is no longer needed*/ + h1:before, + h2:before, + h3:before, + h4:before { + content: ''; + display: none; + } +} + +/* For toc iframe */ +@media (max-width: 260px) { + .toc .level2 > li { + display: block; + } + + .toc .level2 > li:after { + display: none; + } +} + +/* For code snippet line highlight */ +pre > code .line-highlight { + background-color: #ffffcc; +} + +/* Alerts */ +.alert h5 { + text-transform: uppercase; + font-weight: bold; + margin-top: 0; +} + +.alert h5:before { + position:relative; + top:1px; + display:inline-block; + font-family:'Glyphicons Halflings'; + line-height:1; + -webkit-font-smoothing:antialiased; + -moz-osx-font-smoothing:grayscale; + margin-right: 5px; + font-weight: normal; +} + +.alert-info h5:before { + content:"\e086" +} + +.alert-warning h5:before { + content:"\e127" +} + +.alert-danger h5:before { + content:"\e107" +} + +/* For Embedded Video */ +div.embeddedvideo { + padding-top: 56.25%; + position: relative; + width: 100%; +} + +div.embeddedvideo iframe { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; +} + +/* For printer */ +@media print{ + .article.grid-right { + margin-top: 0px; + margin-left: 0px; + } + .sideaffix { + display: none; + } + .mobile-hide { + display: none; + } + .footer { + display: none; + } +} + +/* For tabbed content */ + +.tabGroup { + margin-top: 1rem; } + .tabGroup ul[role="tablist"] { + margin: 0; + padding: 0; + list-style: none; } + .tabGroup ul[role="tablist"] > li { + list-style: none; + display: inline-block; } + .tabGroup a[role="tab"] { + color: #6e6e6e; + box-sizing: border-box; + display: inline-block; + padding: 5px 7.5px; + text-decoration: none; + border-bottom: 2px solid #fff; } + .tabGroup a[role="tab"]:hover, .tabGroup a[role="tab"]:focus, .tabGroup a[role="tab"][aria-selected="true"] { + border-bottom: 2px solid #0050C5; } + .tabGroup a[role="tab"][aria-selected="true"] { + color: #222; } + .tabGroup a[role="tab"]:hover, .tabGroup a[role="tab"]:focus { + color: #0050C5; } + .tabGroup a[role="tab"]:focus { + outline: 1px solid #0050C5; + outline-offset: -1px; } + @media (min-width: 768px) { + .tabGroup a[role="tab"] { + padding: 5px 15px; } } + .tabGroup section[role="tabpanel"] { + border: 1px solid #e0e0e0; + padding: 15px; + margin: 0; + overflow: hidden; } + .tabGroup section[role="tabpanel"] > .codeHeader, + .tabGroup section[role="tabpanel"] > pre { + margin-left: -16px; + margin-right: -16px; } + .tabGroup section[role="tabpanel"] > :first-child { + margin-top: 0; } + .tabGroup section[role="tabpanel"] > pre:last-child { + display: block; + margin-bottom: -16px; } + +.mainContainer[dir='rtl'] main ul[role="tablist"] { + margin: 0; } diff --git a/docs/styles/docfx.js b/docs/styles/docfx.js new file mode 100644 index 00000000..384396b3 --- /dev/null +++ b/docs/styles/docfx.js @@ -0,0 +1,1175 @@ +// Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information. +$(function () { + var active = 'active'; + var expanded = 'in'; + var collapsed = 'collapsed'; + var filtered = 'filtered'; + var show = 'show'; + var hide = 'hide'; + var util = new utility(); + + workAroundFixedHeaderForAnchors(); + highlight(); + enableSearch(); + + renderTables(); + renderAlerts(); + renderLinks(); + renderNavbar(); + renderSidebar(); + renderAffix(); + renderFooter(); + renderLogo(); + + breakText(); + renderTabs(); + + window.refresh = function (article) { + // Update markup result + if (typeof article == 'undefined' || typeof article.content == 'undefined') + console.error("Null Argument"); + $("article.content").html(article.content); + + highlight(); + renderTables(); + renderAlerts(); + renderAffix(); + renderTabs(); + } + + // Add this event listener when needed + // window.addEventListener('content-update', contentUpdate); + + function breakText() { + $(".xref").addClass("text-break"); + var texts = $(".text-break"); + texts.each(function () { + $(this).breakWord(); + }); + } + + // Styling for tables in conceptual documents using Bootstrap. + // See http://getbootstrap.com/css/#tables + function renderTables() { + $('table').addClass('table table-bordered table-striped table-condensed').wrap('
'); + } + + // Styling for alerts. + function renderAlerts() { + $('.NOTE, .TIP').addClass('alert alert-info'); + $('.WARNING').addClass('alert alert-warning'); + $('.IMPORTANT, .CAUTION').addClass('alert alert-danger'); + } + + // Enable anchors for headings. + (function () { + anchors.options = { + placement: 'left', + visible: 'touch' + }; + anchors.add('article h2:not(.no-anchor), article h3:not(.no-anchor), article h4:not(.no-anchor)'); + })(); + + // Open links to different host in a new window. + function renderLinks() { + if ($("meta[property='docfx:newtab']").attr("content") === "true") { + $(document.links).filter(function () { + return this.hostname !== window.location.hostname; + }).attr('target', '_blank'); + } + } + + // Enable highlight.js + function highlight() { + $('pre code').each(function (i, block) { + hljs.highlightBlock(block); + }); + $('pre code[highlight-lines]').each(function (i, block) { + if (block.innerHTML === "") return; + var lines = block.innerHTML.split('\n'); + + queryString = block.getAttribute('highlight-lines'); + if (!queryString) return; + + var ranges = queryString.split(','); + for (var j = 0, range; range = ranges[j++];) { + var found = range.match(/^(\d+)\-(\d+)?$/); + if (found) { + // consider region as `{startlinenumber}-{endlinenumber}`, in which {endlinenumber} is optional + var start = +found[1]; + var end = +found[2]; + if (isNaN(end) || end > lines.length) { + end = lines.length; + } + } else { + // consider region as a sigine line number + if (isNaN(range)) continue; + var start = +range; + var end = start; + } + if (start <= 0 || end <= 0 || start > end || start > lines.length) { + // skip current region if invalid + continue; + } + lines[start - 1] = '' + lines[start - 1]; + lines[end - 1] = lines[end - 1] + ''; + } + + block.innerHTML = lines.join('\n'); + }); + } + + // Support full-text-search + function enableSearch() { + var query; + var relHref = $("meta[property='docfx\\:rel']").attr("content"); + if (typeof relHref === 'undefined') { + return; + } + try { + var worker = new Worker(relHref + 'styles/search-worker.js'); + if (!worker && !window.worker) { + localSearch(); + } else { + webWorkerSearch(); + } + + renderSearchBox(); + highlightKeywords(); + addSearchEvent(); + } catch (e) { + console.error(e); + } + + //Adjust the position of search box in navbar + function renderSearchBox() { + autoCollapse(); + $(window).on('resize', autoCollapse); + $(document).on('click', '.navbar-collapse.in', function (e) { + if ($(e.target).is('a')) { + $(this).collapse('hide'); + } + }); + + function autoCollapse() { + var navbar = $('#autocollapse'); + if (navbar.height() === null) { + setTimeout(autoCollapse, 300); + } + navbar.removeClass(collapsed); + if (navbar.height() > 60) { + navbar.addClass(collapsed); + } + } + } + + // Search factory + function localSearch() { + console.log("using local search"); + var lunrIndex = lunr(function () { + this.ref('href'); + this.field('title', { boost: 50 }); + this.field('keywords', { boost: 20 }); + }); + lunr.tokenizer.seperator = /[\s\-\.]+/; + var searchData = {}; + var searchDataRequest = new XMLHttpRequest(); + + var indexPath = relHref + "index.json"; + if (indexPath) { + searchDataRequest.open('GET', indexPath); + searchDataRequest.onload = function () { + if (this.status != 200) { + return; + } + searchData = JSON.parse(this.responseText); + for (var prop in searchData) { + if (searchData.hasOwnProperty(prop)) { + lunrIndex.add(searchData[prop]); + } + } + } + searchDataRequest.send(); + } + + $("body").bind("queryReady", function () { + var hits = lunrIndex.search(query); + var results = []; + hits.forEach(function (hit) { + var item = searchData[hit.ref]; + results.push({ 'href': item.href, 'title': item.title, 'keywords': item.keywords }); + }); + handleSearchResults(results); + }); + } + + function webWorkerSearch() { + console.log("using Web Worker"); + var indexReady = $.Deferred(); + + worker.onmessage = function (oEvent) { + switch (oEvent.data.e) { + case 'index-ready': + indexReady.resolve(); + break; + case 'query-ready': + var hits = oEvent.data.d; + handleSearchResults(hits); + break; + } + } + + indexReady.promise().done(function () { + $("body").bind("queryReady", function () { + worker.postMessage({ q: query }); + }); + if (query && (query.length >= 3)) { + worker.postMessage({ q: query }); + } + }); + } + + // Highlight the searching keywords + function highlightKeywords() { + var q = url('?q'); + if (q !== null) { + var keywords = q.split("%20"); + keywords.forEach(function (keyword) { + if (keyword !== "") { + $('.data-searchable *').mark(keyword); + $('article *').mark(keyword); + } + }); + } + } + + function addSearchEvent() { + $('body').bind("searchEvent", function () { + $('#search-query').keypress(function (e) { + return e.which !== 13; + }); + + $('#search-query').keyup(function () { + query = $(this).val(); + if (query.length < 3) { + flipContents("show"); + } else { + flipContents("hide"); + $("body").trigger("queryReady"); + $('#search-results>.search-list').text('Search Results for "' + query + '"'); + } + }).off("keydown"); + }); + } + + function flipContents(action) { + if (action === "show") { + $('.hide-when-search').show(); + $('#search-results').hide(); + } else { + $('.hide-when-search').hide(); + $('#search-results').show(); + } + } + + function relativeUrlToAbsoluteUrl(currentUrl, relativeUrl) { + var currentItems = currentUrl.split(/\/+/); + var relativeItems = relativeUrl.split(/\/+/); + var depth = currentItems.length - 1; + var items = []; + for (var i = 0; i < relativeItems.length; i++) { + if (relativeItems[i] === '..') { + depth--; + } else if (relativeItems[i] !== '.') { + items.push(relativeItems[i]); + } + } + return currentItems.slice(0, depth).concat(items).join('/'); + } + + function extractContentBrief(content) { + var briefOffset = 512; + var words = query.split(/\s+/g); + var queryIndex = content.indexOf(words[0]); + var briefContent; + if (queryIndex > briefOffset) { + return "..." + content.slice(queryIndex - briefOffset, queryIndex + briefOffset) + "..."; + } else if (queryIndex <= briefOffset) { + return content.slice(0, queryIndex + briefOffset) + "..."; + } + } + + function handleSearchResults(hits) { + var numPerPage = 10; + $('#pagination').empty(); + $('#pagination').removeData("twbs-pagination"); + if (hits.length === 0) { + $('#search-results>.sr-items').html('

No results found

'); + } else { + $('#pagination').twbsPagination({ + totalPages: Math.ceil(hits.length / numPerPage), + visiblePages: 5, + onPageClick: function (event, page) { + var start = (page - 1) * numPerPage; + var curHits = hits.slice(start, start + numPerPage); + $('#search-results>.sr-items').empty().append( + curHits.map(function (hit) { + var currentUrl = window.location.href; + var itemRawHref = relativeUrlToAbsoluteUrl(currentUrl, relHref + hit.href); + var itemHref = relHref + hit.href + "?q=" + query; + var itemTitle = hit.title; + var itemBrief = extractContentBrief(hit.keywords); + + var itemNode = $('
').attr('class', 'sr-item'); + var itemTitleNode = $('
').attr('class', 'item-title').append($('').attr('href', itemHref).attr("target", "_blank").text(itemTitle)); + var itemHrefNode = $('
').attr('class', 'item-href').text(itemRawHref); + var itemBriefNode = $('
').attr('class', 'item-brief').text(itemBrief); + itemNode.append(itemTitleNode).append(itemHrefNode).append(itemBriefNode); + return itemNode; + }) + ); + query.split(/\s+/).forEach(function (word) { + if (word !== '') { + $('#search-results>.sr-items *').mark(word); + } + }); + } + }); + } + } + }; + + // Update href in navbar + function renderNavbar() { + var navbar = $('#navbar ul')[0]; + if (typeof (navbar) === 'undefined') { + loadNavbar(); + } else { + $('#navbar ul a.active').parents('li').addClass(active); + renderBreadcrumb(); + showSearch(); + } + + function showSearch() { + if ($('#search-results').length !== 0) { + $('#search').show(); + $('body').trigger("searchEvent"); + } + } + + function loadNavbar() { + var navbarPath = $("meta[property='docfx\\:navrel']").attr("content"); + if (!navbarPath) { + return; + } + navbarPath = navbarPath.replace(/\\/g, '/'); + var tocPath = $("meta[property='docfx\\:tocrel']").attr("content") || ''; + if (tocPath) tocPath = tocPath.replace(/\\/g, '/'); + $.get(navbarPath, function (data) { + $(data).find("#toc>ul").appendTo("#navbar"); + showSearch(); + var index = navbarPath.lastIndexOf('/'); + var navrel = ''; + if (index > -1) { + navrel = navbarPath.substr(0, index + 1); + } + $('#navbar>ul').addClass('navbar-nav'); + var currentAbsPath = util.getAbsolutePath(window.location.pathname); + // set active item + $('#navbar').find('a[href]').each(function (i, e) { + var href = $(e).attr("href"); + if (util.isRelativePath(href)) { + href = navrel + href; + $(e).attr("href", href); + + var isActive = false; + var originalHref = e.name; + if (originalHref) { + originalHref = navrel + originalHref; + if (util.getDirectory(util.getAbsolutePath(originalHref)) === util.getDirectory(util.getAbsolutePath(tocPath))) { + isActive = true; + } + } else { + if (util.getAbsolutePath(href) === currentAbsPath) { + var dropdown = $(e).attr('data-toggle') == "dropdown" + if (!dropdown) { + isActive = true; + } + } + } + if (isActive) { + $(e).addClass(active); + } + } + }); + renderNavbar(); + }); + } + } + + function renderSidebar() { + var sidetoc = $('#sidetoggle .sidetoc')[0]; + if (typeof (sidetoc) === 'undefined') { + loadToc(); + } else { + registerTocEvents(); + if ($('footer').is(':visible')) { + $('.sidetoc').addClass('shiftup'); + } + + // Scroll to active item + var top = 0; + $('#toc a.active').parents('li').each(function (i, e) { + $(e).addClass(active).addClass(expanded); + $(e).children('a').addClass(active); + top += $(e).position().top; + }) + $('.sidetoc').scrollTop(top - 50); + + if ($('footer').is(':visible')) { + $('.sidetoc').addClass('shiftup'); + } + + renderBreadcrumb(); + } + + function registerTocEvents() { + var tocFilterInput = $('#toc_filter_input'); + var tocFilterClearButton = $('#toc_filter_clear'); + + $('.toc .nav > li > .expand-stub').click(function (e) { + $(e.target).parent().toggleClass(expanded); + }); + $('.toc .nav > li > .expand-stub + a:not([href])').click(function (e) { + $(e.target).parent().toggleClass(expanded); + }); + tocFilterInput.on('input', function (e) { + var val = this.value; + //Save filter string to local session storage + if (typeof(Storage) !== "undefined") { + sessionStorage.filterString = val; + } + if (val === '') { + // Clear 'filtered' class + $('#toc li').removeClass(filtered).removeClass(hide); + tocFilterClearButton.fadeOut(); + return; + } + tocFilterClearButton.fadeIn(); + + // Get leaf nodes + $('#toc li>a').filter(function (i, e) { + return $(e).siblings().length === 0 + }).each(function (i, anchor) { + var text = $(anchor).attr('title'); + var parent = $(anchor).parent(); + var parentNodes = parent.parents('ul>li'); + for (var i = 0; i < parentNodes.length; i++) { + var parentText = $(parentNodes[i]).children('a').attr('title'); + if (parentText) text = parentText + '.' + text; + }; + if (filterNavItem(text, val)) { + parent.addClass(show); + parent.removeClass(hide); + } else { + parent.addClass(hide); + parent.removeClass(show); + } + }); + $('#toc li>a').filter(function (i, e) { + return $(e).siblings().length > 0 + }).each(function (i, anchor) { + var parent = $(anchor).parent(); + if (parent.find('li.show').length > 0) { + parent.addClass(show); + parent.addClass(filtered); + parent.removeClass(hide); + } else { + parent.addClass(hide); + parent.removeClass(show); + parent.removeClass(filtered); + } + }) + + function filterNavItem(name, text) { + if (!text) return true; + if (name && name.toLowerCase().indexOf(text.toLowerCase()) > -1) return true; + return false; + } + }); + + // toc filter clear button + tocFilterClearButton.hide(); + tocFilterClearButton.on("click", function(e){ + tocFilterInput.val(""); + tocFilterInput.trigger('input'); + if (typeof(Storage) !== "undefined") { + sessionStorage.filterString = ""; + } + }); + + //Set toc filter from local session storage on page load + if (typeof(Storage) !== "undefined") { + tocFilterInput.val(sessionStorage.filterString); + tocFilterInput.trigger('input'); + } + } + + function loadToc() { + var tocPath = $("meta[property='docfx\\:tocrel']").attr("content"); + if (!tocPath) { + return; + } + tocPath = tocPath.replace(/\\/g, '/'); + $('#sidetoc').load(tocPath + " #sidetoggle > div", function () { + var index = tocPath.lastIndexOf('/'); + var tocrel = ''; + if (index > -1) { + tocrel = tocPath.substr(0, index + 1); + } + var currentHref = util.getAbsolutePath(window.location.pathname); + $('#sidetoc').find('a[href]').each(function (i, e) { + var href = $(e).attr("href"); + if (util.isRelativePath(href)) { + href = tocrel + href; + $(e).attr("href", href); + } + + if (util.getAbsolutePath(e.href) === currentHref) { + $(e).addClass(active); + } + + $(e).breakWord(); + }); + + renderSidebar(); + }); + } + } + + function renderBreadcrumb() { + var breadcrumb = []; + $('#navbar a.active').each(function (i, e) { + breadcrumb.push({ + href: e.href, + name: e.innerHTML + }); + }) + $('#toc a.active').each(function (i, e) { + breadcrumb.push({ + href: e.href, + name: e.innerHTML + }); + }) + + var html = util.formList(breadcrumb, 'breadcrumb'); + $('#breadcrumb').html(html); + } + + //Setup Affix + function renderAffix() { + var hierarchy = getHierarchy(); + if (hierarchy && hierarchy.length > 0) { + var html = '
In This Article
' + html += util.formList(hierarchy, ['nav', 'bs-docs-sidenav']); + $("#affix").empty().append(html); + if ($('footer').is(':visible')) { + $(".sideaffix").css("bottom", "70px"); + } + $('#affix a').click(function(e) { + var scrollspy = $('[data-spy="scroll"]').data()['bs.scrollspy']; + var target = e.target.hash; + if (scrollspy && target) { + scrollspy.activate(target); + } + }); + } + + function getHierarchy() { + // supported headers are h1, h2, h3, and h4 + var $headers = $($.map(['h1', 'h2', 'h3', 'h4'], function (h) { return ".article article " + h; }).join(", ")); + + // a stack of hierarchy items that are currently being built + var stack = []; + $headers.each(function (i, e) { + if (!e.id) { + return; + } + + var item = { + name: htmlEncode($(e).text()), + href: "#" + e.id, + items: [] + }; + + if (!stack.length) { + stack.push({ type: e.tagName, siblings: [item] }); + return; + } + + var frame = stack[stack.length - 1]; + if (e.tagName === frame.type) { + frame.siblings.push(item); + } else if (e.tagName[1] > frame.type[1]) { + // we are looking at a child of the last element of frame.siblings. + // push a frame onto the stack. After we've finished building this item's children, + // we'll attach it as a child of the last element + stack.push({ type: e.tagName, siblings: [item] }); + } else { // e.tagName[1] < frame.type[1] + // we are looking at a sibling of an ancestor of the current item. + // pop frames from the stack, building items as we go, until we reach the correct level at which to attach this item. + while (e.tagName[1] < stack[stack.length - 1].type[1]) { + buildParent(); + } + if (e.tagName === stack[stack.length - 1].type) { + stack[stack.length - 1].siblings.push(item); + } else { + stack.push({ type: e.tagName, siblings: [item] }); + } + } + }); + while (stack.length > 1) { + buildParent(); + } + + function buildParent() { + var childrenToAttach = stack.pop(); + var parentFrame = stack[stack.length - 1]; + var parent = parentFrame.siblings[parentFrame.siblings.length - 1]; + $.each(childrenToAttach.siblings, function (i, child) { + parent.items.push(child); + }); + } + if (stack.length > 0) { + + var topLevel = stack.pop().siblings; + if (topLevel.length === 1) { // if there's only one topmost header, dump it + return topLevel[0].items; + } + return topLevel; + } + return undefined; + } + + function htmlEncode(str) { + if (!str) return str; + return str + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(//g, '>'); + } + + function htmlDecode(value) { + if (!str) return str; + return value + .replace(/"/g, '"') + .replace(/'/g, "'") + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/&/g, '&'); + } + + function cssEscape(str) { + // see: http://stackoverflow.com/questions/2786538/need-to-escape-a-special-character-in-a-jquery-selector-string#answer-2837646 + if (!str) return str; + return str + .replace(/[!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, "\\$&"); + } + } + + // Show footer + function renderFooter() { + initFooter(); + $(window).on("scroll", showFooterCore); + + function initFooter() { + if (needFooter()) { + shiftUpBottomCss(); + $("footer").show(); + } else { + resetBottomCss(); + $("footer").hide(); + } + } + + function showFooterCore() { + if (needFooter()) { + shiftUpBottomCss(); + $("footer").fadeIn(); + } else { + resetBottomCss(); + $("footer").fadeOut(); + } + } + + function needFooter() { + var scrollHeight = $(document).height(); + var scrollPosition = $(window).height() + $(window).scrollTop(); + return (scrollHeight - scrollPosition) < 1; + } + + function resetBottomCss() { + $(".sidetoc").removeClass("shiftup"); + $(".sideaffix").removeClass("shiftup"); + } + + function shiftUpBottomCss() { + $(".sidetoc").addClass("shiftup"); + $(".sideaffix").addClass("shiftup"); + } + } + + function renderLogo() { + // For LOGO SVG + // Replace SVG with inline SVG + // http://stackoverflow.com/questions/11978995/how-to-change-color-of-svg-image-using-css-jquery-svg-image-replacement + jQuery('img.svg').each(function () { + var $img = jQuery(this); + var imgID = $img.attr('id'); + var imgClass = $img.attr('class'); + var imgURL = $img.attr('src'); + + jQuery.get(imgURL, function (data) { + // Get the SVG tag, ignore the rest + var $svg = jQuery(data).find('svg'); + + // Add replaced image's ID to the new SVG + if (typeof imgID !== 'undefined') { + $svg = $svg.attr('id', imgID); + } + // Add replaced image's classes to the new SVG + if (typeof imgClass !== 'undefined') { + $svg = $svg.attr('class', imgClass + ' replaced-svg'); + } + + // Remove any invalid XML tags as per http://validator.w3.org + $svg = $svg.removeAttr('xmlns:a'); + + // Replace image with new SVG + $img.replaceWith($svg); + + }, 'xml'); + }); + } + + function renderTabs() { + var contentAttrs = { + id: 'data-bi-id', + name: 'data-bi-name', + type: 'data-bi-type' + }; + + var Tab = (function () { + function Tab(li, a, section) { + this.li = li; + this.a = a; + this.section = section; + } + Object.defineProperty(Tab.prototype, "tabIds", { + get: function () { return this.a.getAttribute('data-tab').split(' '); }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Tab.prototype, "condition", { + get: function () { return this.a.getAttribute('data-condition'); }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Tab.prototype, "visible", { + get: function () { return !this.li.hasAttribute('hidden'); }, + set: function (value) { + if (value) { + this.li.removeAttribute('hidden'); + this.li.removeAttribute('aria-hidden'); + } + else { + this.li.setAttribute('hidden', 'hidden'); + this.li.setAttribute('aria-hidden', 'true'); + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Tab.prototype, "selected", { + get: function () { return !this.section.hasAttribute('hidden'); }, + set: function (value) { + if (value) { + this.a.setAttribute('aria-selected', 'true'); + this.a.tabIndex = 0; + this.section.removeAttribute('hidden'); + this.section.removeAttribute('aria-hidden'); + } + else { + this.a.setAttribute('aria-selected', 'false'); + this.a.tabIndex = -1; + this.section.setAttribute('hidden', 'hidden'); + this.section.setAttribute('aria-hidden', 'true'); + } + }, + enumerable: true, + configurable: true + }); + Tab.prototype.focus = function () { + this.a.focus(); + }; + return Tab; + }()); + + initTabs(document.body); + + function initTabs(container) { + var queryStringTabs = readTabsQueryStringParam(); + var elements = container.querySelectorAll('.tabGroup'); + var state = { groups: [], selectedTabs: [] }; + for (var i = 0; i < elements.length; i++) { + var group = initTabGroup(elements.item(i)); + if (!group.independent) { + updateVisibilityAndSelection(group, state); + state.groups.push(group); + } + } + container.addEventListener('click', function (event) { return handleClick(event, state); }); + if (state.groups.length === 0) { + return state; + } + selectTabs(queryStringTabs, container); + updateTabsQueryStringParam(state); + notifyContentUpdated(); + return state; + } + + function initTabGroup(element) { + var group = { + independent: element.hasAttribute('data-tab-group-independent'), + tabs: [] + }; + var li = element.firstElementChild.firstElementChild; + while (li) { + var a = li.firstElementChild; + a.setAttribute(contentAttrs.name, 'tab'); + var dataTab = a.getAttribute('data-tab').replace(/\+/g, ' '); + a.setAttribute('data-tab', dataTab); + var section = element.querySelector("[id=\"" + a.getAttribute('aria-controls') + "\"]"); + var tab = new Tab(li, a, section); + group.tabs.push(tab); + li = li.nextElementSibling; + } + element.setAttribute(contentAttrs.name, 'tab-group'); + element.tabGroup = group; + return group; + } + + function updateVisibilityAndSelection(group, state) { + var anySelected = false; + var firstVisibleTab; + for (var _i = 0, _a = group.tabs; _i < _a.length; _i++) { + var tab = _a[_i]; + tab.visible = tab.condition === null || state.selectedTabs.indexOf(tab.condition) !== -1; + if (tab.visible) { + if (!firstVisibleTab) { + firstVisibleTab = tab; + } + } + tab.selected = tab.visible && arraysIntersect(state.selectedTabs, tab.tabIds); + anySelected = anySelected || tab.selected; + } + if (!anySelected) { + for (var _b = 0, _c = group.tabs; _b < _c.length; _b++) { + var tabIds = _c[_b].tabIds; + for (var _d = 0, tabIds_1 = tabIds; _d < tabIds_1.length; _d++) { + var tabId = tabIds_1[_d]; + var index = state.selectedTabs.indexOf(tabId); + if (index === -1) { + continue; + } + state.selectedTabs.splice(index, 1); + } + } + var tab = firstVisibleTab; + tab.selected = true; + state.selectedTabs.push(tab.tabIds[0]); + } + } + + function getTabInfoFromEvent(event) { + if (!(event.target instanceof HTMLElement)) { + return null; + } + var anchor = event.target.closest('a[data-tab]'); + if (anchor === null) { + return null; + } + var tabIds = anchor.getAttribute('data-tab').split(' '); + var group = anchor.parentElement.parentElement.parentElement.tabGroup; + if (group === undefined) { + return null; + } + return { tabIds: tabIds, group: group, anchor: anchor }; + } + + function handleClick(event, state) { + var info = getTabInfoFromEvent(event); + if (info === null) { + return; + } + event.preventDefault(); + info.anchor.href = 'javascript:'; + setTimeout(function () { return info.anchor.href = '#' + info.anchor.getAttribute('aria-controls'); }); + var tabIds = info.tabIds, group = info.group; + var originalTop = info.anchor.getBoundingClientRect().top; + if (group.independent) { + for (var _i = 0, _a = group.tabs; _i < _a.length; _i++) { + var tab = _a[_i]; + tab.selected = arraysIntersect(tab.tabIds, tabIds); + } + } + else { + if (arraysIntersect(state.selectedTabs, tabIds)) { + return; + } + var previousTabId = group.tabs.filter(function (t) { return t.selected; })[0].tabIds[0]; + state.selectedTabs.splice(state.selectedTabs.indexOf(previousTabId), 1, tabIds[0]); + for (var _b = 0, _c = state.groups; _b < _c.length; _b++) { + var group_1 = _c[_b]; + updateVisibilityAndSelection(group_1, state); + } + updateTabsQueryStringParam(state); + } + notifyContentUpdated(); + var top = info.anchor.getBoundingClientRect().top; + if (top !== originalTop && event instanceof MouseEvent) { + window.scrollTo(0, window.pageYOffset + top - originalTop); + } + } + + function selectTabs(tabIds) { + for (var _i = 0, tabIds_1 = tabIds; _i < tabIds_1.length; _i++) { + var tabId = tabIds_1[_i]; + var a = document.querySelector(".tabGroup > ul > li > a[data-tab=\"" + tabId + "\"]:not([hidden])"); + if (a === null) { + return; + } + a.dispatchEvent(new CustomEvent('click', { bubbles: true })); + } + } + + function readTabsQueryStringParam() { + var qs = parseQueryString(); + var t = qs.tabs; + if (t === undefined || t === '') { + return []; + } + return t.split(','); + } + + function updateTabsQueryStringParam(state) { + var qs = parseQueryString(); + qs.tabs = state.selectedTabs.join(); + var url = location.protocol + "//" + location.host + location.pathname + "?" + toQueryString(qs) + location.hash; + if (location.href === url) { + return; + } + history.replaceState({}, document.title, url); + } + + function toQueryString(args) { + var parts = []; + for (var name_1 in args) { + if (args.hasOwnProperty(name_1) && args[name_1] !== '' && args[name_1] !== null && args[name_1] !== undefined) { + parts.push(encodeURIComponent(name_1) + '=' + encodeURIComponent(args[name_1])); + } + } + return parts.join('&'); + } + + function parseQueryString(queryString) { + var match; + var pl = /\+/g; + var search = /([^&=]+)=?([^&]*)/g; + var decode = function (s) { return decodeURIComponent(s.replace(pl, ' ')); }; + if (queryString === undefined) { + queryString = ''; + } + queryString = queryString.substring(1); + var urlParams = {}; + while (match = search.exec(queryString)) { + urlParams[decode(match[1])] = decode(match[2]); + } + return urlParams; + } + + function arraysIntersect(a, b) { + for (var _i = 0, a_1 = a; _i < a_1.length; _i++) { + var itemA = a_1[_i]; + for (var _a = 0, b_1 = b; _a < b_1.length; _a++) { + var itemB = b_1[_a]; + if (itemA === itemB) { + return true; + } + } + } + return false; + } + + function notifyContentUpdated() { + // Dispatch this event when needed + // window.dispatchEvent(new CustomEvent('content-update')); + } + } + + function utility() { + this.getAbsolutePath = getAbsolutePath; + this.isRelativePath = isRelativePath; + this.isAbsolutePath = isAbsolutePath; + this.getDirectory = getDirectory; + this.formList = formList; + + function getAbsolutePath(href) { + // Use anchor to normalize href + var anchor = $('
')[0]; + // Ignore protocal, remove search and query + return anchor.host + anchor.pathname; + } + + function isRelativePath(href) { + if (href === undefined || href === '' || href[0] === '/') { + return false; + } + return !isAbsolutePath(href); + } + + function isAbsolutePath(href) { + return (/^(?:[a-z]+:)?\/\//i).test(href); + } + + function getDirectory(href) { + if (!href) return ''; + var index = href.lastIndexOf('/'); + if (index == -1) return ''; + if (index > -1) { + return href.substr(0, index); + } + } + + function formList(item, classes) { + var level = 1; + var model = { + items: item + }; + var cls = [].concat(classes).join(" "); + return getList(model, cls); + + function getList(model, cls) { + if (!model || !model.items) return null; + var l = model.items.length; + if (l === 0) return null; + var html = '
    '; + level++; + for (var i = 0; i < l; i++) { + var item = model.items[i]; + var href = item.href; + var name = item.name; + if (!name) continue; + html += href ? '
  • ' + name + '' : '
  • ' + name; + html += getList(item, cls) || ''; + html += '
  • '; + } + html += '
'; + return html; + } + } + + /** + * Add into long word. + * @param {String} text - The word to break. It should be in plain text without HTML tags. + */ + function breakPlainText(text) { + if (!text) return text; + return text.replace(/([a-z])([A-Z])|(\.)(\w)/g, '$1$3$2$4') + } + + /** + * Add into long word. The jQuery element should contain no html tags. + * If the jQuery element contains tags, this function will not change the element. + */ + $.fn.breakWord = function () { + if (this.html() == this.text()) { + this.html(function (index, text) { + return breakPlainText(text); + }) + } + return this; + } + } + + // adjusted from https://stackoverflow.com/a/13067009/1523776 + function workAroundFixedHeaderForAnchors() { + var HISTORY_SUPPORT = !!(history && history.pushState); + var ANCHOR_REGEX = /^#[^ ]+$/; + + function getFixedOffset() { + return $('header').first().height(); + } + + /** + * If the provided href is an anchor which resolves to an element on the + * page, scroll to it. + * @param {String} href + * @return {Boolean} - Was the href an anchor. + */ + function scrollIfAnchor(href, pushToHistory) { + var match, rect, anchorOffset; + + if (!ANCHOR_REGEX.test(href)) { + return false; + } + + match = document.getElementById(href.slice(1)); + + if (match) { + rect = match.getBoundingClientRect(); + anchorOffset = window.pageYOffset + rect.top - getFixedOffset(); + window.scrollTo(window.pageXOffset, anchorOffset); + + // Add the state to history as-per normal anchor links + if (HISTORY_SUPPORT && pushToHistory) { + history.pushState({}, document.title, location.pathname + href); + } + } + + return !!match; + } + + /** + * Attempt to scroll to the current location's hash. + */ + function scrollToCurrent() { + scrollIfAnchor(window.location.hash); + } + + /** + * If the click event's target was an anchor, fix the scroll position. + */ + function delegateAnchors(e) { + var elem = e.target; + + if (scrollIfAnchor(elem.getAttribute('href'), true)) { + e.preventDefault(); + } + } + + $(window).on('hashchange', scrollToCurrent); + + $(window).load(function () { + // scroll to the anchor if present, offset by the header + scrollToCurrent(); + }); + + $(document).ready(function () { + // Exclude tabbed content case + $('a:not([data-tab])').click(function (e) { delegateAnchors(e); }); + }); + } +}); diff --git a/docs/styles/docfx.vendor.css b/docs/styles/docfx.vendor.css new file mode 100644 index 00000000..91bb610c --- /dev/null +++ b/docs/styles/docfx.vendor.css @@ -0,0 +1,1464 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ +.label,sub,sup{vertical-align:baseline} +hr,img{border:0} +body,figure{margin:0} +.btn-group>.btn-group,.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.dropdown-menu{float:left} +.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.pre-scrollable{max-height:340px} +html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%} +article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block} +audio,canvas,progress,video{display:inline-block;vertical-align:baseline} +audio:not([controls]){display:none;height:0} +[hidden],template{display:none} +a{background-color:transparent} +a:active,a:hover{outline:0} +b,optgroup,strong{font-weight:700} +dfn{font-style:italic} +h1{margin:.67em 0} +mark{color:#000;background:#ff0} +sub,sup{position:relative;font-size:75%;line-height:0} +sup{top:-.5em} +sub{bottom:-.25em} +img{vertical-align:middle} +svg:not(:root){overflow:hidden} +hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box} +pre,textarea{overflow:auto} +code,kbd,pre,samp{font-size:1em} +button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit} +.glyphicon,address{font-style:normal} +button{overflow:visible} +button,select{text-transform:none} +button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer} +button[disabled],html input[disabled]{cursor:default} +button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0} +input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0} +input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto} +input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none} +table{border-spacing:0;border-collapse:collapse} +td,th{padding:0} +/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ +@media print{blockquote,img,pre,tr{page-break-inside:avoid} +*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important} +a,a:visited{text-decoration:underline} +a[href]:after{content:" (" attr(href) ")"} +abbr[title]:after{content:" (" attr(title) ")"} +a[href^="javascript:"]:after,a[href^="#"]:after{content:""} +blockquote,pre{border:1px solid #999} +thead{display:table-header-group} +img{max-width:100%!important} +h2,h3,p{orphans:3;widows:3} +h2,h3{page-break-after:avoid} +.navbar{display:none} +.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important} +.label{border:1px solid #000} +.table{border-collapse:collapse!important} +.table td,.table th{background-color:#fff!important} +.table-bordered td,.table-bordered th{border:1px solid #ddd!important} +} +.dropdown-menu,.modal-content{-webkit-background-clip:padding-box} +.btn,.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-warning.active,.btn-warning:active,.btn.active,.btn:active,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover,.form-control,.navbar-toggle,.open>.dropdown-toggle.btn-danger,.open>.dropdown-toggle.btn-default,.open>.dropdown-toggle.btn-info,.open>.dropdown-toggle.btn-primary,.open>.dropdown-toggle.btn-warning{background-image:none} +.img-thumbnail,body{background-color:#fff} +@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')} +.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale} +.glyphicon-asterisk:before{content:"\002a"} +.glyphicon-plus:before{content:"\002b"} +.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"} +.glyphicon-minus:before{content:"\2212"} +.glyphicon-cloud:before{content:"\2601"} +.glyphicon-envelope:before{content:"\2709"} +.glyphicon-pencil:before{content:"\270f"} +.glyphicon-glass:before{content:"\e001"} +.glyphicon-music:before{content:"\e002"} +.glyphicon-search:before{content:"\e003"} +.glyphicon-heart:before{content:"\e005"} +.glyphicon-star:before{content:"\e006"} +.glyphicon-star-empty:before{content:"\e007"} +.glyphicon-user:before{content:"\e008"} +.glyphicon-film:before{content:"\e009"} +.glyphicon-th-large:before{content:"\e010"} +.glyphicon-th:before{content:"\e011"} +.glyphicon-th-list:before{content:"\e012"} +.glyphicon-ok:before{content:"\e013"} +.glyphicon-remove:before{content:"\e014"} +.glyphicon-zoom-in:before{content:"\e015"} +.glyphicon-zoom-out:before{content:"\e016"} +.glyphicon-off:before{content:"\e017"} +.glyphicon-signal:before{content:"\e018"} +.glyphicon-cog:before{content:"\e019"} +.glyphicon-trash:before{content:"\e020"} +.glyphicon-home:before{content:"\e021"} +.glyphicon-file:before{content:"\e022"} +.glyphicon-time:before{content:"\e023"} +.glyphicon-road:before{content:"\e024"} +.glyphicon-download-alt:before{content:"\e025"} +.glyphicon-download:before{content:"\e026"} +.glyphicon-upload:before{content:"\e027"} +.glyphicon-inbox:before{content:"\e028"} +.glyphicon-play-circle:before{content:"\e029"} +.glyphicon-repeat:before{content:"\e030"} +.glyphicon-refresh:before{content:"\e031"} +.glyphicon-list-alt:before{content:"\e032"} +.glyphicon-lock:before{content:"\e033"} +.glyphicon-flag:before{content:"\e034"} +.glyphicon-headphones:before{content:"\e035"} +.glyphicon-volume-off:before{content:"\e036"} +.glyphicon-volume-down:before{content:"\e037"} +.glyphicon-volume-up:before{content:"\e038"} +.glyphicon-qrcode:before{content:"\e039"} +.glyphicon-barcode:before{content:"\e040"} +.glyphicon-tag:before{content:"\e041"} +.glyphicon-tags:before{content:"\e042"} +.glyphicon-book:before{content:"\e043"} +.glyphicon-bookmark:before{content:"\e044"} +.glyphicon-print:before{content:"\e045"} +.glyphicon-camera:before{content:"\e046"} +.glyphicon-font:before{content:"\e047"} +.glyphicon-bold:before{content:"\e048"} +.glyphicon-italic:before{content:"\e049"} +.glyphicon-text-height:before{content:"\e050"} +.glyphicon-text-width:before{content:"\e051"} +.glyphicon-align-left:before{content:"\e052"} +.glyphicon-align-center:before{content:"\e053"} +.glyphicon-align-right:before{content:"\e054"} +.glyphicon-align-justify:before{content:"\e055"} +.glyphicon-list:before{content:"\e056"} +.glyphicon-indent-left:before{content:"\e057"} +.glyphicon-indent-right:before{content:"\e058"} +.glyphicon-facetime-video:before{content:"\e059"} +.glyphicon-picture:before{content:"\e060"} +.glyphicon-map-marker:before{content:"\e062"} +.glyphicon-adjust:before{content:"\e063"} +.glyphicon-tint:before{content:"\e064"} +.glyphicon-edit:before{content:"\e065"} +.glyphicon-share:before{content:"\e066"} +.glyphicon-check:before{content:"\e067"} +.glyphicon-move:before{content:"\e068"} +.glyphicon-step-backward:before{content:"\e069"} +.glyphicon-fast-backward:before{content:"\e070"} +.glyphicon-backward:before{content:"\e071"} +.glyphicon-play:before{content:"\e072"} +.glyphicon-pause:before{content:"\e073"} +.glyphicon-stop:before{content:"\e074"} +.glyphicon-forward:before{content:"\e075"} +.glyphicon-fast-forward:before{content:"\e076"} +.glyphicon-step-forward:before{content:"\e077"} +.glyphicon-eject:before{content:"\e078"} +.glyphicon-chevron-left:before{content:"\e079"} +.glyphicon-chevron-right:before{content:"\e080"} +.glyphicon-plus-sign:before{content:"\e081"} +.glyphicon-minus-sign:before{content:"\e082"} +.glyphicon-remove-sign:before{content:"\e083"} +.glyphicon-ok-sign:before{content:"\e084"} +.glyphicon-question-sign:before{content:"\e085"} +.glyphicon-info-sign:before{content:"\e086"} +.glyphicon-screenshot:before{content:"\e087"} +.glyphicon-remove-circle:before{content:"\e088"} +.glyphicon-ok-circle:before{content:"\e089"} +.glyphicon-ban-circle:before{content:"\e090"} +.glyphicon-arrow-left:before{content:"\e091"} +.glyphicon-arrow-right:before{content:"\e092"} +.glyphicon-arrow-up:before{content:"\e093"} +.glyphicon-arrow-down:before{content:"\e094"} +.glyphicon-share-alt:before{content:"\e095"} +.glyphicon-resize-full:before{content:"\e096"} +.glyphicon-resize-small:before{content:"\e097"} +.glyphicon-exclamation-sign:before{content:"\e101"} +.glyphicon-gift:before{content:"\e102"} +.glyphicon-leaf:before{content:"\e103"} +.glyphicon-fire:before{content:"\e104"} +.glyphicon-eye-open:before{content:"\e105"} +.glyphicon-eye-close:before{content:"\e106"} +.glyphicon-warning-sign:before{content:"\e107"} +.glyphicon-plane:before{content:"\e108"} +.glyphicon-calendar:before{content:"\e109"} +.glyphicon-random:before{content:"\e110"} +.glyphicon-comment:before{content:"\e111"} +.glyphicon-magnet:before{content:"\e112"} +.glyphicon-chevron-up:before{content:"\e113"} +.glyphicon-chevron-down:before{content:"\e114"} +.glyphicon-retweet:before{content:"\e115"} +.glyphicon-shopping-cart:before{content:"\e116"} +.glyphicon-folder-close:before{content:"\e117"} +.glyphicon-folder-open:before{content:"\e118"} +.glyphicon-resize-vertical:before{content:"\e119"} +.glyphicon-resize-horizontal:before{content:"\e120"} +.glyphicon-hdd:before{content:"\e121"} +.glyphicon-bullhorn:before{content:"\e122"} +.glyphicon-bell:before{content:"\e123"} +.glyphicon-certificate:before{content:"\e124"} +.glyphicon-thumbs-up:before{content:"\e125"} +.glyphicon-thumbs-down:before{content:"\e126"} +.glyphicon-hand-right:before{content:"\e127"} +.glyphicon-hand-left:before{content:"\e128"} +.glyphicon-hand-up:before{content:"\e129"} +.glyphicon-hand-down:before{content:"\e130"} +.glyphicon-circle-arrow-right:before{content:"\e131"} +.glyphicon-circle-arrow-left:before{content:"\e132"} +.glyphicon-circle-arrow-up:before{content:"\e133"} +.glyphicon-circle-arrow-down:before{content:"\e134"} +.glyphicon-globe:before{content:"\e135"} +.glyphicon-wrench:before{content:"\e136"} +.glyphicon-tasks:before{content:"\e137"} +.glyphicon-filter:before{content:"\e138"} +.glyphicon-briefcase:before{content:"\e139"} +.glyphicon-fullscreen:before{content:"\e140"} +.glyphicon-dashboard:before{content:"\e141"} +.glyphicon-paperclip:before{content:"\e142"} +.glyphicon-heart-empty:before{content:"\e143"} +.glyphicon-link:before{content:"\e144"} +.glyphicon-phone:before{content:"\e145"} +.glyphicon-pushpin:before{content:"\e146"} +.glyphicon-usd:before{content:"\e148"} +.glyphicon-gbp:before{content:"\e149"} +.glyphicon-sort:before{content:"\e150"} +.glyphicon-sort-by-alphabet:before{content:"\e151"} +.glyphicon-sort-by-alphabet-alt:before{content:"\e152"} +.glyphicon-sort-by-order:before{content:"\e153"} +.glyphicon-sort-by-order-alt:before{content:"\e154"} +.glyphicon-sort-by-attributes:before{content:"\e155"} +.glyphicon-sort-by-attributes-alt:before{content:"\e156"} +.glyphicon-unchecked:before{content:"\e157"} +.glyphicon-expand:before{content:"\e158"} +.glyphicon-collapse-down:before{content:"\e159"} +.glyphicon-collapse-up:before{content:"\e160"} +.glyphicon-log-in:before{content:"\e161"} +.glyphicon-flash:before{content:"\e162"} +.glyphicon-log-out:before{content:"\e163"} +.glyphicon-new-window:before{content:"\e164"} +.glyphicon-record:before{content:"\e165"} +.glyphicon-save:before{content:"\e166"} +.glyphicon-open:before{content:"\e167"} +.glyphicon-saved:before{content:"\e168"} +.glyphicon-import:before{content:"\e169"} +.glyphicon-export:before{content:"\e170"} +.glyphicon-send:before{content:"\e171"} +.glyphicon-floppy-disk:before{content:"\e172"} +.glyphicon-floppy-saved:before{content:"\e173"} +.glyphicon-floppy-remove:before{content:"\e174"} +.glyphicon-floppy-save:before{content:"\e175"} +.glyphicon-floppy-open:before{content:"\e176"} +.glyphicon-credit-card:before{content:"\e177"} +.glyphicon-transfer:before{content:"\e178"} +.glyphicon-cutlery:before{content:"\e179"} +.glyphicon-header:before{content:"\e180"} +.glyphicon-compressed:before{content:"\e181"} +.glyphicon-earphone:before{content:"\e182"} +.glyphicon-phone-alt:before{content:"\e183"} +.glyphicon-tower:before{content:"\e184"} +.glyphicon-stats:before{content:"\e185"} +.glyphicon-sd-video:before{content:"\e186"} +.glyphicon-hd-video:before{content:"\e187"} +.glyphicon-subtitles:before{content:"\e188"} +.glyphicon-sound-stereo:before{content:"\e189"} +.glyphicon-sound-dolby:before{content:"\e190"} +.glyphicon-sound-5-1:before{content:"\e191"} +.glyphicon-sound-6-1:before{content:"\e192"} +.glyphicon-sound-7-1:before{content:"\e193"} +.glyphicon-copyright-mark:before{content:"\e194"} +.glyphicon-registration-mark:before{content:"\e195"} +.glyphicon-cloud-download:before{content:"\e197"} +.glyphicon-cloud-upload:before{content:"\e198"} +.glyphicon-tree-conifer:before{content:"\e199"} +.glyphicon-tree-deciduous:before{content:"\e200"} +.glyphicon-cd:before{content:"\e201"} +.glyphicon-save-file:before{content:"\e202"} +.glyphicon-open-file:before{content:"\e203"} +.glyphicon-level-up:before{content:"\e204"} +.glyphicon-copy:before{content:"\e205"} +.glyphicon-paste:before{content:"\e206"} +.glyphicon-alert:before{content:"\e209"} +.glyphicon-equalizer:before{content:"\e210"} +.glyphicon-king:before{content:"\e211"} +.glyphicon-queen:before{content:"\e212"} +.glyphicon-pawn:before{content:"\e213"} +.glyphicon-bishop:before{content:"\e214"} +.glyphicon-knight:before{content:"\e215"} +.glyphicon-baby-formula:before{content:"\e216"} +.glyphicon-tent:before{content:"\26fa"} +.glyphicon-blackboard:before{content:"\e218"} +.glyphicon-bed:before{content:"\e219"} +.glyphicon-apple:before{content:"\f8ff"} +.glyphicon-erase:before{content:"\e221"} +.glyphicon-hourglass:before{content:"\231b"} +.glyphicon-lamp:before{content:"\e223"} +.glyphicon-duplicate:before{content:"\e224"} +.glyphicon-piggy-bank:before{content:"\e225"} +.glyphicon-scissors:before{content:"\e226"} +.glyphicon-bitcoin:before,.glyphicon-btc:before,.glyphicon-xbt:before{content:"\e227"} +.glyphicon-jpy:before,.glyphicon-yen:before{content:"\00a5"} +.glyphicon-rub:before,.glyphicon-ruble:before{content:"\20bd"} +.glyphicon-scale:before{content:"\e230"} +.glyphicon-ice-lolly:before{content:"\e231"} +.glyphicon-ice-lolly-tasted:before{content:"\e232"} +.glyphicon-education:before{content:"\e233"} +.glyphicon-option-horizontal:before{content:"\e234"} +.glyphicon-option-vertical:before{content:"\e235"} +.glyphicon-menu-hamburger:before{content:"\e236"} +.glyphicon-modal-window:before{content:"\e237"} +.glyphicon-oil:before{content:"\e238"} +.glyphicon-grain:before{content:"\e239"} +.glyphicon-sunglasses:before{content:"\e240"} +.glyphicon-text-size:before{content:"\e241"} +.glyphicon-text-color:before{content:"\e242"} +.glyphicon-text-background:before{content:"\e243"} +.glyphicon-object-align-top:before{content:"\e244"} +.glyphicon-object-align-bottom:before{content:"\e245"} +.glyphicon-object-align-horizontal:before{content:"\e246"} +.glyphicon-object-align-left:before{content:"\e247"} +.glyphicon-object-align-vertical:before{content:"\e248"} +.glyphicon-object-align-right:before{content:"\e249"} +.glyphicon-triangle-right:before{content:"\e250"} +.glyphicon-triangle-left:before{content:"\e251"} +.glyphicon-triangle-bottom:before{content:"\e252"} +.glyphicon-triangle-top:before{content:"\e253"} +.glyphicon-console:before{content:"\e254"} +.glyphicon-superscript:before{content:"\e255"} +.glyphicon-subscript:before{content:"\e256"} +.glyphicon-menu-left:before{content:"\e257"} +.glyphicon-menu-right:before{content:"\e258"} +.glyphicon-menu-down:before{content:"\e259"} +.glyphicon-menu-up:before{content:"\e260"} +*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +html{font-size:10px;-webkit-tap-highlight-color:transparent} +body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333} +button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit} +a{color:#337ab7;text-decoration:none} +a:focus,a:hover{color:#23527c;text-decoration:underline} +a:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} +.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto} +.img-rounded{border-radius:6px} +.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out} +.img-circle{border-radius:50%} +hr{margin-top:20px;margin-bottom:20px;border-top:1px solid #eee} +.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0} +.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} +[role=button]{cursor:pointer} +.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit} +.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777} +.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px} +.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%} +.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px} +.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%} +.h1,h1{font-size:36px} +.h2,h2{font-size:30px} +.h3,h3{font-size:24px} +.h4,h4{font-size:18px} +.h5,h5{font-size:14px} +.h6,h6{font-size:12px} +p{margin:0 0 10px} +.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4} +dt,kbd kbd,label{font-weight:700} +address,blockquote .small,blockquote footer,blockquote small,dd,dt,pre{line-height:1.42857143} +@media (min-width:768px){.lead{font-size:21px} +} +.small,small{font-size:85%} +.mark,mark{padding:.2em;background-color:#fcf8e3} +.list-inline,.list-unstyled{padding-left:0;list-style:none} +.text-left{text-align:left} +.text-right{text-align:right} +.text-center{text-align:center} +.text-justify{text-align:justify} +.text-nowrap{white-space:nowrap} +.text-lowercase{text-transform:lowercase} +.text-uppercase{text-transform:uppercase} +.text-capitalize{text-transform:capitalize} +.text-muted{color:#777} +.text-primary{color:#337ab7} +a.text-primary:focus,a.text-primary:hover{color:#286090} +.text-success{color:#3c763d} +a.text-success:focus,a.text-success:hover{color:#2b542c} +.text-info{color:#31708f} +a.text-info:focus,a.text-info:hover{color:#245269} +.text-warning{color:#8a6d3b} +a.text-warning:focus,a.text-warning:hover{color:#66512c} +.text-danger{color:#a94442} +a.text-danger:focus,a.text-danger:hover{color:#843534} +.bg-primary{color:#fff;background-color:#337ab7} +a.bg-primary:focus,a.bg-primary:hover{background-color:#286090} +.bg-success{background-color:#dff0d8} +a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3} +.bg-info{background-color:#d9edf7} +a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee} +.bg-warning{background-color:#fcf8e3} +a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5} +.bg-danger{background-color:#f2dede} +a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9} +pre code,table{background-color:transparent} +.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee} +dl,ol,ul{margin-top:0} +blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child,ol ol,ol ul,ul ol,ul ul{margin-bottom:0} +address,dl{margin-bottom:20px} +ol,ul{margin-bottom:10px} +.list-inline{margin-left:-5px} +.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px} +dd{margin-left:0} +@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap} +.dl-horizontal dd{margin-left:180px} +.container{width:750px} +} +abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777} +.initialism{font-size:90%;text-transform:uppercase} +blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee} +blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;color:#777} +legend,pre{display:block;color:#333} +blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'} +.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0} +code,kbd{padding:2px 4px;font-size:90%} +caption,th{text-align:left} +.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''} +.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'} +code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace} +code{color:#c7254e;background-color:#f9f2f4;border-radius:4px} +kbd{color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)} +kbd kbd{padding:0;font-size:100%;-webkit-box-shadow:none;box-shadow:none} +pre{padding:9.5px;margin:0 0 10px;font-size:13px;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px} +.container,.container-fluid{margin-right:auto;margin-left:auto} +pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-radius:0} +.container,.container-fluid{padding-right:15px;padding-left:15px} +.pre-scrollable{overflow-y:scroll} +@media (min-width:992px){.container{width:970px} +} +@media (min-width:1200px){.container{width:1170px} +} +.row{margin-right:-15px;margin-left:-15px} +.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px} +.col-xs-12{width:100%} +.col-xs-11{width:91.66666667%} +.col-xs-10{width:83.33333333%} +.col-xs-9{width:75%} +.col-xs-8{width:66.66666667%} +.col-xs-7{width:58.33333333%} +.col-xs-6{width:50%} +.col-xs-5{width:41.66666667%} +.col-xs-4{width:33.33333333%} +.col-xs-3{width:25%} +.col-xs-2{width:16.66666667%} +.col-xs-1{width:8.33333333%} +.col-xs-pull-12{right:100%} +.col-xs-pull-11{right:91.66666667%} +.col-xs-pull-10{right:83.33333333%} +.col-xs-pull-9{right:75%} +.col-xs-pull-8{right:66.66666667%} +.col-xs-pull-7{right:58.33333333%} +.col-xs-pull-6{right:50%} +.col-xs-pull-5{right:41.66666667%} +.col-xs-pull-4{right:33.33333333%} +.col-xs-pull-3{right:25%} +.col-xs-pull-2{right:16.66666667%} +.col-xs-pull-1{right:8.33333333%} +.col-xs-pull-0{right:auto} +.col-xs-push-12{left:100%} +.col-xs-push-11{left:91.66666667%} +.col-xs-push-10{left:83.33333333%} +.col-xs-push-9{left:75%} +.col-xs-push-8{left:66.66666667%} +.col-xs-push-7{left:58.33333333%} +.col-xs-push-6{left:50%} +.col-xs-push-5{left:41.66666667%} +.col-xs-push-4{left:33.33333333%} +.col-xs-push-3{left:25%} +.col-xs-push-2{left:16.66666667%} +.col-xs-push-1{left:8.33333333%} +.col-xs-push-0{left:auto} +.col-xs-offset-12{margin-left:100%} +.col-xs-offset-11{margin-left:91.66666667%} +.col-xs-offset-10{margin-left:83.33333333%} +.col-xs-offset-9{margin-left:75%} +.col-xs-offset-8{margin-left:66.66666667%} +.col-xs-offset-7{margin-left:58.33333333%} +.col-xs-offset-6{margin-left:50%} +.col-xs-offset-5{margin-left:41.66666667%} +.col-xs-offset-4{margin-left:33.33333333%} +.col-xs-offset-3{margin-left:25%} +.col-xs-offset-2{margin-left:16.66666667%} +.col-xs-offset-1{margin-left:8.33333333%} +.col-xs-offset-0{margin-left:0} +@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left} +.col-sm-12{width:100%} +.col-sm-11{width:91.66666667%} +.col-sm-10{width:83.33333333%} +.col-sm-9{width:75%} +.col-sm-8{width:66.66666667%} +.col-sm-7{width:58.33333333%} +.col-sm-6{width:50%} +.col-sm-5{width:41.66666667%} +.col-sm-4{width:33.33333333%} +.col-sm-3{width:25%} +.col-sm-2{width:16.66666667%} +.col-sm-1{width:8.33333333%} +.col-sm-pull-12{right:100%} +.col-sm-pull-11{right:91.66666667%} +.col-sm-pull-10{right:83.33333333%} +.col-sm-pull-9{right:75%} +.col-sm-pull-8{right:66.66666667%} +.col-sm-pull-7{right:58.33333333%} +.col-sm-pull-6{right:50%} +.col-sm-pull-5{right:41.66666667%} +.col-sm-pull-4{right:33.33333333%} +.col-sm-pull-3{right:25%} +.col-sm-pull-2{right:16.66666667%} +.col-sm-pull-1{right:8.33333333%} +.col-sm-pull-0{right:auto} +.col-sm-push-12{left:100%} +.col-sm-push-11{left:91.66666667%} +.col-sm-push-10{left:83.33333333%} +.col-sm-push-9{left:75%} +.col-sm-push-8{left:66.66666667%} +.col-sm-push-7{left:58.33333333%} +.col-sm-push-6{left:50%} +.col-sm-push-5{left:41.66666667%} +.col-sm-push-4{left:33.33333333%} +.col-sm-push-3{left:25%} +.col-sm-push-2{left:16.66666667%} +.col-sm-push-1{left:8.33333333%} +.col-sm-push-0{left:auto} +.col-sm-offset-12{margin-left:100%} +.col-sm-offset-11{margin-left:91.66666667%} +.col-sm-offset-10{margin-left:83.33333333%} +.col-sm-offset-9{margin-left:75%} +.col-sm-offset-8{margin-left:66.66666667%} +.col-sm-offset-7{margin-left:58.33333333%} +.col-sm-offset-6{margin-left:50%} +.col-sm-offset-5{margin-left:41.66666667%} +.col-sm-offset-4{margin-left:33.33333333%} +.col-sm-offset-3{margin-left:25%} +.col-sm-offset-2{margin-left:16.66666667%} +.col-sm-offset-1{margin-left:8.33333333%} +.col-sm-offset-0{margin-left:0} +} +@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left} +.col-md-12{width:100%} +.col-md-11{width:91.66666667%} +.col-md-10{width:83.33333333%} +.col-md-9{width:75%} +.col-md-8{width:66.66666667%} +.col-md-7{width:58.33333333%} +.col-md-6{width:50%} +.col-md-5{width:41.66666667%} +.col-md-4{width:33.33333333%} +.col-md-3{width:25%} +.col-md-2{width:16.66666667%} +.col-md-1{width:8.33333333%} +.col-md-pull-12{right:100%} +.col-md-pull-11{right:91.66666667%} +.col-md-pull-10{right:83.33333333%} +.col-md-pull-9{right:75%} +.col-md-pull-8{right:66.66666667%} +.col-md-pull-7{right:58.33333333%} +.col-md-pull-6{right:50%} +.col-md-pull-5{right:41.66666667%} +.col-md-pull-4{right:33.33333333%} +.col-md-pull-3{right:25%} +.col-md-pull-2{right:16.66666667%} +.col-md-pull-1{right:8.33333333%} +.col-md-pull-0{right:auto} +.col-md-push-12{left:100%} +.col-md-push-11{left:91.66666667%} +.col-md-push-10{left:83.33333333%} +.col-md-push-9{left:75%} +.col-md-push-8{left:66.66666667%} +.col-md-push-7{left:58.33333333%} +.col-md-push-6{left:50%} +.col-md-push-5{left:41.66666667%} +.col-md-push-4{left:33.33333333%} +.col-md-push-3{left:25%} +.col-md-push-2{left:16.66666667%} +.col-md-push-1{left:8.33333333%} +.col-md-push-0{left:auto} +.col-md-offset-12{margin-left:100%} +.col-md-offset-11{margin-left:91.66666667%} +.col-md-offset-10{margin-left:83.33333333%} +.col-md-offset-9{margin-left:75%} +.col-md-offset-8{margin-left:66.66666667%} +.col-md-offset-7{margin-left:58.33333333%} +.col-md-offset-6{margin-left:50%} +.col-md-offset-5{margin-left:41.66666667%} +.col-md-offset-4{margin-left:33.33333333%} +.col-md-offset-3{margin-left:25%} +.col-md-offset-2{margin-left:16.66666667%} +.col-md-offset-1{margin-left:8.33333333%} +.col-md-offset-0{margin-left:0} +} +@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left} +.col-lg-12{width:100%} +.col-lg-11{width:91.66666667%} +.col-lg-10{width:83.33333333%} +.col-lg-9{width:75%} +.col-lg-8{width:66.66666667%} +.col-lg-7{width:58.33333333%} +.col-lg-6{width:50%} +.col-lg-5{width:41.66666667%} +.col-lg-4{width:33.33333333%} +.col-lg-3{width:25%} +.col-lg-2{width:16.66666667%} +.col-lg-1{width:8.33333333%} +.col-lg-pull-12{right:100%} +.col-lg-pull-11{right:91.66666667%} +.col-lg-pull-10{right:83.33333333%} +.col-lg-pull-9{right:75%} +.col-lg-pull-8{right:66.66666667%} +.col-lg-pull-7{right:58.33333333%} +.col-lg-pull-6{right:50%} +.col-lg-pull-5{right:41.66666667%} +.col-lg-pull-4{right:33.33333333%} +.col-lg-pull-3{right:25%} +.col-lg-pull-2{right:16.66666667%} +.col-lg-pull-1{right:8.33333333%} +.col-lg-pull-0{right:auto} +.col-lg-push-12{left:100%} +.col-lg-push-11{left:91.66666667%} +.col-lg-push-10{left:83.33333333%} +.col-lg-push-9{left:75%} +.col-lg-push-8{left:66.66666667%} +.col-lg-push-7{left:58.33333333%} +.col-lg-push-6{left:50%} +.col-lg-push-5{left:41.66666667%} +.col-lg-push-4{left:33.33333333%} +.col-lg-push-3{left:25%} +.col-lg-push-2{left:16.66666667%} +.col-lg-push-1{left:8.33333333%} +.col-lg-push-0{left:auto} +.col-lg-offset-12{margin-left:100%} +.col-lg-offset-11{margin-left:91.66666667%} +.col-lg-offset-10{margin-left:83.33333333%} +.col-lg-offset-9{margin-left:75%} +.col-lg-offset-8{margin-left:66.66666667%} +.col-lg-offset-7{margin-left:58.33333333%} +.col-lg-offset-6{margin-left:50%} +.col-lg-offset-5{margin-left:41.66666667%} +.col-lg-offset-4{margin-left:33.33333333%} +.col-lg-offset-3{margin-left:25%} +.col-lg-offset-2{margin-left:16.66666667%} +.col-lg-offset-1{margin-left:8.33333333%} +.col-lg-offset-0{margin-left:0} +} +caption{padding-top:8px;padding-bottom:8px;color:#777} +.table{width:100%;max-width:100%;margin-bottom:20px} +.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd} +.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd} +.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0} +.table>tbody+tbody{border-top:2px solid #ddd} +.table .table{background-color:#fff} +.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px} +.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd} +.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px} +.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9} +.table-hover>tbody>tr:hover,.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5} +table col[class*=col-]{position:static;display:table-column;float:none} +table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none} +.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8} +.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8} +.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6} +.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7} +.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3} +.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3} +.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc} +.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede} +.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc} +.table-responsive{min-height:.01%;overflow-x:auto} +@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd} +.table-responsive>.table{margin-bottom:0} +.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap} +.table-responsive>.table-bordered{border:0} +.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0} +.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0} +.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0} +} +fieldset,legend{padding:0;border:0} +fieldset{min-width:0;margin:0} +legend{width:100%;margin-bottom:20px;font-size:21px;line-height:inherit;border-bottom:1px solid #e5e5e5} +label{display:inline-block;max-width:100%;margin-bottom:5px} +input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none} +input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal} +.form-control,output{font-size:14px;line-height:1.42857143;color:#555;display:block} +input[type=file]{display:block} +input[type=range]{display:block;width:100%} +select[multiple],select[size]{height:auto} +input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} +output{padding-top:7px} +.form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s} +.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)} +.form-control::-moz-placeholder{color:#999;opacity:1} +.form-control:-ms-input-placeholder{color:#999} +.form-control::-webkit-input-placeholder{color:#999} +.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .form-control-feedback,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d} +.form-control::-ms-expand{background-color:transparent;border:0} +.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1} +.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed} +textarea.form-control{height:auto} +@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px} +.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px} +.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px} +} +.form-group{margin-bottom:15px} +.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px} +.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer} +.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px} +.checkbox+.checkbox,.radio+.radio{margin-top:-5px} +.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer} +.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px} +.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio label,fieldset[disabled] .radio-inline,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed} +.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0} +.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0} +.form-group-sm .form-control,.input-sm{padding:5px 10px;border-radius:3px;font-size:12px} +.input-sm{height:30px;line-height:1.5} +select.input-sm{height:30px;line-height:30px} +select[multiple].input-sm,textarea.input-sm{height:auto} +.form-group-sm .form-control{height:30px;line-height:1.5} +.form-group-lg .form-control,.input-lg{border-radius:6px;padding:10px 16px;font-size:18px} +.form-group-sm select.form-control{height:30px;line-height:30px} +.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto} +.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5} +.input-lg{height:46px;line-height:1.3333333} +select.input-lg{height:46px;line-height:46px} +select[multiple].input-lg,textarea.input-lg{height:auto} +.form-group-lg .form-control{height:46px;line-height:1.3333333} +.form-group-lg select.form-control{height:46px;line-height:46px} +.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto} +.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333} +.has-feedback{position:relative} +.has-feedback .form-control{padding-right:42.5px} +.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none} +.collapsing,.dropdown,.dropup{position:relative} +.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px} +.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px} +.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)} +.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168} +.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d} +.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .form-control-feedback,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b} +.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)} +.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b} +.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b} +.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .form-control-feedback,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442} +.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)} +.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483} +.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442} +.has-feedback label~.form-control-feedback{top:25px} +.has-feedback label.sr-only~.form-control-feedback{top:0} +.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373} +@media (min-width:768px){.form-inline .form-control-static,.form-inline .form-group{display:inline-block} +.form-inline .control-label,.form-inline .form-group{margin-bottom:0;vertical-align:middle} +.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle} +.form-inline .input-group{display:inline-table;vertical-align:middle} +.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto} +.form-inline .input-group>.form-control{width:100%} +.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle} +.form-inline .checkbox label,.form-inline .radio label{padding-left:0} +.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0} +.form-inline .has-feedback .form-control-feedback{top:0} +.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right} +} +.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0} +.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px} +.form-horizontal .form-group{margin-right:-15px;margin-left:-15px} +.form-horizontal .has-feedback .form-control-feedback{right:15px} +@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px} +.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px} +} +.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;border-radius:4px} +.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} +.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none} +.btn.active,.btn:active{outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)} +.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65} +a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none} +.btn-default{color:#333;background-color:#fff;border-color:#ccc} +.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c} +.btn-default.active,.btn-default:active,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad} +.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c} +.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc} +.btn-default .badge{color:#fff;background-color:#333} +.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4} +.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40} +.btn-primary.active,.btn-primary:active,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74} +.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40} +.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4} +.btn-primary .badge{color:#337ab7;background-color:#fff} +.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c} +.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625} +.btn-success.active,.btn-success:active,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439} +.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625} +.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none} +.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c} +.btn-success .badge{color:#5cb85c;background-color:#fff} +.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da} +.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85} +.btn-info.active,.btn-info:active,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc} +.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85} +.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da} +.btn-info .badge{color:#5bc0de;background-color:#fff} +.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236} +.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d} +.btn-warning.active,.btn-warning:active,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512} +.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d} +.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236} +.btn-warning .badge{color:#f0ad4e;background-color:#fff} +.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a} +.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19} +.btn-danger.active,.btn-danger:active,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925} +.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19} +.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a} +.btn-danger .badge{color:#d9534f;background-color:#fff} +.btn-link{font-weight:400;color:#337ab7;border-radius:0} +.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none} +.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent} +.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent} +.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none} +.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px} +.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px} +.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px} +.btn-block{display:block;width:100%} +.btn-block+.btn-block{margin-top:5px} +input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%} +.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear} +.fade.in{opacity:1} +.collapse{display:none} +.collapse.in{display:block} +tr.collapse.in{display:table-row} +tbody.collapse.in{display:table-row-group} +.collapsing{height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility} +.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent} +.dropdown-toggle:focus{outline:0} +.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)} +.dropdown-menu-right,.dropdown-menu.pull-right{right:0;left:auto} +.dropdown-header,.dropdown-menu>li>a{display:block;padding:3px 20px;line-height:1.42857143;white-space:nowrap} +.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle,.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0} +.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child,.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0} +.btn-group-vertical>.btn:not(:first-child):not(:last-child),.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn,.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0} +.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5} +.dropdown-menu>li>a{clear:both;font-weight:400;color:#333} +.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5} +.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0} +.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777} +.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)} +.open>.dropdown-menu{display:block} +.open>a{outline:0} +.dropdown-menu-left{right:auto;left:0} +.dropdown-header{font-size:12px;color:#777} +.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990} +.nav-justified>.dropdown .dropdown-menu,.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto} +.pull-right>.dropdown-menu{right:0;left:auto} +.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9} +.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px} +@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto} +.navbar-right .dropdown-menu-left{right:auto;left:0} +} +.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle} +.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left} +.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2} +.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px} +.btn-toolbar{margin-left:-5px} +.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px} +.btn .caret,.btn-group>.btn:first-child{margin-left:0} +.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0} +.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px} +.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px} +.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)} +.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none} +.btn-lg .caret{border-width:5px 5px 0} +.dropup .btn-lg .caret{border-width:0 5px 5px} +.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%} +.btn-group-vertical>.btn-group>.btn{float:none} +.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0} +.btn-group-vertical>.btn:first-child:not(:last-child){border-radius:4px 4px 0 0} +.btn-group-vertical>.btn:last-child:not(:first-child){border-radius:0 0 4px 4px} +.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0} +.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0} +.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0} +.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate} +.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%} +.btn-group-justified>.btn-group .btn{width:100%} +.btn-group-justified>.btn-group .dropdown-menu{left:auto} +[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none} +.input-group{position:relative;display:table;border-collapse:separate} +.input-group[class*=col-]{float:none;padding-right:0;padding-left:0} +.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0} +.input-group .form-control:focus{z-index:3} +.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px} +select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px} +select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto} +.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px} +select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px} +select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto} +.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell} +.nav>li,.nav>li>a{display:block;position:relative} +.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0} +.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle} +.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px} +.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px} +.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px} +.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0} +.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0} +.input-group-addon:first-child{border-right:0} +.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0} +.input-group-addon:last-child{border-left:0} +.input-group-btn{position:relative;font-size:0;white-space:nowrap} +.input-group-btn>.btn{position:relative} +.input-group-btn>.btn+.btn{margin-left:-1px} +.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2} +.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px} +.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px} +.nav{padding-left:0;margin-bottom:0;list-style:none} +.nav>li>a{padding:10px 15px} +.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee} +.nav>li.disabled>a{color:#777} +.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent} +.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7} +.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5} +.nav>li>a>img{max-width:none} +.nav-tabs{border-bottom:1px solid #ddd} +.nav-tabs>li{float:left;margin-bottom:-1px} +.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0} +.nav-tabs>li>a:hover{border-color:#eee #eee #ddd} +.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent} +.nav-tabs.nav-justified{width:100%;border-bottom:0} +.nav-tabs.nav-justified>li{float:none} +.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center;margin-right:0;border-radius:4px} +.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd} +@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%} +.nav-tabs.nav-justified>li>a{margin-bottom:0;border-bottom:1px solid #ddd;border-radius:4px 4px 0 0} +.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff} +} +.nav-pills>li{float:left} +.nav-justified>li,.nav-stacked>li{float:none} +.nav-pills>li>a{border-radius:4px} +.nav-pills>li+li{margin-left:2px} +.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7} +.nav-stacked>li+li{margin-top:2px;margin-left:0} +.nav-justified{width:100%} +.nav-justified>li>a{margin-bottom:5px;text-align:center} +.nav-tabs-justified{border-bottom:0} +.nav-tabs-justified>li>a{margin-right:0;border-radius:4px} +.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd} +@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%} +.nav-justified>li>a{margin-bottom:0} +.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0} +.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff} +} +.tab-content>.tab-pane{display:none} +.tab-content>.active{display:block} +.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0} +.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent} +.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)} +.navbar-collapse.in{overflow-y:auto} +@media (min-width:768px){.navbar{border-radius:4px} +.navbar-header{float:left} +.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none} +.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important} +.navbar-collapse.in{overflow-y:visible} +.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0} +} +.embed-responsive,.modal,.modal-open,.progress{overflow:hidden} +@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px} +} +.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px} +.navbar-static-top{z-index:1000;border-width:0 0 1px} +.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030} +.navbar-fixed-top{top:0;border-width:0 0 1px} +.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0} +.navbar-brand{float:left;height:50px;padding:15px;font-size:18px;line-height:20px} +.navbar-brand:focus,.navbar-brand:hover{text-decoration:none} +.navbar-brand>img{display:block} +@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0} +.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0} +.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px} +} +.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px} +.navbar-toggle:focus{outline:0} +.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px} +.navbar-toggle .icon-bar+.icon-bar{margin-top:4px} +.navbar-nav{margin:7.5px -15px} +.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px} +@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none} +.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px} +.navbar-nav .open .dropdown-menu>li>a{line-height:20px} +.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none} +} +.progress-bar-striped,.progress-striped .progress-bar,.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +@media (min-width:768px){.navbar-toggle{display:none} +.navbar-nav{float:left;margin:0} +.navbar-nav>li{float:left} +.navbar-nav>li>a{padding-top:15px;padding-bottom:15px} +} +.navbar-form{padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin:8px -15px} +@media (min-width:768px){.navbar-form .form-control-static,.navbar-form .form-group{display:inline-block} +.navbar-form .control-label,.navbar-form .form-group{margin-bottom:0;vertical-align:middle} +.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle} +.navbar-form .input-group{display:inline-table;vertical-align:middle} +.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto} +.navbar-form .input-group>.form-control{width:100%} +.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle} +.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0} +.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0} +.navbar-form .has-feedback .form-control-feedback{top:0} +.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none} +} +.breadcrumb>li,.pagination{display:inline-block} +.btn .badge,.btn .label{top:-1px;position:relative} +@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px} +.navbar-form .form-group:last-child{margin-bottom:0} +} +.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0} +.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-radius:4px 4px 0 0} +.navbar-btn{margin-top:8px;margin-bottom:8px} +.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px} +.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px} +.navbar-text{margin-top:15px;margin-bottom:15px} +@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px} +.navbar-left{float:left!important} +.navbar-right{float:right!important;margin-right:-15px} +.navbar-right~.navbar-right{margin-right:0} +} +.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7} +.navbar-default .navbar-brand{color:#777} +.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent} +.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#777} +.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent} +.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7} +.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent} +.navbar-default .navbar-toggle{border-color:#ddd} +.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd} +.navbar-default .navbar-toggle .icon-bar{background-color:#888} +.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7} +.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7} +@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777} +.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent} +.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7} +.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent} +} +.navbar-default .navbar-link{color:#777} +.navbar-default .navbar-link:hover{color:#333} +.navbar-default .btn-link{color:#777} +.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333} +.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc} +.navbar-inverse{background-color:#222;border-color:#080808} +.navbar-inverse .navbar-brand{color:#9d9d9d} +.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent} +.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#9d9d9d} +.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent} +.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808} +.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent} +.navbar-inverse .navbar-toggle{border-color:#333} +.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333} +.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff} +.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010} +.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808} +@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808} +.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808} +.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d} +.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent} +.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808} +.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent} +} +.navbar-inverse .navbar-link{color:#9d9d9d} +.navbar-inverse .navbar-link:hover{color:#fff} +.navbar-inverse .btn-link{color:#9d9d9d} +.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff} +.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444} +.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px} +.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"} +.breadcrumb>.active{color:#777} +.pagination{padding-left:0;margin:20px 0;border-radius:4px} +.pager li,.pagination>li{display:inline} +.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd} +.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px} +.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px} +.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd} +.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7} +.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd} +.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333} +.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px} +.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px} +.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5} +.badge,.label{font-weight:700;line-height:1;white-space:nowrap;text-align:center} +.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px} +.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px} +.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none} +.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px} +.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee} +.pager .next>a,.pager .next>span{float:right} +.pager .previous>a,.pager .previous>span{float:left} +.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff} +a.badge:focus,a.badge:hover,a.label:focus,a.label:hover{color:#fff;cursor:pointer;text-decoration:none} +.label{display:inline;padding:.2em .6em .3em;font-size:75%;color:#fff;border-radius:.25em} +.label:empty{display:none} +.label-default{background-color:#777} +.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e} +.label-primary{background-color:#337ab7} +.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090} +.label-success{background-color:#5cb85c} +.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44} +.label-info{background-color:#5bc0de} +.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5} +.label-warning{background-color:#f0ad4e} +.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f} +.label-danger{background-color:#d9534f} +.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c} +.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;color:#fff;vertical-align:middle;background-color:#777;border-radius:10px} +.badge:empty{display:none} +.media-object,.thumbnail{display:block} +.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px} +.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff} +.jumbotron,.jumbotron .h1,.jumbotron h1{color:inherit} +.list-group-item>.badge{float:right} +.list-group-item>.badge+.badge{margin-right:5px} +.nav-pills>li>a>.badge{margin-left:3px} +.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;background-color:#eee} +.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200} +.alert,.thumbnail{margin-bottom:20px} +.alert .alert-link,.close{font-weight:700} +.jumbotron>hr{border-top-color:#d5d5d5} +.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px} +.jumbotron .container{max-width:100%} +@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px} +.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px} +.jumbotron .h1,.jumbotron h1{font-size:63px} +} +.thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out} +.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto} +a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7} +.thumbnail .caption{padding:9px;color:#333} +.alert{padding:15px;border:1px solid transparent;border-radius:4px} +.alert h4{margin-top:0;color:inherit} +.alert>p,.alert>ul{margin-bottom:0} +.alert>p+p{margin-top:5px} +.alert-dismissable,.alert-dismissible{padding-right:35px} +.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit} +.modal,.modal-backdrop{top:0;right:0;bottom:0;left:0} +.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6} +.alert-success hr{border-top-color:#c9e2b3} +.alert-success .alert-link{color:#2b542c} +.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1} +.alert-info hr{border-top-color:#a6e1ec} +.alert-info .alert-link{color:#245269} +.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc} +.alert-warning hr{border-top-color:#f7e1b5} +.alert-warning .alert-link{color:#66512c} +.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1} +.alert-danger hr{border-top-color:#e4b9c0} +.alert-danger .alert-link{color:#843534} +@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0} +to{background-position:0 0} +} +@-o-keyframes progress-bar-stripes{from{background-position:40px 0} +to{background-position:0 0} +} +@keyframes progress-bar-stripes{from{background-position:40px 0} +to{background-position:0 0} +} +.progress{height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)} +.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease} +.progress-bar-striped,.progress-striped .progress-bar{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px} +.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite} +.progress-bar-success{background-color:#5cb85c} +.progress-striped .progress-bar-success{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.progress-striped .progress-bar-info,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.progress-bar-info{background-color:#5bc0de} +.progress-striped .progress-bar-info{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.progress-bar-warning{background-color:#f0ad4e} +.progress-striped .progress-bar-warning{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.progress-bar-danger{background-color:#d9534f} +.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.media{margin-top:15px} +.media:first-child{margin-top:0} +.media,.media-body{overflow:hidden;zoom:1} +.media-body{width:10000px} +.media-object.img-thumbnail{max-width:none} +.media-right,.media>.pull-right{padding-left:10px} +.media-left,.media>.pull-left{padding-right:10px} +.media-body,.media-left,.media-right{display:table-cell;vertical-align:top} +.media-middle{vertical-align:middle} +.media-bottom{vertical-align:bottom} +.media-heading{margin-top:0;margin-bottom:5px} +.media-list{padding-left:0;list-style:none} +.list-group{padding-left:0;margin-bottom:20px} +.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd} +.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px} +.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px} +a.list-group-item,button.list-group-item{color:#555} +a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333} +a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5} +button.list-group-item{width:100%;text-align:left} +.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee} +.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit} +.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777} +.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7} +.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit} +.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef} +.list-group-item-success{color:#3c763d;background-color:#dff0d8} +a.list-group-item-success,button.list-group-item-success{color:#3c763d} +a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit} +a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6} +a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d} +.list-group-item-info{color:#31708f;background-color:#d9edf7} +a.list-group-item-info,button.list-group-item-info{color:#31708f} +a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit} +a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3} +a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f} +.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3} +a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b} +a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit} +a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc} +a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b} +.list-group-item-danger{color:#a94442;background-color:#f2dede} +a.list-group-item-danger,button.list-group-item-danger{color:#a94442} +a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit} +a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc} +a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442} +.panel-heading>.dropdown .dropdown-toggle,.panel-title,.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit} +.list-group-item-heading{margin-top:0;margin-bottom:5px} +.list-group-item-text{margin-bottom:0;line-height:1.3} +.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)} +.panel-title,.panel>.list-group,.panel>.panel-collapse>.list-group,.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0} +.panel-body{padding:15px} +.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px} +.panel-title{margin-top:0;font-size:16px} +.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px} +.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0} +.panel-group .panel-heading,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0} +.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px} +.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px} +.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0} +.list-group+.panel-footer,.panel-heading+.list-group .list-group-item:first-child{border-top-width:0} +.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px} +.panel>.table-responsive:first-child>.table:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px} +.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px} +.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px} +.panel>.table-responsive:last-child>.table:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px} +.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px} +.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px} +.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd} +.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0} +.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0} +.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0} +.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0} +.panel>.table-responsive{margin-bottom:0;border:0} +.panel-group{margin-bottom:20px} +.panel-group .panel{margin-bottom:0;border-radius:4px} +.panel-group .panel+.panel{margin-top:5px} +.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd} +.panel-group .panel-footer{border-top:0} +.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd} +.panel-default{border-color:#ddd} +.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd} +.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd} +.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333} +.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd} +.panel-primary{border-color:#337ab7} +.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7} +.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7} +.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff} +.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7} +.panel-success{border-color:#d6e9c6} +.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6} +.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6} +.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d} +.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6} +.panel-info{border-color:#bce8f1} +.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1} +.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1} +.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f} +.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1} +.panel-warning{border-color:#faebcc} +.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc} +.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc} +.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b} +.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc} +.panel-danger{border-color:#ebccd1} +.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1} +.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1} +.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442} +.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1} +.embed-responsive{position:relative;display:block;height:0;padding:0} +.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0} +.embed-responsive-16by9{padding-bottom:56.25%} +.embed-responsive-4by3{padding-bottom:75%} +.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)} +.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)} +.well-lg{padding:24px;border-radius:6px} +.well-sm{padding:9px;border-radius:3px} +.close{float:right;font-size:21px;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2} +.popover,.tooltip{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;line-break:auto;text-decoration:none} +.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5} +button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0} +.modal{position:fixed;z-index:1050;display:none;-webkit-overflow-scrolling:touch;outline:0} +.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)} +.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)} +.modal-open .modal{overflow-x:hidden;overflow-y:auto} +.modal-dialog{position:relative;width:auto;margin:10px} +.modal-content{position:relative;background-color:#fff;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)} +.modal-backdrop{position:fixed;z-index:1040;background-color:#000} +.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0} +.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5} +.modal-header{padding:15px;border-bottom:1px solid #e5e5e5} +.modal-header .close{margin-top:-2px} +.modal-title{margin:0;line-height:1.42857143} +.modal-body{position:relative;padding:15px} +.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5} +.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px} +.modal-footer .btn-group .btn+.btn{margin-left:-1px} +.modal-footer .btn-block+.btn-block{margin-left:0} +.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll} +@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto} +.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)} +.modal-sm{width:300px} +} +@media (min-width:992px){.modal-lg{width:900px} +} +.tooltip{position:absolute;z-index:1070;display:block;font-size:12px;text-align:left;text-align:start;filter:alpha(opacity=0);opacity:0} +.tooltip.in{filter:alpha(opacity=90);opacity:.9} +.tooltip.top{padding:5px 0;margin-top:-3px} +.tooltip.right{padding:0 5px;margin-left:3px} +.tooltip.bottom{padding:5px 0;margin-top:3px} +.tooltip.left{padding:0 5px;margin-left:-3px} +.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px} +.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid} +.tooltip.top .tooltip-arrow,.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;border-width:5px 5px 0;border-top-color:#000} +.tooltip.top .tooltip-arrow{left:50%;margin-left:-5px} +.tooltip.top-left .tooltip-arrow{right:5px;margin-bottom:-5px} +.tooltip.top-right .tooltip-arrow{left:5px;margin-bottom:-5px} +.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000} +.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000} +.tooltip.bottom .tooltip-arrow,.tooltip.bottom-left .tooltip-arrow,.tooltip.bottom-right .tooltip-arrow{border-width:0 5px 5px;border-bottom-color:#000;top:0} +.tooltip.bottom .tooltip-arrow{left:50%;margin-left:-5px} +.tooltip.bottom-left .tooltip-arrow{right:5px;margin-top:-5px} +.tooltip.bottom-right .tooltip-arrow{left:5px;margin-top:-5px} +.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-size:14px;text-align:left;text-align:start;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)} +.carousel-caption,.carousel-control{color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)} +.popover.top{margin-top:-10px} +.popover.right{margin-left:10px} +.popover.bottom{margin-top:10px} +.popover.left{margin-left:-10px} +.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0} +.popover-content{padding:9px 14px} +.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid} +.carousel,.carousel-inner{position:relative} +.popover>.arrow{border-width:11px} +.popover>.arrow:after{content:"";border-width:10px} +.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0} +.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0} +.popover.left>.arrow:after,.popover.right>.arrow:after{bottom:-10px;content:" "} +.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0} +.popover.right>.arrow:after{left:1px;border-right-color:#fff;border-left-width:0} +.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)} +.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff} +.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)} +.popover.left>.arrow:after{right:1px;border-right-width:0;border-left-color:#fff} +.carousel-inner{width:100%;overflow:hidden} +.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left} +.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1} +@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px} +.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)} +.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)} +.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)} +} +.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block} +.carousel-inner>.active{left:0} +.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%} +.carousel-inner>.next{left:100%} +.carousel-inner>.prev{left:-100%} +.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0} +.carousel-inner>.active.left{left:-100%} +.carousel-inner>.active.right{left:100%} +.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5} +.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x} +.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x} +.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9} +.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px} +.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px} +.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px} +.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1} +.carousel-control .icon-prev:before{content:'\2039'} +.carousel-control .icon-next:before{content:'\203a'} +.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none} +.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px} +.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff} +.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px} +.carousel-caption .btn,.text-hide{text-shadow:none} +@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px} +.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px} +.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px} +.carousel-caption{right:20%;left:20%;padding-bottom:30px} +.carousel-indicators{bottom:20px} +} +.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "} +.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both} +.center-block{display:block;margin-right:auto;margin-left:auto} +.pull-right{float:right!important} +.pull-left{float:left!important} +.hide{display:none!important} +.show{display:block!important} +.hidden,.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important} +.invisible{visibility:hidden} +.text-hide{font:0/0 a;color:transparent;background-color:transparent;border:0} +.affix{position:fixed} +@-ms-viewport{width:device-width} +@media (max-width:767px){.visible-xs{display:block!important} +table.visible-xs{display:table!important} +tr.visible-xs{display:table-row!important} +td.visible-xs,th.visible-xs{display:table-cell!important} +.visible-xs-block{display:block!important} +.visible-xs-inline{display:inline!important} +.visible-xs-inline-block{display:inline-block!important} +} +@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important} +table.visible-sm{display:table!important} +tr.visible-sm{display:table-row!important} +td.visible-sm,th.visible-sm{display:table-cell!important} +.visible-sm-block{display:block!important} +.visible-sm-inline{display:inline!important} +.visible-sm-inline-block{display:inline-block!important} +} +@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important} +table.visible-md{display:table!important} +tr.visible-md{display:table-row!important} +td.visible-md,th.visible-md{display:table-cell!important} +.visible-md-block{display:block!important} +.visible-md-inline{display:inline!important} +.visible-md-inline-block{display:inline-block!important} +} +@media (min-width:1200px){.visible-lg{display:block!important} +table.visible-lg{display:table!important} +tr.visible-lg{display:table-row!important} +td.visible-lg,th.visible-lg{display:table-cell!important} +.visible-lg-block{display:block!important} +.visible-lg-inline{display:inline!important} +.visible-lg-inline-block{display:inline-block!important} +.hidden-lg{display:none!important} +} +@media (max-width:767px){.hidden-xs{display:none!important} +} +@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important} +} +@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important} +} +.visible-print{display:none!important} +@media print{.visible-print{display:block!important} +table.visible-print{display:table!important} +tr.visible-print{display:table-row!important} +td.visible-print,th.visible-print{display:table-cell!important} +} +.visible-print-block{display:none!important} +@media print{.visible-print-block{display:block!important} +} +.visible-print-inline{display:none!important} +@media print{.visible-print-inline{display:inline!important} +} +.visible-print-inline-block{display:none!important} +@media print{.visible-print-inline-block{display:inline-block!important} +.hidden-print{display:none!important} +} +.hljs{display:block;background:#fff;padding:.5em;color:#333;overflow-x:auto} +.hljs-comment,.hljs-meta{color:#969896} +.hljs-emphasis,.hljs-quote,.hljs-string,.hljs-strong,.hljs-template-variable,.hljs-variable{color:#df5000} +.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#a71d5d} +.hljs-attribute,.hljs-bullet,.hljs-literal,.hljs-symbol{color:#0086b3} +.hljs-name,.hljs-section{color:#63a35c} +.hljs-tag{color:#333} +.hljs-attr,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title{color:#795da3} +.hljs-addition{color:#55a532;background-color:#eaffea} +.hljs-deletion{color:#bd2c00;background-color:#ffecec} +.hljs-link{text-decoration:underline} \ No newline at end of file diff --git a/docs/styles/docfx.vendor.js b/docs/styles/docfx.vendor.js new file mode 100644 index 00000000..ff662c6d --- /dev/null +++ b/docs/styles/docfx.vendor.js @@ -0,0 +1,55 @@ +/*! jQuery v2.1.4 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b="length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){ +return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,ba=/<([\w:]+)/,ca=/<|&#?\w+;/,da=/<(?:script|style|link)/i,ea=/checked\s*(?:[^=]|=\s*.checked.)/i,fa=/^$|\/(?:java|ecma)script/i,ga=/^true\/(.*)/,ha=/^\s*\s*$/g,ia={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ia.optgroup=ia.option,ia.tbody=ia.tfoot=ia.colgroup=ia.caption=ia.thead,ia.th=ia.td;function ja(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function ka(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function la(a){var b=ga.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function ma(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function na(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function oa(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pa(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=oa(h),f=oa(a),d=0,e=f.length;e>d;d++)pa(f[d],g[d]);if(b)if(c)for(f=f||oa(a),g=g||oa(h),d=0,e=f.length;e>d;d++)na(f[d],g[d]);else na(a,h);return g=oa(h,"script"),g.length>0&&ma(g,!i&&oa(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(ca.test(e)){f=f||k.appendChild(b.createElement("div")),g=(ba.exec(e)||["",""])[1].toLowerCase(),h=ia[g]||ia._default,f.innerHTML=h[1]+e.replace(aa,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=oa(k.appendChild(e),"script"),i&&ma(f),c)){j=0;while(e=f[j++])fa.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(oa(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&ma(oa(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(oa(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!da.test(a)&&!ia[(ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(aa,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(oa(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(oa(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&ea.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(oa(c,"script"),ka),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,oa(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,la),j=0;g>j;j++)h=f[j],fa.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(ha,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qa,ra={};function sa(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function ta(a){var b=l,c=ra[a];return c||(c=sa(a,b),"none"!==c&&c||(qa=(qa||n("