private void ConnectionManagerThread(object state)
        {
            Thread.CurrentThread.Name = "ConnectionsManager_ConnectionManagerThread";
            Thread.CurrentThread.Priority = ThreadPriority.Lowest;

            var connectionManager = state as ConnectionManager;
            if (connectionManager == null) return;

            try
            {
                var packetManager = _packetControlManager[connectionManager.Node];

                var nodeUpdateTime = new Stopwatch();
                var updateTime = new Stopwatch();
                updateTime.Start();
                var blockDiffusionTime = new Stopwatch();
                blockDiffusionTime.Start();
                var metadataUpdateTime = new Stopwatch();
                metadataUpdateTime.Start();

                for (;;)
                {
                    Thread.Sleep(1000);
                    if (this.State == ManagerState.Stop) return;
                    if (!_connectionManagers.Contains(connectionManager)) return;

                    var connectionCount = 0;

                    lock (_thisLock)
                    {
                        connectionCount = _connectionManagers.Count;
                    }

                    // PushNodes
                    if (!nodeUpdateTime.IsRunning || nodeUpdateTime.Elapsed.TotalMinutes >= 3)
                    {
                        nodeUpdateTime.Restart();

                        var nodes = new HashSet<Node>();

                        lock (_thisLock)
                        {
                            foreach (var node in _routeTable.Randomize())
                            {
                                if (nodes.Count >= 64) break;

                                if (node.Uris.Any(n => _succeededUris.Contains(n)))
                                {
                                    nodes.Add(node);
                                }
                            }

                            foreach (var node in _routeTable.Randomize())
                            {
                                if (nodes.Count >= 128) break;

                                nodes.Add(node);
                            }
                        }

                        if (nodes.Count > 0)
                        {
                            connectionManager.PushNodes(nodes.Randomize());

                            Debug.WriteLine(string.Format("ConnectionManager: Push Nodes ({0})", nodes.Count));
                            _pushNodeCount.Add(nodes.Count);
                        }
                    }

                    if (updateTime.Elapsed.TotalSeconds >= 60)
                    {
                        updateTime.Restart();

                        // PushBlocksLink
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            List<Key> targetList = null;

                            lock (_pushBlocksLinkDictionary.ThisLock)
                            {
                                if (_pushBlocksLinkDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushBlocksLinkDictionary.Remove(connectionManager.Node);
                                }
                            }

                            if (targetList != null)
                            {
                                connectionManager.PushBlocksLink(targetList);

                                Debug.WriteLine(string.Format("ConnectionManager: Push BlocksLink ({0})", targetList.Count));
                                _pushBlockLinkCount.Add(targetList.Count);
                            }
                        }

                        // PushBlocksRequest
                        if (connectionCount >= _downloadingConnectionCountLowerLimit)
                        {
                            List<Key> targetList = null;

                            lock (_pushBlocksRequestDictionary.ThisLock)
                            {
                                if (_pushBlocksRequestDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushBlocksRequestDictionary.Remove(connectionManager.Node);
                                }
                            }

                            if (targetList != null)
                            {
                                connectionManager.PushBlocksRequest(targetList);

                                packetManager.PushBlocksRequest.AddRange(targetList);

                                Debug.WriteLine(string.Format("ConnectionManager: Push BlocksRequest ({0})", targetList.Count));
                                _pushBlockRequestCount.Add(targetList.Count);
                            }
                        }

                        // PushBroadcastMetadatasRequest
                        if (connectionCount >= _downloadingConnectionCountLowerLimit)
                        {
                            List<string> targetList = null;

                            lock (_pushBroadcastMetadatasRequestDictionary.ThisLock)
                            {
                                if (_pushBroadcastMetadatasRequestDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushBroadcastMetadatasRequestDictionary.Remove(connectionManager.Node);
                                }
                            }

                            if (targetList != null)
                            {
                                connectionManager.PushBroadcastMetadatasRequest(targetList);

                                foreach (var item in targetList)
                                {
                                    _pushBroadcastMetadatasRequestList.Remove(item);
                                }

                                Debug.WriteLine(string.Format("ConnectionManager: Push BroadcastMetadatasRequest ({0})", targetList.Count));
                                _pushMetadataRequestCount.Add(targetList.Count);
                            }
                        }

                        // PushUnicastMetadatasRequest
                        if (connectionCount >= _downloadingConnectionCountLowerLimit)
                        {
                            List<string> targetList = null;

                            lock (_pushUnicastMetadatasRequestDictionary.ThisLock)
                            {
                                if (_pushUnicastMetadatasRequestDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushUnicastMetadatasRequestDictionary.Remove(connectionManager.Node);
                                }
                            }

                            if (targetList != null)
                            {
                                connectionManager.PushUnicastMetadatasRequest(targetList);

                                foreach (var item in targetList)
                                {
                                    _pushUnicastMetadatasRequestList.Remove(item);
                                }

                                Debug.WriteLine(string.Format("ConnectionManager: Push UnicastMetadatasRequest ({0})", targetList.Count));
                                _pushMetadataRequestCount.Add(targetList.Count);
                            }
                        }

                        // PushMulticastMetadatasRequest
                        if (connectionCount >= _downloadingConnectionCountLowerLimit)
                        {
                            List<Tag> targetList = null;

                            lock (_pushMulticastMetadatasRequestDictionary.ThisLock)
                            {
                                if (_pushMulticastMetadatasRequestDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushMulticastMetadatasRequestDictionary.Remove(connectionManager.Node);
                                }
                            }

                            if (targetList != null)
                            {
                                connectionManager.PushMulticastMetadatasRequest(targetList);

                                foreach (var item in targetList)
                                {
                                    _pushMulticastMetadatasRequestList.Remove(item);
                                }

                                Debug.WriteLine(string.Format("ConnectionManager: Push MulticastMetadatasRequest ({0})", targetList.Count));
                                _pushMetadataRequestCount.Add(targetList.Count);
                            }
                        }
                    }

                    if (blockDiffusionTime.Elapsed.TotalSeconds >= 3)
                    {
                        blockDiffusionTime.Restart();

                        // PushBlock
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            Key key = null;

                            lock (_diffusionBlocksDictionary.ThisLock)
                            {
                                Queue<Key> queue;

                                if (_diffusionBlocksDictionary.TryGetValue(connectionManager.Node, out queue))
                                {
                                    if (queue.Count > 0)
                                    {
                                        key = queue.Dequeue();
                                    }
                                }
                            }

                            if (key != null)
                            {
                                var buffer = new ArraySegment<byte>();

                                try
                                {
                                    buffer = _cacheManager[key];

                                    connectionManager.PushBlock(key, buffer);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push Block (Diffusion) ({0})", NetworkConverter.ToBase64UrlString(key.Hash)));
                                    _pushBlockCount.Increment();

                                    packetManager.PullBlocksRequest.Remove(key);
                                }
                                catch (BlockNotFoundException)
                                {

                                }
                                finally
                                {
                                    if (buffer.Array != null)
                                    {
                                        _bufferManager.ReturnBuffer(buffer.Array);
                                    }
                                }

                                _blockUploadedEventQueue.Enqueue(key);

                                _settings.UploadBlocksRequest.Remove(key);
                                _settings.DiffusionBlocksRequest.Remove(key);
                            }
                        }
                    }

                    if (_random.NextDouble() < this.GetPriority(connectionManager.Node))
                    {
                        // PushBlock
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            Key key = null;

                            lock (_uploadBlocksDictionary.ThisLock)
                            {
                                Queue<Key> queue;

                                if (_uploadBlocksDictionary.TryGetValue(connectionManager.Node, out queue))
                                {
                                    if (queue.Count > 0)
                                    {
                                        key = queue.Dequeue();
                                    }
                                }
                            }

                            if (key != null)
                            {
                                var buffer = new ArraySegment<byte>();

                                try
                                {
                                    buffer = _cacheManager[key];

                                    connectionManager.PushBlock(key, buffer);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push Block (Upload) ({0})", NetworkConverter.ToBase64UrlString(key.Hash)));
                                    _pushBlockCount.Increment();

                                    packetManager.PullBlocksRequest.Remove(key);

                                    packetManager.Priority.Decrement();

                                    // Infomation
                                    {
                                        if (_relayBlocks.Contains(key))
                                        {
                                            _relayBlockCount.Increment();
                                        }
                                    }
                                }
                                catch (BlockNotFoundException)
                                {

                                }
                                finally
                                {
                                    if (buffer.Array != null)
                                    {
                                        _bufferManager.ReturnBuffer(buffer.Array);
                                    }
                                }

                                _blockUploadedEventQueue.Enqueue(key);

                                _settings.UploadBlocksRequest.Remove(key);
                                _settings.DiffusionBlocksRequest.Remove(key);
                            }
                        }
                    }

                    if (metadataUpdateTime.Elapsed.TotalSeconds >= 60)
                    {
                        metadataUpdateTime.Restart();

                        // PushBroadcastMetadatas
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            {
                                var signatures = packetManager.PullBroadcastMetadatasRequest.ToArray();

                                var broadcastMetadats = new List<BroadcastMetadata>();

                                _random.Shuffle(signatures);
                                foreach (var signature in signatures)
                                {
                                    foreach (var metadata in _settings.MetadataManager.GetBroadcastMetadatas(signature).Randomize())
                                    {
                                        if (!packetManager.StockBroadcastMetadatas.Contains(metadata.CreateHash(_hashAlgorithm)))
                                        {
                                            broadcastMetadats.Add(metadata);

                                            if (broadcastMetadats.Count >= _maxMetadataCount) goto End;
                                        }
                                    }
                                }

                                End:;

                                if (broadcastMetadats.Count > 0)
                                {
                                    connectionManager.PushBroadcastMetadatas(broadcastMetadats);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push BroadcastMetadatas ({0})", broadcastMetadats.Count));
                                    _pushMetadataCount.Add(broadcastMetadats.Count);

                                    foreach (var metadata in broadcastMetadats)
                                    {
                                        packetManager.StockBroadcastMetadatas.Add(metadata.CreateHash(_hashAlgorithm));
                                    }
                                }
                            }
                        }

                        // PushUnicastMetadatas
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            {
                                var signatures = packetManager.PullUnicastMetadatasRequest.ToArray();

                                var unicastMetadata = new List<UnicastMetadata>();

                                _random.Shuffle(signatures);
                                foreach (var signature in signatures)
                                {
                                    foreach (var metadata in _settings.MetadataManager.GetUnicastMetadatas(signature).Randomize())
                                    {
                                        if (!packetManager.StockUnicastMetadatas.Contains(metadata.CreateHash(_hashAlgorithm)))
                                        {
                                            unicastMetadata.Add(metadata);

                                            if (unicastMetadata.Count >= _maxMetadataCount) goto End;
                                        }
                                    }
                                }

                                End:;

                                if (unicastMetadata.Count > 0)
                                {
                                    connectionManager.PushUnicastMetadatas(unicastMetadata);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push UnicastMetadatas ({0})", unicastMetadata.Count));
                                    _pushMetadataCount.Add(unicastMetadata.Count);

                                    foreach (var metadata in unicastMetadata)
                                    {
                                        packetManager.StockUnicastMetadatas.Add(metadata.CreateHash(_hashAlgorithm));
                                    }
                                }
                            }
                        }

                        // PushMulticastMetadatas
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            {
                                var tags = packetManager.PullMulticastMetadatasRequest.ToArray();

                                var multicastMetadatas = new List<MulticastMetadata>();

                                _random.Shuffle(tags);
                                foreach (var tag in tags)
                                {
                                    foreach (var metadata in _settings.MetadataManager.GetMulticastMetadatas(tag).Randomize())
                                    {
                                        if (!packetManager.StockMulticastMetadatas.Contains(metadata.CreateHash(_hashAlgorithm)))
                                        {
                                            multicastMetadatas.Add(metadata);

                                            if (multicastMetadatas.Count >= _maxMetadataCount) goto End;
                                        }
                                    }
                                }

                                End:;

                                if (multicastMetadatas.Count > 0)
                                {
                                    connectionManager.PushMulticastMetadatas(multicastMetadatas);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push MulticastMetadatas ({0})", multicastMetadatas.Count));
                                    _pushMetadataCount.Add(multicastMetadatas.Count);

                                    foreach (var metadata in multicastMetadatas)
                                    {
                                        packetManager.StockMulticastMetadatas.Add(metadata.CreateHash(_hashAlgorithm));
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
            }
            finally
            {
                this.RemoveConnectionManager(connectionManager);
            }
        }
        private void CreateConnectionThread()
        {
            for (;;)
            {
                if (this.State == ManagerState.Stop) return;
                Thread.Sleep(1000);

                // 接続数を制限する。
                {
                    var connectionCount = 0;

                    lock (_thisLock)
                    {
                        connectionCount = _connectionManagers.Count(n => n.Direction == ConnectDirection.Out);
                    }

                    if (connectionCount >= (this.ConnectionCountLimit / 2))
                    {
                        continue;
                    }
                }

                Node node = null;

                lock (_thisLock)
                {
                    node = _routeTable
                        .ToArray()
                        .Where(n => !_connectionManagers.Any(m => CollectionUtils.Equals(m.Node.Id, n.Id))
                            && !_creatingNodes.Contains(n)
                            && !_waitingNodes.Contains(n))
                        .Randomize()
                        .FirstOrDefault();

                    if (node == null) continue;

                    _creatingNodes.Add(node);
                    _waitingNodes.Add(node);
                }

                try
                {
                    var uris = new HashSet<string>();
                    uris.UnionWith(node.Uris.Take(12));

                    if (uris.Count == 0)
                    {
                        lock (_thisLock)
                        {
                            _removeNodes.Remove(node);
                            _routeTable.Remove(node);
                        }

                        continue;
                    }

                    foreach (var uri in uris.Randomize())
                    {
                        if (this.State == ManagerState.Stop) return;

                        var connection = _clientManager.CreateConnection(uri, _bandwidthLimit);

                        if (connection != null)
                        {
                            var connectionManager = new ConnectionManager(connection, _mySessionId, this.BaseNode, ConnectDirection.Out, _bufferManager);

                            try
                            {
                                connectionManager.Connect();
                                if (!ConnectionsManager.Check(connectionManager.Node)) throw new ArgumentException();

                                _succeededUris.Add(uri);

                                lock (_thisLock)
                                {
                                    if (node != connectionManager.Node)
                                    {
                                        this.RemoveNode(connectionManager.Node);
                                    }

                                    if (connectionManager.Node.Uris.Count() != 0)
                                    {
                                        _routeTable.Live(connectionManager.Node);
                                    }
                                }

                                _connectConnectionCount.Increment();

                                this.AddConnectionManager(connectionManager, uri);

                                goto End;
                            }
                            catch (Exception e)
                            {
                                Debug.WriteLine(e);

                                connectionManager.Dispose();
                            }
                        }
                    }

                    this.RemoveNode(node);
                    End:;
                }
                finally
                {
                    _creatingNodes.Remove(node);
                }
            }
        }
        private void ConnectionManagerThread(object state)
        {
            Thread.CurrentThread.Name = "ConnectionsManager_ConnectionManagerThread";
            Thread.CurrentThread.Priority = ThreadPriority.Lowest;

            var connectionManager = state as ConnectionManager;
            if (connectionManager == null) return;

            try
            {
                var messageManager = _messagesManager[connectionManager.Node];

                Stopwatch nodeUpdateTime = new Stopwatch();
                Stopwatch updateTime = new Stopwatch();
                updateTime.Start();
                Stopwatch blockDiffusionTime = new Stopwatch();
                blockDiffusionTime.Start();
                Stopwatch metadataUpdateTime = new Stopwatch();
                metadataUpdateTime.Start();

                for (; ; )
                {
                    Thread.Sleep(1000);
                    if (this.State == ManagerState.Stop) return;
                    if (!_connectionManagers.Contains(connectionManager)) return;

                    var connectionCount = 0;

                    lock (this.ThisLock)
                    {
                        connectionCount = _connectionManagers.Count;
                    }

                    // PushNodes
                    if (!nodeUpdateTime.IsRunning || nodeUpdateTime.Elapsed.TotalMinutes >= 3)
                    {
                        nodeUpdateTime.Restart();

                        var nodes = new HashSet<Node>();

                        lock (this.ThisLock)
                        {
                            foreach (var node in _routeTable.Randomize())
                            {
                                if (nodes.Count >= 64) break;

                                if (node.Uris.Any(n => _succeededUris.Contains(n)))
                                {
                                    nodes.Add(node);
                                }
                            }

                            foreach (var node in _routeTable.Randomize())
                            {
                                if (nodes.Count >= 128) break;

                                nodes.Add(node);
                            }
                        }

                        if (nodes.Count > 0)
                        {
                            connectionManager.PushNodes(nodes.Randomize());

                            Debug.WriteLine(string.Format("ConnectionManager: Push Nodes ({0})", nodes.Count));
                            _pushNodeCount.Add(nodes.Count);
                        }
                    }

                    if (updateTime.Elapsed.TotalSeconds >= 60)
                    {
                        updateTime.Restart();

                        // PushBlocksLink
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            List<Key> targetList = null;

                            lock (_pushBlocksLinkDictionary.ThisLock)
                            {
                                if (_pushBlocksLinkDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushBlocksLinkDictionary.Remove(connectionManager.Node);
                                    messageManager.PushBlocksLink.AddRange(targetList);
                                }
                            }

                            if (targetList != null)
                            {
                                try
                                {
                                    connectionManager.PushBlocksLink(targetList);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push BlocksLink ({0})", targetList.Count));
                                    _pushBlockLinkCount.Add(targetList.Count);
                                }
                                catch (Exception e)
                                {
                                    foreach (var item in targetList)
                                    {
                                        messageManager.PushBlocksLink.Remove(item);
                                    }

                                    throw e;
                                }
                            }
                        }

                        // PushBlocksRequest
                        if (connectionCount >= _downloadingConnectionCountLowerLimit)
                        {
                            List<Key> targetList = null;

                            lock (_pushBlocksRequestDictionary.ThisLock)
                            {
                                if (_pushBlocksRequestDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushBlocksRequestDictionary.Remove(connectionManager.Node);
                                    messageManager.PushBlocksRequest.AddRange(targetList);
                                }
                            }

                            if (targetList != null)
                            {
                                try
                                {
                                    connectionManager.PushBlocksRequest(targetList);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push BlocksRequest ({0})", targetList.Count));
                                    _pushBlockRequestCount.Add(targetList.Count);
                                }
                                catch (Exception e)
                                {
                                    foreach (var item in targetList)
                                    {
                                        messageManager.PushBlocksRequest.Remove(item);
                                    }

                                    throw e;
                                }
                            }
                        }

                        // PushBroadcastMetadatasRequest
                        if (connectionCount >= _downloadingConnectionCountLowerLimit)
                        {
                            List<string> targetList = null;

                            lock (_pushBroadcastSignaturesRequestDictionary.ThisLock)
                            {
                                if (_pushBroadcastSignaturesRequestDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushBroadcastSignaturesRequestDictionary.Remove(connectionManager.Node);
                                    messageManager.PushBroadcastSignaturesRequest.AddRange(targetList);
                                }
                            }

                            if (targetList != null)
                            {
                                try
                                {
                                    connectionManager.PushBroadcastMetadatasRequest(targetList);

                                    foreach (var item in targetList)
                                    {
                                        _pushBroadcastSignaturesRequestList.Remove(item);
                                    }

                                    Debug.WriteLine(string.Format("ConnectionManager: Push BroadcastMetadatasRequest ({0})", targetList.Count));
                                    _pushMetadataRequestCount.Add(targetList.Count);
                                }
                                catch (Exception e)
                                {
                                    foreach (var item in targetList)
                                    {
                                        messageManager.PushBroadcastSignaturesRequest.Remove(item);
                                    }

                                    throw e;
                                }
                            }
                        }

                        // PushUnicastMetadatasRequest
                        if (connectionCount >= _downloadingConnectionCountLowerLimit)
                        {
                            List<string> targetList = null;

                            lock (_pushUnicastSignaturesRequestDictionary.ThisLock)
                            {
                                if (_pushUnicastSignaturesRequestDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushUnicastSignaturesRequestDictionary.Remove(connectionManager.Node);
                                    messageManager.PushUnicastSignaturesRequest.AddRange(targetList);
                                }
                            }

                            if (targetList != null)
                            {
                                try
                                {
                                    connectionManager.PushUnicastMetadatasRequest(targetList);

                                    foreach (var item in targetList)
                                    {
                                        _pushUnicastSignaturesRequestList.Remove(item);
                                    }

                                    Debug.WriteLine(string.Format("ConnectionManager: Push UnicastMetadatasRequest ({0})", targetList.Count));
                                    _pushMetadataRequestCount.Add(targetList.Count);
                                }
                                catch (Exception e)
                                {
                                    foreach (var item in targetList)
                                    {
                                        messageManager.PushUnicastSignaturesRequest.Remove(item);
                                    }

                                    throw e;
                                }
                            }
                        }

                        // PushMulticastMetadatasRequest
                        if (connectionCount >= _downloadingConnectionCountLowerLimit)
                        {
                            {
                                List<Wiki> wikiList = null;
                                List<Chat> chatList = null;

                                lock (_pushMulticastWikisRequestDictionary.ThisLock)
                                {
                                    if (_pushMulticastWikisRequestDictionary.TryGetValue(connectionManager.Node, out wikiList))
                                    {
                                        _pushMulticastWikisRequestDictionary.Remove(connectionManager.Node);
                                        messageManager.PushMulticastWikisRequest.AddRange(wikiList);
                                    }
                                }

                                lock (_pushMulticastChatsRequestDictionary.ThisLock)
                                {
                                    if (_pushMulticastChatsRequestDictionary.TryGetValue(connectionManager.Node, out chatList))
                                    {
                                        _pushMulticastChatsRequestDictionary.Remove(connectionManager.Node);
                                        messageManager.PushMulticastChatsRequest.AddRange(chatList);
                                    }
                                }

                                if (wikiList != null || chatList != null)
                                {
                                    try
                                    {
                                        connectionManager.PushMulticastMetadatasRequest(wikiList, chatList);

                                        int tagCount = 0;

                                        if (wikiList != null)
                                        {
                                            foreach (var item in wikiList)
                                            {
                                                _pushMulticastWikisRequestList.Remove(item);
                                            }

                                            tagCount += wikiList.Count;
                                        }

                                        if (chatList != null)
                                        {
                                            foreach (var item in chatList)
                                            {
                                                _pushMulticastChatsRequestList.Remove(item);
                                            }

                                            tagCount += chatList.Count;
                                        }

                                        Debug.WriteLine(string.Format("ConnectionManager: Push MulticastMetadatasRequest ({0})", tagCount));
                                        _pushMetadataRequestCount.Add(tagCount);
                                    }
                                    catch (Exception e)
                                    {
                                        if (wikiList != null)
                                        {
                                            foreach (var item in wikiList)
                                            {
                                                messageManager.PushMulticastWikisRequest.Remove(item);
                                            }
                                        }

                                        if (chatList != null)
                                        {
                                            foreach (var item in chatList)
                                            {
                                                messageManager.PushMulticastChatsRequest.Remove(item);
                                            }
                                        }

                                        throw e;
                                    }
                                }
                            }
                        }
                    }

                    if (blockDiffusionTime.Elapsed.TotalSeconds >= 5)
                    {
                        blockDiffusionTime.Restart();

                        // PushBlock
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            Key key = null;

                            lock (_diffusionBlocksDictionary.ThisLock)
                            {
                                Queue<Key> queue;

                                if (_diffusionBlocksDictionary.TryGetValue(connectionManager.Node, out queue))
                                {
                                    if (queue.Count > 0)
                                    {
                                        key = queue.Dequeue();
                                        messageManager.StockBlocks.Add(key);
                                    }
                                }
                            }

                            if (key != null)
                            {
                                ArraySegment<byte> buffer = new ArraySegment<byte>();

                                try
                                {
                                    buffer = _cacheManager[key];

                                    connectionManager.PushBlock(key, buffer);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push Block (Diffusion) ({0})", NetworkConverter.ToBase64UrlString(key.Hash)));
                                    _pushBlockCount.Increment();

                                    messageManager.PullBlocksRequest.Remove(key);
                                }
                                catch (ConnectionManagerException e)
                                {
                                    messageManager.StockBlocks.Remove(key);

                                    throw e;
                                }
                                catch (BlockNotFoundException)
                                {
                                    messageManager.StockBlocks.Remove(key);
                                }
                                finally
                                {
                                    if (buffer.Array != null)
                                    {
                                        _bufferManager.ReturnBuffer(buffer.Array);
                                    }
                                }

                                _settings.UploadBlocksRequest.Remove(key);
                                _settings.DiffusionBlocksRequest.Remove(key);
                            }
                        }
                    }

                    if (_random.NextDouble() < this.GetPriority(connectionManager.Node))
                    {
                        // PushBlock
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            Key key = null;

                            lock (_uploadBlocksDictionary.ThisLock)
                            {
                                Queue<Key> queue;

                                if (_uploadBlocksDictionary.TryGetValue(connectionManager.Node, out queue))
                                {
                                    if (queue.Count > 0)
                                    {
                                        key = queue.Dequeue();
                                        messageManager.StockBlocks.Add(key);
                                    }
                                }
                            }

                            if (key != null)
                            {
                                ArraySegment<byte> buffer = new ArraySegment<byte>();

                                try
                                {
                                    buffer = _cacheManager[key];

                                    connectionManager.PushBlock(key, buffer);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push Block (Upload) ({0})", NetworkConverter.ToBase64UrlString(key.Hash)));
                                    _pushBlockCount.Increment();

                                    messageManager.PullBlocksRequest.Remove(key);

                                    messageManager.Priority.Decrement();

                                    // Infomation
                                    {
                                        if (_relayBlocks.Contains(key))
                                        {
                                            _relayBlockCount.Increment();
                                        }
                                    }
                                }
                                catch (ConnectionManagerException e)
                                {
                                    messageManager.StockBlocks.Remove(key);

                                    throw e;
                                }
                                catch (BlockNotFoundException)
                                {
                                    messageManager.StockBlocks.Remove(key);
                                }
                                finally
                                {
                                    if (buffer.Array != null)
                                    {
                                        _bufferManager.ReturnBuffer(buffer.Array);
                                    }
                                }

                                _settings.UploadBlocksRequest.Remove(key);
                                _settings.DiffusionBlocksRequest.Remove(key);
                            }
                        }
                    }

                    if (metadataUpdateTime.Elapsed.TotalSeconds >= 60)
                    {
                        metadataUpdateTime.Restart();

                        // PushBroadcastMetadatas
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            {
                                var signatures = messageManager.PullBroadcastSignaturesRequest.ToArray();

                                var profileMetadatas = new List<ProfileMetadata>();

                                _random.Shuffle(signatures);
                                foreach (var signature in signatures)
                                {
                                    var metadata = _settings.MetadataManager.GetProfileMetadata(signature);
                                    if (metadata == null) continue;

                                    if (!messageManager.StockProfileMetadatas.Contains(metadata.CreateHash(_hashAlgorithm)))
                                    {
                                        profileMetadatas.Add(metadata);

                                        if (profileMetadatas.Count >= _maxMetadataCount) break;
                                    }

                                    if (profileMetadatas.Count >= _maxMetadataCount) break;
                                }

                                if (profileMetadatas.Count > 0)
                                {
                                    connectionManager.PushBroadcastMetadatas(
                                        profileMetadatas);

                                    var metadataCount =
                                        profileMetadatas.Count;

                                    Debug.WriteLine(string.Format("ConnectionManager: Push BroadcastMetadatas ({0})", metadataCount));
                                    _pushMetadataCount.Add(metadataCount);

                                    foreach (var metadata in profileMetadatas)
                                    {
                                        messageManager.StockProfileMetadatas.Add(metadata.CreateHash(_hashAlgorithm));
                                    }
                                }
                            }
                        }

                        // PushUnicastMetadatas
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            {
                                var signatures = messageManager.PullUnicastSignaturesRequest.ToArray();

                                var signatureMessageMetadatas = new List<SignatureMessageMetadata>();

                                _random.Shuffle(signatures);
                                foreach (var signature in signatures)
                                {
                                    foreach (var metadata in _settings.MetadataManager.GetSignatureMessageMetadatas(signature))
                                    {
                                        if (!messageManager.StockSignatureMessageMetadatas.Contains(metadata.CreateHash(_hashAlgorithm)))
                                        {
                                            signatureMessageMetadatas.Add(metadata);

                                            if (signatureMessageMetadatas.Count >= _maxMetadataCount) break;
                                        }
                                    }

                                    if (signatureMessageMetadatas.Count >= _maxMetadataCount) break;
                                }

                                if (signatureMessageMetadatas.Count > 0)
                                {
                                    connectionManager.PushUnicastMetadatas(
                                        signatureMessageMetadatas);

                                    var metadataCount =
                                        signatureMessageMetadatas.Count;

                                    Debug.WriteLine(string.Format("ConnectionManager: Push UnicastMetadatas ({0})", metadataCount));
                                    _pushMetadataCount.Add(metadataCount);

                                    foreach (var metadata in signatureMessageMetadatas)
                                    {
                                        messageManager.StockSignatureMessageMetadatas.Add(metadata.CreateHash(_hashAlgorithm));
                                    }
                                }
                            }
                        }

                        // PushMulticastMetadatas
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            {
                                var wikis = messageManager.PullMulticastWikisRequest.ToArray();
                                var chats = messageManager.PullMulticastChatsRequest.ToArray();

                                var wikiDocumentMetadatas = new List<WikiDocumentMetadata>();
                                var chatMessageMetadatas = new List<ChatMessageMetadata>();

                                _random.Shuffle(wikis);
                                foreach (var tag in wikis)
                                {
                                    foreach (var metadata in _settings.MetadataManager.GetWikiDocumentMetadatas(tag))
                                    {
                                        if (!messageManager.StockWikiDocumentMetadatas.Contains(metadata.CreateHash(_hashAlgorithm)))
                                        {
                                            wikiDocumentMetadatas.Add(metadata);

                                            if (wikiDocumentMetadatas.Count >= _maxMetadataCount) break;
                                        }
                                    }

                                    if (wikiDocumentMetadatas.Count >= _maxMetadataCount) break;
                                }

                                _random.Shuffle(chats);
                                foreach (var tag in chats)
                                {
                                    foreach (var metadata in _settings.MetadataManager.GetChatMessageMetadatas(tag))
                                    {
                                        if (!messageManager.StockChatMessageMetadatas.Contains(metadata.CreateHash(_hashAlgorithm)))
                                        {
                                            chatMessageMetadatas.Add(metadata);

                                            if (chatMessageMetadatas.Count >= _maxMetadataCount) break;
                                        }
                                    }

                                    if (chatMessageMetadatas.Count >= _maxMetadataCount) break;
                                }

                                if (wikiDocumentMetadatas.Count > 0
                                    || chatMessageMetadatas.Count > 0)
                                {
                                    connectionManager.PushMulticastMetadatas(
                                        wikiDocumentMetadatas,
                                        chatMessageMetadatas);

                                    var metadataCount =
                                        wikiDocumentMetadatas.Count
                                        + chatMessageMetadatas.Count;

                                    Debug.WriteLine(string.Format("ConnectionManager: Push MulticastMetadatas ({0})", metadataCount));
                                    _pushMetadataCount.Add(metadataCount);

                                    foreach (var metadata in wikiDocumentMetadatas)
                                    {
                                        messageManager.StockWikiDocumentMetadatas.Add(metadata.CreateHash(_hashAlgorithm));
                                    }

                                    foreach (var metadata in chatMessageMetadatas)
                                    {
                                        messageManager.StockChatMessageMetadatas.Add(metadata.CreateHash(_hashAlgorithm));
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
            }
            finally
            {
                this.RemoveConnectionManager(connectionManager);
            }
        }
        private void ConnectionsManagerThread()
        {
            var refreshStopwatch = new Stopwatch();
            bool refreshThreadRunning = false;

            var pushBlockDiffusionStopwatch = new Stopwatch();
            pushBlockDiffusionStopwatch.Start();
            var pushBlockUploadStopwatch = new Stopwatch();
            pushBlockUploadStopwatch.Start();
            var pushBlockDownloadStopwatch = new Stopwatch();
            pushBlockDownloadStopwatch.Start();

            var pushMetadataUploadStopwatch = new Stopwatch();
            pushMetadataUploadStopwatch.Start();
            var pushMetadataDownloadStopwatch = new Stopwatch();
            pushMetadataDownloadStopwatch.Start();

            var requestCounts = new VolatileHashDictionary<Key, int>(new TimeSpan(0, 10, 0));

            for (;;)
            {
                Thread.Sleep(1000);
                if (this.State == ManagerState.Stop) return;

                var connectionCount = 0;

                lock (_thisLock)
                {
                    connectionCount = _connectionManagers.Count;
                }

                if (!refreshStopwatch.IsRunning || refreshStopwatch.Elapsed.TotalSeconds >= 60)
                {
                    refreshStopwatch.Restart();

                    // トラストにより必要なMetadataを選択し、不要なMetadataを削除する。
                    Task.Run(() =>
                    {
                        if (refreshThreadRunning) return;
                        refreshThreadRunning = true;

                        try
                        {
                            var lockSignatures = this.OnLockSignaturesEvent();
                            if (lockSignatures == null) return;

                            var lockTags = this.OnLockTagsEvent();
                            if (lockTags == null) return;

                            _settings.MetadataManager.Refresh(lockSignatures.ToArray(), lockTags.ToArray());
                        }
                        catch (Exception e)
                        {
                            Log.Error(e);
                        }
                        finally
                        {
                            refreshThreadRunning = false;
                        }
                    });
                }

                // 拡散アップロード
                if (connectionCount > _diffusionConnectionCountLowerLimit
                    && pushBlockDiffusionStopwatch.Elapsed.TotalSeconds >= 60)
                {
                    pushBlockDiffusionStopwatch.Restart();

                    // 拡散アップロードするブロック数を10000以下に抑える。
                    lock (_thisLock)
                    {
                        lock (_settings.DiffusionBlocksRequest.ThisLock)
                        {
                            if (_settings.DiffusionBlocksRequest.Count > 10000)
                            {
                                foreach (var key in _settings.DiffusionBlocksRequest.Randomize()
                                    .Take(_settings.DiffusionBlocksRequest.Count - 10000))
                                {
                                    _settings.DiffusionBlocksRequest.Remove(key);
                                }
                            }
                        }
                    }

                    // 存在しないブロックのKeyをRemoveする。
                    lock (_thisLock)
                    {
                        lock (_settings.DiffusionBlocksRequest.ThisLock)
                        {
                            foreach (var key in _cacheManager.ExceptFrom(_settings.DiffusionBlocksRequest.ToArray()).ToArray())
                            {
                                _settings.DiffusionBlocksRequest.Remove(key);
                            }
                        }

                        lock (_settings.UploadBlocksRequest.ThisLock)
                        {
                            foreach (var key in _cacheManager.ExceptFrom(_settings.UploadBlocksRequest.ToArray()).ToArray())
                            {
                                _settings.UploadBlocksRequest.Remove(key);
                            }
                        }
                    }

                    var baseNode = this.BaseNode;

                    var otherNodes = new List<Node>();

                    lock (_thisLock)
                    {
                        otherNodes.AddRange(_connectionManagers.Select(n => n.Node));
                    }

                    var packetManagers = new Dictionary<Node, PacketManager>();

                    foreach (var node in otherNodes)
                    {
                        packetManagers[node] = _packetControlManager[node];
                    }

                    var diffusionBlocksList = new HashSet<Key>();

                    {
                        {
                            var array = _settings.UploadBlocksRequest.ToArray();
                            _random.Shuffle(array);

                            int count = 1024;

                            for (int i = 0; i < count && i < array.Length; i++)
                            {
                                diffusionBlocksList.Add(array[i]);
                            }
                        }

                        {
                            var array = _settings.DiffusionBlocksRequest.ToArray();
                            _random.Shuffle(array);

                            int count = 1024;

                            for (int i = 0; i < count && i < array.Length; i++)
                            {
                                diffusionBlocksList.Add(array[i]);
                            }
                        }
                    }

                    {
                        var diffusionBlocksDictionary = new Dictionary<Node, List<Key>>();

                        foreach (var key in diffusionBlocksList.Randomize())
                        {
                            try
                            {
                                var requestNodes = new List<Node>();

                                foreach (var node in Kademlia<Node>.Search(key.Hash, baseNode.Id, otherNodes, 2))
                                {
                                    requestNodes.Add(node);
                                }

                                if (requestNodes.Count == 0)
                                {
                                    _blockUploadedEventQueue.Enqueue(key);

                                    _settings.UploadBlocksRequest.Remove(key);
                                    _settings.DiffusionBlocksRequest.Remove(key);

                                    continue;
                                }

                                for (int i = 0; i < requestNodes.Count; i++)
                                {
                                    List<Key> collection;

                                    if (!diffusionBlocksDictionary.TryGetValue(requestNodes[i], out collection))
                                    {
                                        collection = new List<Key>();
                                        diffusionBlocksDictionary[requestNodes[i]] = collection;
                                    }

                                    collection.Add(key);
                                }
                            }
                            catch (Exception e)
                            {
                                Log.Error(e);
                            }
                        }

                        lock (_diffusionBlocksDictionary.ThisLock)
                        {
                            _diffusionBlocksDictionary.Clear();

                            foreach (var pair in diffusionBlocksDictionary)
                            {
                                var node = pair.Key;
                                var targets = pair.Value;

                                _random.Shuffle(targets);

                                _diffusionBlocksDictionary.Add(node, new Queue<Key>(targets));
                            }
                        }
                    }
                }

                // アップロード
                if (connectionCount >= _uploadingConnectionCountLowerLimit
                    && pushBlockUploadStopwatch.Elapsed.TotalSeconds >= 60)
                {
                    pushBlockUploadStopwatch.Restart();

                    var baseNode = this.BaseNode;

                    var otherNodes = new List<Node>();

                    lock (_thisLock)
                    {
                        otherNodes.AddRange(_connectionManagers.Select(n => n.Node));
                    }

                    var packetManagers = new Dictionary<Node, PacketManager>();

                    foreach (var node in otherNodes)
                    {
                        packetManagers[node] = _packetControlManager[node];
                    }

                    {
                        var uploadBlocksDictionary = new Dictionary<Node, List<Key>>();

                        foreach (var pair in packetManagers)
                        {
                            var node = pair.Key;
                            var packetManager = pair.Value;

                            uploadBlocksDictionary.Add(node, _cacheManager.IntersectFrom(packetManager.PullBlocksRequest.ToArray().Randomize()).Take(1024).ToList());
                        }

                        lock (_uploadBlocksDictionary.ThisLock)
                        {
                            _uploadBlocksDictionary.Clear();

                            foreach (var pair in uploadBlocksDictionary)
                            {
                                var node = pair.Key;
                                var targets = pair.Value;

                                _uploadBlocksDictionary.Add(node, new Queue<Key>(targets));
                            }
                        }
                    }
                }

                // ダウンロード
                if (connectionCount >= _downloadingConnectionCountLowerLimit
                    && pushBlockDownloadStopwatch.Elapsed.TotalSeconds >= 60)
                {
                    pushBlockDownloadStopwatch.Restart();

                    var baseNode = this.BaseNode;

                    var otherNodes = new List<Node>();

                    lock (_thisLock)
                    {
                        otherNodes.AddRange(_connectionManagers.Select(n => n.Node));
                    }

                    var packetManagers = new Dictionary<Node, PacketManager>();

                    foreach (var node in otherNodes)
                    {
                        packetManagers[node] = _packetControlManager[node];
                    }

                    var pushBlocksLinkList = new HashSet<Key>();
                    var pushBlocksRequestList = new HashSet<Key>();

                    {
                        {
                            var array = _cacheManager.ToArray();
                            _random.Shuffle(array);

                            int count = _maxBlockLinkCount;

                            pushBlocksLinkList.UnionWith(array.Take(count));
                        }

                        foreach (var pair in packetManagers)
                        {
                            var node = pair.Key;
                            var packetManager = pair.Value;

                            {
                                var array = packetManager.PullBlocksLink.ToArray(new TimeSpan(0, 10, 0));
                                _random.Shuffle(array);

                                var count = (int)((_maxBlockLinkCount * ((double)12 / otherNodes.Count)) * this.GetPriority(node));

                                pushBlocksLinkList.UnionWith(array.Take(count));
                            }
                        }

                        {
                            var array = _cacheManager.ExceptFrom(_downloadBlocks.ToArray()).ToArray();
                            _random.Shuffle(array);

                            int count = _maxBlockRequestCount;

                            pushBlocksRequestList.UnionWith(array.Take(count));
                        }

                        foreach (var pair in packetManagers)
                        {
                            var node = pair.Key;
                            var packetManager = pair.Value;

                            {
                                var array = _cacheManager.ExceptFrom(packetManager.PullBlocksRequest.ToArray(new TimeSpan(0, 10, 0))).ToArray();
                                _random.Shuffle(array);

                                var count = (int)((_maxBlockRequestCount * ((double)12 / otherNodes.Count)) * this.GetPriority(node));

                                pushBlocksRequestList.UnionWith(array.Take(count));
                            }
                        }
                    }

                    {
                        var pushBlocksLinkDictionary = new Dictionary<Node, List<Key>>();

                        foreach (var key in pushBlocksLinkList.Randomize())
                        {
                            try
                            {
                                var requestNodes = new List<Node>();

                                foreach (var node in Kademlia<Node>.Search(key.Hash, otherNodes, 2))
                                {
                                    requestNodes.Add(node);
                                }

                                for (int i = 0; i < requestNodes.Count; i++)
                                {
                                    List<Key> collection;

                                    if (!pushBlocksLinkDictionary.TryGetValue(requestNodes[i], out collection))
                                    {
                                        collection = new List<Key>();
                                        pushBlocksLinkDictionary[requestNodes[i]] = collection;
                                    }

                                    if (collection.Count < _maxBlockLinkCount)
                                    {
                                        collection.Add(key);
                                    }
                                }
                            }
                            catch (Exception e)
                            {
                                Log.Error(e);
                            }
                        }

                        lock (_pushBlocksLinkDictionary.ThisLock)
                        {
                            _pushBlocksLinkDictionary.Clear();

                            foreach (var pair in pushBlocksLinkDictionary)
                            {
                                var node = pair.Key;
                                var targets = pair.Value;

                                _random.Shuffle(targets);

                                _pushBlocksLinkDictionary.Add(node, targets);
                            }
                        }
                    }

                    {
                        requestCounts.Update();

                        var pushBlocksRequestDictionary = new Dictionary<Node, List<Key>>();

                        foreach (var key in pushBlocksRequestList.Randomize())
                        {
                            int count;
                            {
                                int value;
                                requestCounts.TryGetValue(key, out value);

                                if (value < 6) requestCounts[key] = (value += 2);

                                count = value;
                            }

                            try
                            {
                                var requestNodes = new List<Node>();

                                foreach (var node in Kademlia<Node>.Search(key.Hash, otherNodes, count))
                                {
                                    requestNodes.Add(node);
                                }

                                foreach (var pair in packetManagers)
                                {
                                    var node = pair.Key;
                                    var packetManager = pair.Value;

                                    if (packetManager.PullBlocksLink.Contains(key))
                                    {
                                        requestNodes.Add(node);
                                    }
                                }

                                for (int i = 0; i < requestNodes.Count; i++)
                                {
                                    List<Key> collection;

                                    if (!pushBlocksRequestDictionary.TryGetValue(requestNodes[i], out collection))
                                    {
                                        collection = new List<Key>();
                                        pushBlocksRequestDictionary[requestNodes[i]] = collection;
                                    }

                                    if (collection.Count < _maxBlockRequestCount)
                                    {
                                        collection.Add(key);
                                    }
                                }
                            }
                            catch (Exception e)
                            {
                                Log.Error(e);
                            }
                        }

                        lock (_pushBlocksRequestDictionary.ThisLock)
                        {
                            _pushBlocksRequestDictionary.Clear();

                            foreach (var pair in pushBlocksRequestDictionary)
                            {
                                var node = pair.Key;
                                var targets = pair.Value;

                                _random.Shuffle(targets);

                                _pushBlocksRequestDictionary.Add(node, targets);
                            }
                        }
                    }
                }

                // Metadataのアップロード
                if (connectionCount >= _uploadingConnectionCountLowerLimit
                    && pushMetadataUploadStopwatch.Elapsed.TotalMinutes >= 3)
                {
                    pushMetadataUploadStopwatch.Restart();

                    var baseNode = this.BaseNode;

                    var otherNodes = new List<Node>();

                    lock (_thisLock)
                    {
                        otherNodes.AddRange(_connectionManagers.Select(n => n.Node));
                    }

                    var packetManagers = new Dictionary<Node, PacketManager>();

                    foreach (var node in otherNodes)
                    {
                        packetManagers[node] = _packetControlManager[node];
                    }

                    // Broadcast
                    foreach (var signature in _settings.MetadataManager.GetBroadcastSignatures())
                    {
                        try
                        {
                            var requestNodes = new List<Node>();

                            foreach (var node in Kademlia<Node>.Search(Signature.GetHash(signature), otherNodes, 2))
                            {
                                requestNodes.Add(node);
                            }

                            for (int i = 0; i < requestNodes.Count; i++)
                            {
                                packetManagers[requestNodes[i]].PullBroadcastMetadatasRequest.Add(signature);
                            }
                        }
                        catch (Exception e)
                        {
                            Log.Error(e);
                        }
                    }

                    // Unicast
                    foreach (var signature in _settings.MetadataManager.GetUnicastSignatures())
                    {
                        try
                        {
                            var requestNodes = new List<Node>();

                            foreach (var node in Kademlia<Node>.Search(Signature.GetHash(signature), otherNodes, 2))
                            {
                                requestNodes.Add(node);
                            }

                            for (int i = 0; i < requestNodes.Count; i++)
                            {
                                packetManagers[requestNodes[i]].PullUnicastMetadatasRequest.Add(signature);
                            }
                        }
                        catch (Exception e)
                        {
                            Log.Error(e);
                        }
                    }

                    // Multicast
                    {
                        foreach (var tag in _settings.MetadataManager.GetMulticastTags())
                        {
                            try
                            {
                                var requestNodes = new List<Node>();

                                foreach (var node in Kademlia<Node>.Search(tag.Id, otherNodes, 2))
                                {
                                    requestNodes.Add(node);
                                }

                                for (int i = 0; i < requestNodes.Count; i++)
                                {
                                    packetManagers[requestNodes[i]].PullMulticastMetadatasRequest.Add(tag);
                                }
                            }
                            catch (Exception e)
                            {
                                Log.Error(e);
                            }
                        }
                    }
                }

                // Metadataのダウンロード
                if (connectionCount >= _downloadingConnectionCountLowerLimit
                    && pushMetadataDownloadStopwatch.Elapsed.TotalSeconds >= 60)
                {
                    pushMetadataDownloadStopwatch.Restart();

                    var baseNode = this.BaseNode;

                    var otherNodes = new List<Node>();

                    lock (_thisLock)
                    {
                        otherNodes.AddRange(_connectionManagers.Select(n => n.Node));
                    }

                    var packetManagers = new Dictionary<Node, PacketManager>();

                    foreach (var node in otherNodes)
                    {
                        packetManagers[node] = _packetControlManager[node];
                    }

                    var pushBroadcastMetadatasRequestList = new HashSet<string>();
                    var pushUnicastMetadatasRequestList = new HashSet<string>();
                    var pushMulticastMetadatasRequestList = new HashSet<Tag>();

                    {
                        // Broadcast
                        {
                            {
                                var array = _pushBroadcastMetadatasRequestList.ToArray();
                                _random.Shuffle(array);

                                int count = _maxMetadataRequestCount;

                                for (int i = 0; count > 0 && i < array.Length; i++)
                                {
                                    pushBroadcastMetadatasRequestList.Add(array[i]);

                                    count--;
                                }
                            }

                            foreach (var pair in packetManagers)
                            {
                                var node = pair.Key;
                                var packetManager = pair.Value;

                                {
                                    var array = packetManager.PullBroadcastMetadatasRequest.ToArray(new TimeSpan(0, 10, 0));
                                    _random.Shuffle(array);

                                    int count = _maxMetadataRequestCount;

                                    for (int i = 0; count > 0 && i < array.Length; i++)
                                    {
                                        pushBroadcastMetadatasRequestList.Add(array[i]);

                                        count--;
                                    }
                                }
                            }
                        }

                        // Unicast
                        {
                            {
                                var array = _pushUnicastMetadatasRequestList.ToArray();
                                _random.Shuffle(array);

                                int count = _maxMetadataRequestCount;

                                for (int i = 0; count > 0 && i < array.Length; i++)
                                {
                                    pushUnicastMetadatasRequestList.Add(array[i]);

                                    count--;
                                }
                            }

                            foreach (var pair in packetManagers)
                            {
                                var node = pair.Key;
                                var packetManager = pair.Value;

                                {
                                    var array = packetManager.PullUnicastMetadatasRequest.ToArray(new TimeSpan(0, 10, 0));
                                    _random.Shuffle(array);

                                    int count = _maxMetadataRequestCount;

                                    for (int i = 0; count > 0 && i < array.Length; i++)
                                    {
                                        pushUnicastMetadatasRequestList.Add(array[i]);

                                        count--;
                                    }
                                }
                            }
                        }

                        // Multicast
                        {
                            {
                                var array = _pushMulticastMetadatasRequestList.ToArray();
                                _random.Shuffle(array);

                                int count = _maxMetadataRequestCount;

                                for (int i = 0; count > 0 && i < array.Length; i++)
                                {
                                    pushMulticastMetadatasRequestList.Add(array[i]);

                                    count--;
                                }
                            }

                            foreach (var pair in packetManagers)
                            {
                                var node = pair.Key;
                                var packetManager = pair.Value;

                                {
                                    var array = packetManager.PullMulticastMetadatasRequest.ToArray(new TimeSpan(0, 10, 0));
                                    _random.Shuffle(array);

                                    int count = _maxMetadataRequestCount;

                                    for (int i = 0; count > 0 && i < array.Length; i++)
                                    {
                                        pushMulticastMetadatasRequestList.Add(array[i]);

                                        count--;
                                    }
                                }
                            }
                        }
                    }

                    {
                        // Broadcast
                        {
                            var pushBroadcastMetadatasRequestDictionary = new Dictionary<Node, List<string>>();

                            foreach (var signature in pushBroadcastMetadatasRequestList.Randomize())
                            {
                                try
                                {
                                    var requestNodes = new List<Node>();

                                    foreach (var node in Kademlia<Node>.Search(Signature.GetHash(signature), otherNodes, 2))
                                    {
                                        requestNodes.Add(node);
                                    }

                                    for (int i = 0; i < requestNodes.Count; i++)
                                    {
                                        List<string> collection;

                                        if (!pushBroadcastMetadatasRequestDictionary.TryGetValue(requestNodes[i], out collection))
                                        {
                                            collection = new List<string>();
                                            pushBroadcastMetadatasRequestDictionary[requestNodes[i]] = collection;
                                        }

                                        if (collection.Count < _maxMetadataRequestCount)
                                        {
                                            collection.Add(signature);
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    Log.Error(e);
                                }
                            }

                            lock (_pushBroadcastMetadatasRequestDictionary.ThisLock)
                            {
                                _pushBroadcastMetadatasRequestDictionary.Clear();

                                foreach (var pair in pushBroadcastMetadatasRequestDictionary)
                                {
                                    var node = pair.Key;
                                    var targets = pair.Value;

                                    _random.Shuffle(targets);

                                    _pushBroadcastMetadatasRequestDictionary.Add(node, targets);
                                }
                            }
                        }

                        // Unicast
                        {
                            var pushUnicastMetadatasRequestDictionary = new Dictionary<Node, List<string>>();

                            foreach (var signature in pushUnicastMetadatasRequestList.Randomize())
                            {
                                try
                                {
                                    var requestNodes = new List<Node>();

                                    foreach (var node in Kademlia<Node>.Search(Signature.GetHash(signature), otherNodes, 2))
                                    {
                                        requestNodes.Add(node);
                                    }

                                    for (int i = 0; i < requestNodes.Count; i++)
                                    {
                                        List<string> collection;

                                        if (!pushUnicastMetadatasRequestDictionary.TryGetValue(requestNodes[i], out collection))
                                        {
                                            collection = new List<string>();
                                            pushUnicastMetadatasRequestDictionary[requestNodes[i]] = collection;
                                        }

                                        if (collection.Count < _maxMetadataRequestCount)
                                        {
                                            collection.Add(signature);
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    Log.Error(e);
                                }
                            }

                            lock (_pushUnicastMetadatasRequestDictionary.ThisLock)
                            {
                                _pushUnicastMetadatasRequestDictionary.Clear();

                                foreach (var pair in pushUnicastMetadatasRequestDictionary)
                                {
                                    var node = pair.Key;
                                    var targets = pair.Value;

                                    _random.Shuffle(targets);

                                    _pushUnicastMetadatasRequestDictionary.Add(node, targets);
                                }
                            }
                        }

                        // Multicast
                        {
                            var pushMulticastMetadatasRequestDictionary = new Dictionary<Node, List<Tag>>();

                            foreach (var tag in pushMulticastMetadatasRequestList.Randomize())
                            {
                                try
                                {
                                    var requestNodes = new List<Node>();

                                    foreach (var node in Kademlia<Node>.Search(tag.Id, otherNodes, 2))
                                    {
                                        requestNodes.Add(node);
                                    }

                                    for (int i = 0; i < requestNodes.Count; i++)
                                    {
                                        List<Tag> collection;

                                        if (!pushMulticastMetadatasRequestDictionary.TryGetValue(requestNodes[i], out collection))
                                        {
                                            collection = new List<Tag>();
                                            pushMulticastMetadatasRequestDictionary[requestNodes[i]] = collection;
                                        }

                                        if (collection.Count < _maxMetadataRequestCount)
                                        {
                                            collection.Add(tag);
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    Log.Error(e);
                                }
                            }

                            lock (_pushMulticastMetadatasRequestDictionary.ThisLock)
                            {
                                _pushMulticastMetadatasRequestDictionary.Clear();

                                foreach (var pair in pushMulticastMetadatasRequestDictionary)
                                {
                                    var node = pair.Key;
                                    var targets = pair.Value;

                                    _random.Shuffle(targets);

                                    _pushMulticastMetadatasRequestDictionary.Add(node, targets);
                                }
                            }
                        }
                    }
                }
            }
        }
        private void ConnectionManagerThread(object state)
        {
            Thread.CurrentThread.Name = "ConnectionsManager_ConnectionManagerThread";
            Thread.CurrentThread.Priority = ThreadPriority.Lowest;

            var connectionManager = state as ConnectionManager;
            if (connectionManager == null) return;

            try
            {
                var messageManager = _messagesManager[connectionManager.Node];

                Stopwatch checkTime = new Stopwatch();
                checkTime.Start();
                Stopwatch nodeUpdateTime = new Stopwatch();
                Stopwatch updateTime = new Stopwatch();
                updateTime.Start();
                Stopwatch blockDiffusionTime = new Stopwatch();
                blockDiffusionTime.Start();
                Stopwatch seedUpdateTime = new Stopwatch();
                seedUpdateTime.Start();

                for (; ; )
                {
                    Thread.Sleep(1000);
                    if (this.State == ManagerState.Stop) return;
                    if (!_connectionManagers.Contains(connectionManager)) return;

                    var connectionCount = 0;

                    lock (this.ThisLock)
                    {
                        connectionCount = _connectionManagers.Count;
                    }

                    // Check
                    if (messageManager.Priority < 0 && checkTime.Elapsed.TotalSeconds >= 5)
                    {
                        checkTime.Restart();

                        if ((DateTime.UtcNow - messageManager.LastPullTime).TotalMinutes >= 5)
                        {
                            lock (this.ThisLock)
                            {
                                this.RemoveNode(connectionManager.Node);
                            }

                            connectionManager.PushCancel();

                            Debug.WriteLine("ConnectionManager: Push Cancel");
                            return;
                        }
                    }

                    // PushNodes
                    if (!nodeUpdateTime.IsRunning || nodeUpdateTime.Elapsed.TotalMinutes >= 3)
                    {
                        nodeUpdateTime.Restart();

                        var nodes = new HashSet<Node>();

                        lock (this.ThisLock)
                        {
                            foreach (var node in _routeTable.Randomize())
                            {
                                if (nodes.Count >= 64) break;

                                if (node.Uris.Any(n => _succeededUris.Contains(n)))
                                {
                                    nodes.Add(node);
                                }
                            }

                            foreach (var node in _routeTable.Randomize())
                            {
                                if (nodes.Count >= 128) break;

                                nodes.Add(node);
                            }
                        }

                        if (nodes.Count > 0)
                        {
                            connectionManager.PushNodes(nodes.Randomize());

                            Debug.WriteLine(string.Format("ConnectionManager: Push Nodes ({0})", nodes.Count));
                            _pushNodeCount.Add(nodes.Count);
                        }
                    }

                    if (updateTime.Elapsed.TotalSeconds >= 30)
                    {
                        updateTime.Restart();

                        // PushBlocksLink
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            List<Key> targetList = null;

                            lock (_pushBlocksLinkDictionary.ThisLock)
                            {
                                if (_pushBlocksLinkDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushBlocksLinkDictionary.Remove(connectionManager.Node);
                                    messageManager.PushBlocksLink.AddRange(targetList);
                                }
                            }

                            if (targetList != null)
                            {
                                try
                                {
                                    connectionManager.PushBlocksLink(targetList);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push BlocksLink ({0})", targetList.Count));
                                    _pushBlockLinkCount.Add(targetList.Count);
                                }
                                catch (Exception e)
                                {
                                    foreach (var item in targetList)
                                    {
                                        messageManager.PushBlocksLink.Remove(item);
                                    }

                                    throw e;
                                }
                            }
                        }

                        // PushBlocksRequest
                        if (connectionCount >= _downloadingConnectionCountLowerLimit)
                        {
                            List<Key> targetList = null;

                            lock (_pushBlocksRequestDictionary.ThisLock)
                            {
                                if (_pushBlocksRequestDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushBlocksRequestDictionary.Remove(connectionManager.Node);
                                    messageManager.PushBlocksRequest.AddRange(targetList);
                                }
                            }

                            if (targetList != null)
                            {
                                try
                                {
                                    connectionManager.PushBlocksRequest(targetList);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push BlocksRequest ({0})", targetList.Count));
                                    _pushBlockRequestCount.Add(targetList.Count);
                                }
                                catch (Exception e)
                                {
                                    foreach (var item in targetList)
                                    {
                                        messageManager.PushBlocksRequest.Remove(item);
                                    }

                                    throw e;
                                }
                            }
                        }

                        // PushSeedsRequest
                        if (connectionCount >= _downloadingConnectionCountLowerLimit)
                        {
                            List<string> targetList = null;

                            lock (_pushSeedsRequestDictionary.ThisLock)
                            {
                                if (_pushSeedsRequestDictionary.TryGetValue(connectionManager.Node, out targetList))
                                {
                                    _pushSeedsRequestDictionary.Remove(connectionManager.Node);
                                    messageManager.PushSeedsRequest.AddRange(targetList);
                                }
                            }

                            if (targetList != null)
                            {
                                try
                                {
                                    connectionManager.PushSeedsRequest(targetList);

                                    foreach (var item in targetList)
                                    {
                                        _pushSeedsRequestList.Remove(item);
                                    }

                                    Debug.WriteLine(string.Format("ConnectionManager: Push SeedsRequest ({0})", targetList.Count));
                                    _pushSeedRequestCount.Add(targetList.Count);
                                }
                                catch (Exception e)
                                {
                                    foreach (var item in targetList)
                                    {
                                        messageManager.PushSeedsRequest.Remove(item);
                                    }

                                    throw e;
                                }
                            }
                        }
                    }

                    if (blockDiffusionTime.Elapsed.TotalSeconds >= connectionCount)
                    {
                        blockDiffusionTime.Restart();

                        // PushBlock
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            Key key = null;

                            lock (_diffusionBlocksDictionary.ThisLock)
                            {
                                Queue<Key> queue;

                                if (_diffusionBlocksDictionary.TryGetValue(connectionManager.Node, out queue))
                                {
                                    if (queue.Count > 0)
                                    {
                                        key = queue.Dequeue();
                                        messageManager.StockBlocks.Add(key);
                                    }
                                }
                            }

                            if (key != null)
                            {
                                ArraySegment<byte> buffer = new ArraySegment<byte>();

                                try
                                {
                                    buffer = _cacheManager[key];

                                    connectionManager.PushBlock(key, buffer);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push Block (Diffusion) ({0})", NetworkConverter.ToBase64UrlString(key.Hash)));
                                    _pushBlockCount.Increment();

                                    messageManager.PullBlocksRequest.Remove(key);
                                }
                                catch (ConnectionManagerException e)
                                {
                                    messageManager.StockBlocks.Remove(key);

                                    throw e;
                                }
                                catch (BlockNotFoundException)
                                {
                                    messageManager.StockBlocks.Remove(key);
                                }
                                finally
                                {
                                    if (buffer.Array != null)
                                    {
                                        _bufferManager.ReturnBuffer(buffer.Array);
                                    }
                                }

                                _settings.UploadBlocksRequest.Remove(key);
                                _settings.DiffusionBlocksRequest.Remove(key);

                                this.OnUploadedEvent(new Key[] { key });
                            }
                        }
                    }

                    if (_random.NextDouble() < this.GetPriority(connectionManager.Node))
                    {
                        // PushBlock
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            Key key = null;

                            lock (_uploadBlocksDictionary.ThisLock)
                            {
                                Queue<Key> queue;

                                if (_uploadBlocksDictionary.TryGetValue(connectionManager.Node, out queue))
                                {
                                    if (queue.Count > 0)
                                    {
                                        key = queue.Dequeue();
                                        messageManager.StockBlocks.Add(key);
                                    }
                                }
                            }

                            if (key != null)
                            {
                                ArraySegment<byte> buffer = new ArraySegment<byte>();

                                try
                                {
                                    buffer = _cacheManager[key];

                                    connectionManager.PushBlock(key, buffer);

                                    Debug.WriteLine(string.Format("ConnectionManager: Push Block (Upload) ({0})", NetworkConverter.ToBase64UrlString(key.Hash)));
                                    _pushBlockCount.Increment();

                                    messageManager.PullBlocksRequest.Remove(key);

                                    messageManager.Priority.Decrement();

                                    // Infomation
                                    {
                                        if (_relayBlocks.Contains(key))
                                        {
                                            _relayBlockCount.Increment();
                                        }
                                    }
                                }
                                catch (ConnectionManagerException e)
                                {
                                    messageManager.StockBlocks.Remove(key);

                                    throw e;
                                }
                                catch (BlockNotFoundException)
                                {
                                    messageManager.StockBlocks.Remove(key);
                                }
                                finally
                                {
                                    if (buffer.Array != null)
                                    {
                                        _bufferManager.ReturnBuffer(buffer.Array);
                                    }
                                }

                                _settings.UploadBlocksRequest.Remove(key);
                                _settings.DiffusionBlocksRequest.Remove(key);

                                this.OnUploadedEvent(new Key[] { key });
                            }
                        }
                    }

                    if (seedUpdateTime.Elapsed.TotalSeconds >= 30)
                    {
                        seedUpdateTime.Restart();

                        // PushSeeds
                        if (connectionCount >= _uploadingConnectionCountLowerLimit)
                        {
                            var signatures = messageManager.PullSeedsRequest.ToArray();

                            var linkSeeds = new List<Seed>();

                            // Link
                            _random.Shuffle(signatures);
                            foreach (var signature in signatures)
                            {
                                Seed tempSeed = _settings.GetLinkSeed(signature);
                                if (tempSeed == null) continue;

                                DateTime creationTime;

                                if (!messageManager.StockLinkSeeds.TryGetValue(signature, out creationTime)
                                    || tempSeed.CreationTime > creationTime)
                                {
                                    linkSeeds.Add(tempSeed);

                                    if (linkSeeds.Count >= (_maxSeedCount / 2)) break;
                                }
                            }

                            var storeSeeds = new List<Seed>();

                            // Store
                            _random.Shuffle(signatures);
                            foreach (var signature in signatures)
                            {
                                Seed tempSeed = _settings.GetStoreSeed(signature);
                                if (tempSeed == null) continue;

                                DateTime creationTime;

                                if (!messageManager.StockStoreSeeds.TryGetValue(signature, out creationTime)
                                    || tempSeed.CreationTime > creationTime)
                                {
                                    storeSeeds.Add(tempSeed);

                                    if (storeSeeds.Count >= (_maxSeedCount / 2)) break;
                                }
                            }

                            if (linkSeeds.Count > 0 || storeSeeds.Count > 0)
                            {
                                var seeds = new List<Seed>();
                                seeds.AddRange(linkSeeds);
                                seeds.AddRange(storeSeeds);

                                _random.Shuffle(seeds);

                                connectionManager.PushSeeds(seeds);

                                Debug.WriteLine(string.Format("ConnectionManager: Push Seeds ({0})", seeds.Count));
                                _pushSeedCount.Add(seeds.Count);

                                foreach (var seed in linkSeeds)
                                {
                                    var signature = seed.Certificate.ToString();

                                    messageManager.StockLinkSeeds[signature] = seed.CreationTime;
                                }

                                foreach (var seed in storeSeeds)
                                {
                                    var signature = seed.Certificate.ToString();

                                    messageManager.StockStoreSeeds[signature] = seed.CreationTime;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
            }
            finally
            {
                this.RemoveConnectionManager(connectionManager);
            }
        }