áááºá¹ááá¬áá« Habrusersá áá®áá±á·áá±á¬á· áááºážáá²á·ááá¯ááºááá¯áẠNTP client ááᯠáááºááá¯áá±ážáááá²ááá¯áᬠááŒá±á¬ááŒáá»ááºáá«áááºá á¡ááŒá±áá¶á¡á¬ážááŒáá·áºá á
áá¬ážááá¯ááºážááẠáááºáááºáááœá²á·á
ááºážáá¯á¶ááŸáá·áº NTP áá¬áá¬á០áá¯á¶á·ááŒááºááŸá¯ááᯠáá¯ááºáá±á¬ááºááá·áºáááºážáááºážááá¯á· ááŒá±á¬ááºážáá²ááœá¬ážáááºááŒá
áºáááºá áá¯ááºááᯠPython ááŒáá·áº áá±ážáá¬ážáááá·áºáááºá á¡ááŒá±á¬ááºážááŸá¬ ááá¯ááá¯á·áá±á¬ á¡áá¬áá»á¬ážá¡ááœáẠááá¯ááá¯áá±á¬ááºážááœááºáá±á¬ áá¬áá¬á
áá¬áž áááŸááᯠáá°ááá«áááºá Connoisseurs áá»á¬ážááẠntplib áá¯ááºááŸáá·áº áá¯ááºá áá°áá®ááŸá¯ááᯠáááááŒá¯áááááá·áºááẠ- áááºážááŒá±á¬áá·áº áá»áœááºá¯ááºááẠâá
áááºá¡á¬ážáááºáááºâ áá²á·áááºá
áá«ááᯠNTP ááá¯áá¬áá¬áá²á NTP ááẠá¡áá»áááºá¡ááá¡áá»áá¬áá¬áá»á¬ážááŸáá·áº á¡ááŒááºá¡ááŸááºáá¯á¶á·ááŒááºáááºá¡ááœáẠáááá¯ááá¯áá±á¬áá
áºáá¯ááŒá
áºáááºá á€áááá¯ááá¯áá±á¬ááᯠáá±ááºáá®á
ááºáá»á¬ážá
áœá¬ááœáẠá¡áá¯á¶ážááŒá¯áááºá á¥ááá¬á¡á¬ážááŒáá·áºá windows ááŸá w32tm áááºáá±á¬ááºááŸá¯á
NTP áááá¯ááá¯áá±á¬á áá¬ážááŸááºáž á á¯á á¯áá±á«ááºáž á áá»áá¯ážááŸááááºá ááááá¬ážááŸááºáž 0 (1985, RFC958) ááᯠáááºááŸáááœáẠáá±ááºááá®áá±á¬á·áᯠáá°ááá¬ážáááºá áááºááŸáááœáẠáá¬ážááŸááºážá¡áá áºáá»á¬ážááᯠá¡áá¯á¶ážááŒá¯áá±áááº- áá¬ážááŸááºáž 1 (1988, RFC1059)á áá¬ážááŸááºáž 2 (1989, RFC1119)á áá¬ážááŸááºáž 3 (1992, RFC1305) ááŸáá·áº áá¬ážááŸááºáž 4 (1996, RFC2030)á áá¬ážááŸááºáž 1-4 áá»á¬ážááẠáá áºáá¯ááŸáá·áºáá áºáᯠááœá²áááºá¡áá¯á¶ážááŒá¯ááá¯ááºáááºá áááºážááá¯á·á áááºáááºááŸá¯ á¡ááºáááá¯áá®áááºáá»á¬ážááœááºáᬠááœá²ááŒá¬ážáááºá áá¬áá¬áá»á¬áž.
Package áá±á¬áºáááº

