private void RouteTo(Message message, Elastic3D to)
        {
            // peer lists
            ElasticAddress[] peers = Peers.ToArray <ElasticAddress>(to, message.Layout()).Shuffle();

            // send me if peers contains me
            if (peers.Contains(LocalEndPoint))
            {
                new BConsole.MessageBuilder()
                .Append("(+) Routing message(")
                .Append(ConsoleColor.DarkCyan, message.ID.Ellipsis())
                .Append(") To:")
                .Append(to.Mul() == 0 ? ConsoleColor.DarkYellow : ConsoleColor.DarkGreen, to)
                .Append(", Me:")
                .Append(ConsoleColor.DarkCyan, LocalEndPoint.Ellipsis())
                //.WriteLine( $", message={message}");
                .WriteLine();

                SendTo(message, LocalEndPoint);

                return;
            }

            // send message to randomly picked one
            // try next if failed
            foreach (var peer in peers)
            {
                new BConsole.MessageBuilder()
                .Append("(+) Routing message(")
                .Append(ConsoleColor.DarkCyan, message.ID.Ellipsis())
                .Append(") To:")
                .Append(to.Mul() == 0 ? ConsoleColor.DarkYellow : ConsoleColor.DarkGreen, to)
                .Append(", Peer:")
                .Append(ConsoleColor.DarkCyan, peer.Ellipsis())
                //.WriteLine($", message={message}");
                .WriteLine();

                if (SendTo(message, peer))
                {
                    break;
                }
            }
        }
        private void OnElasticMessage(Message message)
        {
            // routes info
            byte          ttl    = message.TimeToLive();
            Elastic3D     to     = message.To();
            ElasticLayout layout = message.Layout();
            Elastic3D     me     = layout.DefineCoordinates(NodeKey.Address);

            // message router
            Address router = message.Router();

            // router permitted?
            if (!Peers.Exists(router))
            {
                Logger.warning("Unauthorized router!");
                return;
            }

            // verify message
            if (ShouldVerifyRouter && !message.VerifyRouter(router))
            {
                Logger.warning("Router signature not verified!");
                return;
            }

            new BConsole.MessageBuilder()
            .Append("(-) Received ShouldRoute message(")
            .Append(ConsoleColor.DarkCyan, message.ID.Ellipsis())
            .Append(") To:")
            .Append(to.Mul() == 0 ? ConsoleColor.DarkYellow : ConsoleColor.DarkGreen, to)
            //.WriteLine($", message={message}");
            .WriteLine();

            // broadcast to all cell
            if (to.Mul() > 0 && ttl == 1)
            {
                ElasticAddress[] peers = Peers.ToArray <ElasticAddress>(to, layout);

                new BConsole.MessageBuilder()
                .Append("(!) Broadcasting message(")
                .Append(ConsoleColor.DarkCyan, message.ID.Ellipsis())
                .Append("), To=")
                .Append(ConsoleColor.DarkGreen, to)
                .Append(", nPeers=")
                .Append(ConsoleColor.DarkGreen, peers.Length)
                //.WriteLine($", message={message}");
                .WriteLine();

                // 해당 좌표의 모든 노드에 전송한다.
                message.RouteTo(0, to, layout, NodeKey);
                SendTo(message, peers);
                return;
            }

            // z-axis must be > 0
            if (to.Z < 1)
            {
                Logger.error($"to.z < 1");
                return;
            }

            // y-axis
            if (ttl == 3)
            {
                for (byte y = 1; y <= layout.Y; y++)
                {
                    to.Y = y;
                    message.RouteTo(2, to, layout, NodeKey);
                    RouteTo(message, to);
                }
            }
            // x-axis
            else if (ttl == 2 && to.Y > 0)
            {
                for (byte x = 1; x <= layout.X; x++)
                {
                    to.X = x;
                    message.RouteTo(1, to, layout, NodeKey);
                    RouteTo(message, to);
                }
            }
        }