áá¯ááºááŒááá¯áẠ(ááŒááºáááºááŸá¯ááœáŸááºááŒáá»ááº) - ááŸáááŸáá¯ááºážáá¯áááá¡ááŒá±á¬ááºážááááá±ážááœáŸááºááŒáá±á¬áá¶áá«ááºáá
áºáá¯á á¡áááá¹áá«ááº-
- 0 - ááŒá¯ááŒááºááŸá¯áááŸááá«á
- 1 - áá áºáá±á·áá¬ááá±á¬ááºáá¯á¶ážáááá áºááœáẠ61 á áá¹ááá·áºáá«áááºáááºá
- 2 - áá áºáá±á·áá¬ááá±á¬ááºáá¯á¶ážáááá áºááœáẠ59 á áá¹ááá·áºáá«áááºáááºá
- 3 â áá¬áá¬áá»áœááºááœááºážááŸá¯ (á¡áá»áááºááᯠáááºáá°ááŒá¯ááááá«)
áá¬ážááŸááºážáá¶áá«áẠ(áá¬ážááŸááºážáá¶áá«ááº) â NTP áááá¯ááá¯áá±á¬ áá¬ážááŸááºážáá¶áá«áẠ(á-á)á
áá¯á¶ (áá¯ááº) â áá¯ááºááá¯ážáá±ážááá¯á·áá°á áááºáááºááŸá¯áá¯ááºá 0 á០7 á¡ááá á¡áá¯á¶ážá¡áá»á¬ážáá¯á¶ážáááºááá¯áž-
- 3 - áá±á¬ááºáááº
- 4 â áá¬áá¬
- 5 â áá¯ááºááœáŸáá·áºááŸá¯áá¯ááº
á¡ááœáŸá¬ (á¡ááœáŸá¬á¡ááá·áº) â áá¬áá¬ááŸáá·áº áááºááœáŸááºážáá¬áá®ááŒá¬ážááŸá á¡áááºá¡áááºá¡ááœáŸá¬á¡áá±á¡ááœáẠ(1 â áá¬áá¬ááẠáááºááœáŸááºážáá¬áá®á០áá±áá¬ááᯠááá¯ááºááá¯ááºáá°áááºá 2 â áá¬áá¬ááẠá¡ááœáŸá¬ 1 áá«ááá·áº áá¬áá¬áá
áºáá¯á០áá±áá¬ááᯠáá°áááº)á
áá±áá°ážááẠáááºááá¯ááºáááºáá±á·áá»áºáá»á¬ážááŒá¬áž á¡ááŒáá·áºáá¯á¶ážááŒá¬ážáá¬áááᯠááá¯ááºá
á¬ážááŒá¯ááá·áº ááááºážááŒáá·áºáá
áºáá¯ááŒá
áºáááºá NTP client ááẠáá¬áá¬ááᯠá
á
áºáááºážáá±á¬ááºáá°ááẠáá»áŸá±á¬áºááá·áºáá¬ážááá·áº ááŒá¬ážáá¬áááᯠá€áá±áá¬ááœáẠáááºááŸááºáá±ážááŒá®áž NTP áá¬áá¬á០áá±á¬ááºáá°ááẠáá»áŸá±á¬áºááá·áºáá¬ážááá·áº ááŒá¬ážáá¬áááᯠáááºááŸááºáá±ážáá«áááºá áááºááá¯ážááẠá
áá¹ááá·áºá binary logarithm ááŸáá·áº áá®áá»áŸáááºá
á
á±á·á
ááºáá±áá»á¬ááŒááºáž (accuracy) ááẠá
áá
áºáá¬áá®á áááá»ááŸá¯ááᯠááá¯ááºá
á¬ážááŒá¯ááá·áº ááááºážááŒáá·áºááŒá
áºáááºá áááºááá¯ážááẠá
áá¹ááá·áºá binary logarithm ááŸáá·áº áá®áá»áŸáááºá
Root ááŸá±á¬áá·áºááŸá±ážááŒááºážá (áá¬áá¬ááŸá±á¬áá·áºááŸá±ážááŸá¯) â áááºááŸááºáá¬ážáá±á¬ á¡ááŸááºá¡áá±á¡ááœááºá¡ááŒá
Ạá
áá¹ááá·áºá¡ááá¯áẠNTP áá¬áá¬ááá¯á·áá±á¬ááºááŸáááẠáá¬áá®áááºááŸá¯ááŒááºážá¡ááœáẠááá¯á¡ááºáá±á¬á¡áá»áááºá
á¡ááŒá
áºááŒáá·áºááŸá¶á·ááŒááºážá (áá¬áá¬ááŒáá·áºááŒááºááŸá¯) - áá¯á¶áá±á¡ááŸááºááŒáá·áº á
áá¹ááá·áºá¡áá±á¡ááœááºá¡ááŒá
ẠNTP áá¬áá¬áá¬áá®áááºááŒááºážááá»á¶á·ááŸá¶á·ááŸá¯á
Ref id (á¡áááºážá¡ááŒá
Ạidentifier) âââ áá¬áá® IDá áá¬áá¬ááœáẠstratum 1 ááŸááá«áá ref id ááẠá¡ááºáááºáá¬áá® (4 ASCII á
á¬áá¯á¶áž) á á¡áááºááŒá
áºáááºá á¡áááºá áá¬áá¬ááẠá¡ááŒá¬ážáá¬áá¬ááá¯á¡áá¯á¶ážááŒá¯áá«áá ááá¯ážáá¬ážáá»áẠID ááœáẠá€áá¬áá¬áááááºá
á¬áá«ááŸááááºá
áá±á¬ááºáá¯á¶áž á¡ááœáẠ4 áá¯ááẠá¡áá»ááẠ- 32 bits - ááááºážááŒáá·áºá¡ááá¯ááºážá 32 bits - á¡ááá¯ááºážááááºážá¡ááá¯ááºážááᯠááá¯ááºá
á¬ážááŒá¯áááºá
á¡ááœáŸááºáž - áá¬áá¬áá±á«áºááŸá áá±á¬ááºáá¯á¶ážáá±á«áº áá¬áá®áá»á¬ážááᯠáááºááŒááºážá
á¡á
ááŒá¯ - áááºáááºááᯠááá¯á·ááá¯ááºááá·áºá¡áá»ááẠ(áá¬áá¬á០ááŒáá·áºááœááºážááẠ- á€á¡áá¬á¡áá±á«áº áá±á¬ááºáááº)á
áá¶áá° - áá¬áá¬á០packet ááá¯áááºáá¶áááŸáááá·áºá¡áá»áááºá
ááá¯á·áá±áž - áá¬áá¬á០áááá¯ááºážááá·áºáá¶ááá¯á· áááºáááºááᯠáá±ážááá¯á·ááá·áºá¡áá»ááẠ(Client á០ááŒáá·áºááœááºážáá¬ážáá±á¬á á€á¡áá¬á¡áá±á«áº áá±á¬ááºáááº)á
áá»áœááºá¯ááºááá¯á·ááẠáá±á¬ááºáá¯á¶ážáááºáááºááŸá áºáá¯ááᯠááá·áºááœááºážá ááºážá á¬ážáááºááá¯ááºáá«á
áá»áœááºá¯ááºááá¯á·á package ááá¯áá±ážááŒáá«á áá¯á·á
á¡áá¯ááºáá¯ááº
class NTPPacket:
_FORMAT = "!B B b b 11I"
def __init__(self, version_number=2, mode=3, transmit=0):
# Necessary of enter leap second (2 bits)
self.leap_indicator = 0
# Version of protocol (3 bits)
self.version_number = version_number
# Mode of sender (3 bits)
self.mode = mode
# The level of "layering" reading time (1 byte)
self.stratum = 0
# Interval between requests (1 byte)
self.pool = 0
# Precision (log2) (1 byte)
self.precision = 0
# Interval for the clock reach NTP server (4 bytes)
self.root_delay = 0
# Scatter the clock NTP-server (4 bytes)
self.root_dispersion = 0
# Indicator of clocks (4 bytes)
self.ref_id = 0
# Last update time on server (8 bytes)
self.reference = 0
# Time of sending packet from local machine (8 bytes)
self.originate = 0
# Time of receipt on server (8 bytes)
self.receive = 0
# Time of sending answer from server (8 bytes)
self.transmit = transmit
áá¬áá¬ááá¯á· áááºáááºáá
áºáᯠáá±ážááá¯á·ááŒááºáž (áááºáá¶ááŒááºáž) ááŒá¯áá¯ááºáááºá áááºážááᯠbyte áááºážáá»ááºážáá
áºáá¯á¡ááŒá
ẠááŒá±á¬ááºážáá²ááá¯ááºááá«áááºá
ဠ(ááŸáá·áº ááŒá±á¬ááºážááŒááº) áá¯ááºáá±á¬ááºáá»ááºá¡ááœááºá áá»áœááºá¯ááºááá¯á·ááẠáá¯ááºáá±á¬ááºáá»áẠááŸá
áºáá¯ááᯠáá±ážáá¬ážáá«ááẠ- pack() ááŸáá·áº unpack():
pack áá¯ááºáá±á¬ááºáá»ááº
def pack(self):
return struct.pack(NTPPacket._FORMAT,
(self.leap_indicator << 6) +
(self.version_number << 3) + self.mode,
self.stratum,
self.pool,
self.precision,
int(self.root_delay) + get_fraction(self.root_delay, 16),
int(self.root_dispersion) +
get_fraction(self.root_dispersion, 16),
self.ref_id,
int(self.reference),
get_fraction(self.reference, 32),
int(self.originate),
get_fraction(self.originate, 32),
int(self.receive),
get_fraction(self.receive, 32),
int(self.transmit),
get_fraction(self.transmit, 32))
unpack function ááá¯
def unpack(self, data: bytes):
unpacked_data = struct.unpack(NTPPacket._FORMAT, data)
self.leap_indicator = unpacked_data[0] >> 6 # 2 bits
self.version_number = unpacked_data[0] >> 3 & 0b111 # 3 bits
self.mode = unpacked_data[0] & 0b111 # 3 bits
self.stratum = unpacked_data[1] # 1 byte
self.pool = unpacked_data[2] # 1 byte
self.precision = unpacked_data[3] # 1 byte
# 2 bytes | 2 bytes
self.root_delay = (unpacked_data[4] >> 16) +
(unpacked_data[4] & 0xFFFF) / 2 ** 16
# 2 bytes | 2 bytes
self.root_dispersion = (unpacked_data[5] >> 16) +
(unpacked_data[5] & 0xFFFF) / 2 ** 16
# 4 bytes
self.ref_id = str((unpacked_data[6] >> 24) & 0xFF) + " " +
str((unpacked_data[6] >> 16) & 0xFF) + " " +
str((unpacked_data[6] >> 8) & 0xFF) + " " +
str(unpacked_data[6] & 0xFF)
self.reference = unpacked_data[7] + unpacked_data[8] / 2 ** 32 # 8 bytes
self.originate = unpacked_data[9] + unpacked_data[10] / 2 ** 32 # 8 bytes
self.receive = unpacked_data[11] + unpacked_data[12] / 2 ** 32 # 8 bytes
self.transmit = unpacked_data[13] + unpacked_data[14] / 2 ** 32 # 8 bytes
return self
áá»ááºážáá°áá»á¬ážá¡ááœáẠá¡ááá®áá±ážááŸááºážáá áºáá¯á¡áá±ááŒáá·áº áááºáá±á·ááºá»ááᯠááŸááá±á¬á á¬ááŒá±á¬ááºážá¡ááŒá ẠááŒá±á¬ááºážáá²áá±ážááá·áºáá¯ááº
def to_display(self):
return "Leap indicator: {0.leap_indicator}n"
"Version number: {0.version_number}n"
"Mode: {0.mode}n"
"Stratum: {0.stratum}n"
"Pool: {0.pool}n"
"Precision: {0.precision}n"
"Root delay: {0.root_delay}n"
"Root dispersion: {0.root_dispersion}n"
"Ref id: {0.ref_id}n"
"Reference: {0.reference}n"
"Originate: {0.originate}n"
"Receive: {0.receive}n"
"Transmit: {0.transmit}"
.format(self)
áá¬áá¬ááá¯á· áááºáá±á·ááºá»áá áºáᯠááá¯á·ááŒááºážá
ááŒáá·áºáá¬ážáá±á¬ á¡ááœááºáá»á¬ážáá«ááŸááá±á¬ áááºáááºááᯠáá¬áá¬ááá¯á· áá±ážááá¯á·ááá«áááºá áá¬ážááŸááºáž, áá¯á¶ О ááá¯á·áá±ážá á¡ááá¯áá« ááá¯á·áá±áž á ááºááœááºážá ááºááœáẠáááºááŸáá¡áá»ááẠ(áááºááá«áá® 1á 1900 ááááºážá)á áá¬ážááŸááºáž - 1-4á áá¯áẠ- 3 (áá±á¬ááºáááºáá¯ááº) ááœáẠáááºáááºááŸááºááá«áááºá
áá±á¬ááºážááá¯áá»ááºááá¯áááºáá¶ááŒá®ážáá±á¬áẠáá¬áá¬ááẠNTP áááºáááºááŸá ááœááºáááºá¡á¬ážáá¯á¶ážááᯠááŒáá·áºá áœááºáᬠá¡ááœááºáá²ááá¯á· áá°ážáá°ááŒááºáž á¡á ááŒá¯ áá¶ááŸáááºááá¯áž ááá¯á·áá±ážáá±á¬ááºážááá¯áá»ááºáá²ááœáẠáá«áá¬áááºá áá±á¬ááºáááºááẠáááºááœááºážááŸá áá°áá¡áá»áááºáááºááá¯ážááᯠáá»ááºáá»ááºážáááŒáá·áºááá¯ááºáááŒááºážááŸá¬ áá»áœááºá¯ááºá¡ááœáẠáááºážááŒááºáá«áááºá á¡á ááŒá¯. ááááºá¡áá±ááŒáá·áº packet ááŒááºáá¬áá±á¬á¡áá«á client ááœáẠá¡áá»áááºáááºááá¯áž 4 áá¯ááŸáááẠ- áá±á¬ááºážááá¯áá»ááºáá±ážááá¯á·ááá·áºá¡áá»ááẠ(á¡á ááŒá¯) áá¬áá¬ááẠáá±á¬ááºážááá¯áá»ááºááᯠáááºáá¶áááŸáááá·áºá¡áá»ááẠ(áá¶áá°) áá¬áá¬á០áá¯á¶á·ááŒááºááŸá¯áá±ážááá¯á·ááá·áºá¡áá»ááẠ(ááá¯á·áá±áž) ááŸáá·áº client á០áá¯á¶á·ááŒááºááŸá¯ááᯠáááºáá¶áááŸáááá·áºá¡áá»áááº- áá±á¬ááºáᬠ(á¡áá¯ááºáá²ááœááºááá«áá«)á á€áááºááá¯ážáá»á¬ážááá¯á¡áá¯á¶ážááŒá¯ááŒááºážááŒáá·áº áá»áœááºá¯ááºááá¯á·ááẠááŸááºáááºáá±á¬á¡áá»áááºááᯠáááºááŸááºááá¯ááºáááºá
á¡áá¯ááºááá¯á·ááŒááºážááŸáá·áºáááºáá¶ááŒááºážáá¯ááº
# Time difference between 1970 and 1900, seconds
FORMAT_DIFF = (datetime.date(1970, 1, 1) - datetime.date(1900, 1, 1)).days * 24 * 3600
# Waiting time for recv (seconds)
WAITING_TIME = 5
server = "pool.ntp.org"
port = 123
packet = NTPPacket(version_number=2, mode=3, transmit=time.time() + FORMAT_DIFF)
answer = NTPPacket()
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.settimeout(WAITING_TIME)
s.sendto(packet.pack(), (server, port))
data = s.recv(48)
arrive_time = time.time() + FORMAT_DIFF
answer.unpack(data)
áá¬áá¬á០áá±áá¬ááᯠáá¯ááºáá±á¬ááºáá±áááºá
áá¬áá¬á០áá±áá¬áá»á¬ážááᯠáá¯ááºáá°ááŒááºážááẠRaymond M. Smullyan (1978) á ááŒá¿áá¬áá±á¬ááºážá០á¡ááºá¹áááááºáá°ááŒá®ážáááºážá áá¯ááºáá±á¬ááºáá»ááºááŸáá·áº áááºáá°áááº- "áá°áá áºáŠážááœáẠáááºáááºáá¬áá®áá áºáá¯á¶ážá០áááŸááá±á¬áºáááºáž á¡áááºááœáẠáá áºáá«áá áºáá¶ áá°áá±á·áá±áá±á¬ áááá»áá±á¬ ááá¯ááºáááºáá¬áá®áá áºáá¯á¶ážááŸááááºá áá±ááá¯ááºáááºá áá áºáá±á·ááœáẠáá¬áá®ááᯠáá±á¬ááºáá áºááŒááẠáá±ááá¯ááºááẠáá±á·ááœá¬ážáááŒáá·áº áá°á·áá°áááºáá»ááºážáá¶ ááœá¬ážáááºáᬠááá±áááºážááœáẠá¡áá°áá±áᬠá¡áááºááŒááºáá±á¬ááºáá±á¬á¡áá« áá¬áá®ááᯠááŸááºáááºá áœá¬ áááºááŸááºááá¯ááºáá²á·áááºá ááá®ážááœá¬ážáá»áááºááᯠááŒáá¯áááááẠáá°áááºááá¯áá¯ááºáááá²á á¡ááŒá±ááá±á¬á· âá¡áááºáááœááºááœá¬ážáá²á·á¡áá« áá°áá áºáá±á¬ááºá áá¬áá®ááᯠáá±ááá¯ááºááŒá®áž áááºáá²ááŸá¬ááŸááá²á· á¡áá±á¡áá¬ážááᯠááŸááºáááááºá áá°áááºáá»ááºážáá áºáá±á¬ááºáá®áá¬ááŒá®áž á§áá·áºáááºááœá±ááᯠáá¬ážáá²á·ááŒá®áž áá°áá±á¬ááºááŸááá»áááºáá²á· ááœááºááœá¬áá»áááºááᯠááŸááºáá¬ážáá¬ážáá²á·áá«áááºá á€á¡áá¬á áá°áá¬áá±á¬ááºáááºáááºáá²á·áááºááᯠááááŸáááá¯ááºáááºááŒá áºáááºá á¡áááºááŒááºáá±á¬ááºááŒá®áž áá¬áá®ááá¯ááŒáá·áºááá¯ááºáá±á¬á· áá°áá áºáá±á¬ááºá áá°áááŸááá±á¬á·áá²á· á¡áá»áááºááᯠá¡áá¯á¶ážá¡ááŒááºáá±ážáá«áááºá áá°áááºáááºáá²á·áá²á·á¡áá»áááºááᯠáá¯ááºááá¯ááºááŒááºážá¡á¬ážááŒáá·áº á¡á²áá®áá±áá¬áá²á· á¡ááŒááºááá®ážááᯠááŒááºáááºážáá²á·ááá²á· á¡áá»áááºááᯠáá°áá áºáá±á¬ááºá áááááºá á§áá·áºáááºáá»á¬áž ááœááºááœá¬áá»áááºá¡áá áááºážáá±á«áºááœáẠáá¯ááºáá¯á¶ážáá²á·áá±á¬ á¡áá»áááºáá áºáááºááᯠáá±á«ááºážááá·áºááŒááºážááŒáá·áº á¡áááºááá¯á·áá±á¬ááºááŸáááá·áºá¡áá»áááºááᯠááááŸáááá¯ááºááŒá®áž áá¬áá®áááºáá¶áá»á¬ážááᯠáá»áááºááŸáááẠá¡ááœáá·áºá¡áá±ážáááŸááááºááŒá áºáááºáâ
áá±á¬ááºážááá¯áá»ááºáá áºáá¯á¡ááœáẠáá¬áá¬áá¯ááºáá±á¬ááºáá±ááá·áºá¡áá»áááºááᯠááŸá¬áá«-
- client á០áá¬áá¬ááá¯á· packet á ááá®ážááœá¬ážáá»áááºááᯠááŸá¬áá«- ((áá±á¬ááºááŸá â áá°áá¡á ) â (ááá¯á· â áááºáá¶)) / á
- client ááŸáá·áº server time á¡ááŒá¬áž ááŒá¬ážáá¬ážáá»ááºááᯠááŸá¬áá«
áááºáá¶ - Originate - ((Arrive - Originate) - (Transmit - Receive)) / 2 =
2 * áááºáá¶ â 2 * áá°á â áá±á¬ááºááŸááá¬ááẠ+ áá°á + áá±ážááá¯á·ááŒááºáž â áááºáá¶ =
áááºáá¶ â áá°áááºáž â áá±á¬ááºááẠ+ ááá¯á·áá«á
áá»áœááºá¯ááºááá¯á·ááẠáá±áá á¶áá±á¬áºáá»áááºá ááááºáááºááá¯ážááᯠáá±á«ááºážááá·áºáᬠááááᯠáá»á±á¬áºááœáŸááºá áœá¬ááŒááºáááºážáá«á
ááááºááœááº
time_different = answer.get_time_different(arrive_time)
result = "Time difference: {}nServer time: {}n{}".format(
time_different,
datetime.datetime.fromtimestamp(time.time() + time_different).strftime("%c"),
answer.to_display())
print(result)
á¡áá¯á¶ážáááºáááºá .
source: www.habr.com
