import math
import random
COLOURS = [ 'black' , 'yellow' , 'red' , 'magenta' , 'cyan' , 'purple' ]
class Square( object ) :
# строки 6-37 это лишь описание класса, образец, blueprint, если угодно,
# но сам он не является объектом (инстансом) квадрата.
# А вот вызвывая "Square()" уже и создаётся квадрат. Каждый раз — новый,
# с теми параметрами (стороны и цвета), которые были переданы в аргументами.
def __init__ ( self , side, colour= "black" ) :
self .side = side
self .colour = colour
@ classmethod
def generate_random( cls, colours) :
# Это классовый метод, в котором первым аргументом передаётся не инстанс
# класса (то, что в методах 'self' обозначается), а сам класс/тип.
# Т.е. в данном случае cls == Square, а выражение cls(side, colour)
# эквивалентно Square(side, colour). Разница появляется при налседовани, где
# cls уже будет тем классом, без необходимости заново объявлять этот метод.
# В ромбе-алмазе увидишь, как работает.
# Ссылаться на глобальные переменные как-то не круто, я подумал, поэтому
# решил добавить аргумент с массивом цветов, так как это универсальный аргумент
# среди всех фигур.
side = random .random ( ) * 100
colour = colours[ random .randint ( 0 , len ( colours) - 1 ) ]
return cls( side, colour)
def area( self ) :
# на метод изменил, чтобы с проперти тебя не путать — потом почитаешь про них
return self .side ** 2
def description( self ) :
# Возвращает строку с описанием объекта, при вызове этого метода у
# конкретного объекта (инстанса класса Square или любого из унаследовавших)
# __class__.__name__ — чтобы было написано название именно класса объекта,
# а не то, что я тут впишу текстом, но при этом и не было необходимости
# создавать лишние классовые переменные при наследовании. Это на вкус уже,
# конечно, потому что может нужно в тексте иметь "triangle", а класс назвать
# Trngl. Нутыпонел, в общем, просто полезную штучку показать решил.
# В ромбе-алмазе увидишь, как работает.
return "%s %s with side: %.2f, area: %.2f" % ( self .colour .title ( ) ,
self .__class__.__name__.lower ( ) , self .side , self .area ( ) )
class Circle( object ) :
def __init__ ( self , radius, colour= "black" ) :
self .radius = radius
self .colour = colour
@ classmethod
def generate_random( cls, colours) :
radius = random .random ( ) * 100
colour = colours[ random .randint ( 0 , len ( colours) - 1 ) ]
return cls( radius, colour)
def area( self ) :
return self .radius ** 2 * math .pi
def description( self ) :
return "%s %s with radius: %.2f, area: %.2f" % ( self .colour .title ( ) ,
self .__class__.__name__.lower ( ) , self .radius , self .area ( ) )
class Diamond( Square) :
# ромб (у которого все стороны равны, как у квадрата), но имеющий углы по
# 60 и 120 градусов.
def area( self ) :
return self .side ** 2 * math .sin ( math .pi * ( 60 /180 ) )
# Если сначала просто вручную создадим парочку.
s1 = Square( 5 ) # квадрат со стороной 5 и чёрным (дефолтным) цветом.
s2 = Square( 10 , "yellow" ) # жёлтый квадрат со стороной 10.
# Никаки строк текста никуда пока не писалось, но за s1 и s2 стоят самые настоящие
# квадратики, с которым можно что угодно делать. Был бы у них метод draw(), сейчас
# бы я мог их нарисовать. Или не сейчас.
# А вот теперь я хочу посмотреть описание второго квадрата:
print ( s2.description ( ) )
# Теперь к генератору перейдём
classes = [ Square, Circle, Diamond]
# Это просто список всех классов (_типов_ фигур). Я их туда запихнул для лупа
# дальнейшего лупа по этом списку и генерации их всех за один проход. Можно, конечно,
# и как ты - отдельно каждого класса создавать, а потом перемешать, но представь,
# что у тебя 100 таких классов - задолбаешься на каждый из них пускай даже по 5, но
# одинаковых строк тратить. А так запихнул в список и прекрасно.
figs = [ ] # вот это как вот раз список _фигур_ (таких объектов, как s1 и s2)
numfigs = 5
# Дальше создадим десяток их (numfigs = 5, но по две за одну итерацию создаётся)
for i in range ( numfigs) :
fig = classes[ random .randint ( 0 , len ( classes) - 1 ) ]
# fig - просто рандомный класс из списка выше.
# В данные момент, например, может быть, что fig == Circle.
side_or_rad = random .random ( ) * 100
colour = COLOURS[ random .randint ( 0 , len ( COLOURS) - 1 ) ]
# Так как у нас все фигуры имеют одинаковый "вид" создания: длина/радиус и цвет,
# можно не делать отдельно функции для каждого, а просто сгенерить случайные
# side_or_rad и colour, которые можно передавать любому из классов.
# В реальности же, добавив, например, треугольник, больше так не сделать, так как
# он одним параметром не задаётся (разве что равнобедренный, но это отедльный
# случай). Для этого я и сделал классовый метод generate_random(), который
# уникален для каждой отдельной фигуры, и создаётся именно в классе,
# а не где-то отдельно.
figure = fig( side_or_rad, colour)
figs.append ( figure)
# Добавим ещё одну, воспользовавшись этим самым методом.
fig = classes[ random .randint ( 0 , len ( classes) - 1 ) ]
figs.append ( fig.generate_random ( COLOURS) )
# А теперь выведем _описание_ фигуры. По две строки на каждую, где первая - это
# дефолтное питоновское описание любого объекта - класс и область в памяти,
# а вторая - как раз наш метод, возвращающий текст с разрмерами и т.д.
# (На самом деле первая строка это результат метода __repr__(), который в предыдущей версии
# кода можешь увидеть.
for fig in figs:
print ( )
print ( fig)
print ( fig.description ( ) )
aW1wb3J0IG1hdGgKaW1wb3J0IHJhbmRvbQoKQ09MT1VSUyA9IFsnYmxhY2snLCAneWVsbG93JywgJ3JlZCcsICdtYWdlbnRhJywgJ2N5YW4nLCAncHVycGxlJ10KCmNsYXNzIFNxdWFyZShvYmplY3QpOgoJIyDRgdGC0YDQvtC60LggNi0zNyDRjdGC0L4g0LvQuNGI0Ywg0L7Qv9C40YHQsNC90LjQtSDQutC70LDRgdGB0LAsINC+0LHRgNCw0LfQtdGGLCBibHVlcHJpbnQsINC10YHQu9C4INGD0LPQvtC00L3QviwKCSMg0L3QviDRgdCw0Lwg0L7QvSDQvdC1INGP0LLQu9GP0LXRgtGB0Y8g0L7QsdGK0LXQutGC0L7QvCAo0LjQvdGB0YLQsNC90YHQvtC8KSDQutCy0LDQtNGA0LDRgtCwLgoJIyDQkCDQstC+0YIg0LLRi9C30LLRi9Cy0LDRjyAiU3F1YXJlKCkiINGD0LbQtSDQuCDRgdC+0LfQtNCw0ZHRgtGB0Y8g0LrQstCw0LTRgNCw0YIuINCa0LDQttC00YvQuSDRgNCw0Lcg4oCUINC90L7QstGL0LksCgkjINGBINGC0LXQvNC4INC/0LDRgNCw0LzQtdGC0YDQsNC80LggKNGB0YLQvtGA0L7QvdGLINC4INGG0LLQtdGC0LApLCDQutC+0YLQvtGA0YvQtSDQsdGL0LvQuCDQv9C10YDQtdC00LDQvdGLINCyINCw0YDQs9GD0LzQtdC90YLQsNC80LguCiAgICBkZWYgX19pbml0X18oc2VsZiwgc2lkZSwgY29sb3VyPSJibGFjayIpOgogICAgICAgIHNlbGYuc2lkZSA9IHNpZGUKICAgICAgICBzZWxmLmNvbG91ciA9IGNvbG91cgogICAgCiAgICBAY2xhc3NtZXRob2QKICAgIGRlZiBnZW5lcmF0ZV9yYW5kb20oY2xzLCBjb2xvdXJzKToKICAgICAgICAjINCt0YLQviDQutC70LDRgdGB0L7QstGL0Lkg0LzQtdGC0L7QtCwg0LIg0LrQvtGC0L7RgNC+0Lwg0L/QtdGA0LLRi9C8INCw0YDQs9GD0LzQtdC90YLQvtC8INC/0LXRgNC10LTQsNGR0YLRgdGPINC90LUg0LjQvdGB0YLQsNC90YEKICAgICAgICAjINC60LvQsNGB0YHQsCAo0YLQviwg0YfRgtC+INCyINC80LXRgtC+0LTQsNGFICdzZWxmJyDQvtCx0L7Qt9C90LDRh9Cw0LXRgtGB0Y8pLCDQsCDRgdCw0Lwg0LrQu9Cw0YHRgS/RgtC40L8uCiAgICAgICAgIyDQoi7QtS4g0LIg0LTQsNC90L3QvtC8INGB0LvRg9GH0LDQtSBjbHMgPT0gU3F1YXJlLCDQsCDQstGL0YDQsNC20LXQvdC40LUgY2xzKHNpZGUsIGNvbG91cikKICAgICAgICAjINGN0LrQstC40LLQsNC70LXQvdGC0L3QviBTcXVhcmUoc2lkZSwgY29sb3VyKS4g0KDQsNC30L3QuNGG0LAg0L/QvtGP0LLQu9GP0LXRgtGB0Y8g0L/RgNC4INC90LDQu9GB0LXQtNC+0LLQsNC90LgsINCz0LTQtQogICAgICAgICMgY2xzINGD0LbQtSDQsdGD0LTQtdGCINGC0LXQvCDQutC70LDRgdGB0L7QvCwg0LHQtdC3INC90LXQvtCx0YXQvtC00LjQvNC+0YHRgtC4INC30LDQvdC+0LLQviDQvtCx0YrRj9Cy0LvRj9GC0Ywg0Y3RgtC+0YIg0LzQtdGC0L7QtC4KICAgICAgICAjINCSINGA0L7QvNCx0LUt0LDQu9C80LDQt9C1INGD0LLQuNC00LjRiNGMLCDQutCw0Log0YDQsNCx0L7RgtCw0LXRgi4KICAgICAgICAjINCh0YHRi9C70LDRgtGM0YHRjyDQvdCwINCz0LvQvtCx0LDQu9GM0L3Ri9C1INC/0LXRgNC10LzQtdC90L3Ri9C1INC60LDQui3RgtC+INC90LUg0LrRgNGD0YLQviwg0Y8g0L/QvtC00YPQvNCw0LssINC/0L7RjdGC0L7QvNGDCiAgICAgICAgIyDRgNC10YjQuNC7INC00L7QsdCw0LLQuNGC0Ywg0LDRgNCz0YPQvNC10L3RgiDRgSDQvNCw0YHRgdC40LLQvtC8INGG0LLQtdGC0L7Qsiwg0YLQsNC6INC60LDQuiDRjdGC0L4g0YPQvdC40LLQtdGA0YHQsNC70YzQvdGL0Lkg0LDRgNCz0YPQvNC10L3RggogICAgICAgICMg0YHRgNC10LTQuCDQstGB0LXRhSDRhNC40LPRg9GALgogICAgICAgIHNpZGUgPSByYW5kb20ucmFuZG9tKCkgKiAxMDAKICAgICAgICBjb2xvdXIgPSBjb2xvdXJzW3JhbmRvbS5yYW5kaW50KDAsIGxlbihjb2xvdXJzKSAtIDEpXQogICAgICAgIHJldHVybiBjbHMoc2lkZSwgY29sb3VyKQogICAgCiAgICBkZWYgYXJlYShzZWxmKToKICAgICAgICAjINC90LAg0LzQtdGC0L7QtCDQuNC30LzQtdC90LjQuywg0YfRgtC+0LHRiyDRgSDQv9GA0L7Qv9C10YDRgtC4INGC0LXQsdGPINC90LUg0L/Rg9GC0LDRgtGMIOKAlCDQv9C+0YLQvtC8INC/0L7Rh9C40YLQsNC10YjRjCDQv9GA0L4g0L3QuNGFCiAgICAgICAgcmV0dXJuIHNlbGYuc2lkZSAqKiAyCiAgICAKICAgIGRlZiBkZXNjcmlwdGlvbihzZWxmKToKICAgICAgICAjINCS0L7Qt9Cy0YDQsNGJ0LDQtdGCINGB0YLRgNC+0LrRgyDRgSDQvtC/0LjRgdCw0L3QuNC10Lwg0L7QsdGK0LXQutGC0LAsINC/0YDQuCDQstGL0LfQvtCy0LUg0Y3RgtC+0LPQviDQvNC10YLQvtC00LAg0YMgCiAgICAgICAgIyDQutC+0L3QutGA0LXRgtC90L7Qs9C+INC+0LHRitC10LrRgtCwICjQuNC90YHRgtCw0L3RgdCwINC60LvQsNGB0YHQsCBTcXVhcmUg0LjQu9C4INC70Y7QsdC+0LPQviDQuNC3INGD0L3QsNGB0LvQtdC00L7QstCw0LLRiNC40YUpCiAgICAgICAgIyBfX2NsYXNzX18uX19uYW1lX18g4oCUINGH0YLQvtCx0Ysg0LHRi9C70L4g0L3QsNC/0LjRgdCw0L3QviDQvdCw0LfQstCw0L3QuNC1INC40LzQtdC90L3QviDQutC70LDRgdGB0LAg0L7QsdGK0LXQutGC0LAsCiAgICAgICAgIyDQsCDQvdC1INGC0L4sINGH0YLQviDRjyDRgtGD0YIg0LLQv9C40YjRgyDRgtC10LrRgdGC0L7QvCwg0L3QviDQv9GA0Lgg0Y3RgtC+0Lwg0Lgg0L3QtSDQsdGL0LvQviDQvdC10L7QsdGF0L7QtNC40LzQvtGB0YLQuAogICAgICAgICMg0YHQvtC30LTQsNCy0LDRgtGMINC70LjRiNC90LjQtSDQutC70LDRgdGB0L7QstGL0LUg0L/QtdGA0LXQvNC10L3QvdGL0LUg0L/RgNC4INC90LDRgdC70LXQtNC+0LLQsNC90LjQuC4g0K3RgtC+INC90LAg0LLQutGD0YEg0YPQttC1LAogICAgICAgICMg0LrQvtC90LXRh9C90L4sINC/0L7RgtC+0LzRgyDRh9GC0L4g0LzQvtC20LXRgiDQvdGD0LbQvdC+INCyINGC0LXQutGB0YLQtSDQuNC80LXRgtGMICJ0cmlhbmdsZSIsINCwINC60LvQsNGB0YEg0L3QsNC30LLQsNGC0YwKICAgICAgICAjIFRybmdsLiDQndGD0YLRi9C/0L7QvdC10LssINCyINC+0LHRidC10LwsINC/0YDQvtGB0YLQviDQv9C+0LvQtdC30L3Rg9GOINGI0YLRg9GH0LrRgyDQv9C+0LrQsNC30LDRgtGMINGA0LXRiNC40LsuCiAgICAgICAgIyDQkiDRgNC+0LzQsdC1LdCw0LvQvNCw0LfQtSDRg9Cy0LjQtNC40YjRjCwg0LrQsNC6INGA0LDQsdC+0YLQsNC10YIuCiAgICAgICAgcmV0dXJuICIlcyAlcyB3aXRoIHNpZGU6ICUuMmYsIGFyZWE6ICUuMmYiICUgKHNlbGYuY29sb3VyLnRpdGxlKCksIAogICAgICAgICAgICBzZWxmLl9fY2xhc3NfXy5fX25hbWVfXy5sb3dlcigpLCBzZWxmLnNpZGUsIHNlbGYuYXJlYSgpKQogICAgICAgICAgICAKY2xhc3MgQ2lyY2xlKG9iamVjdCk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgcmFkaXVzLCBjb2xvdXI9ImJsYWNrIik6CiAgICAgICAgc2VsZi5yYWRpdXMgPSByYWRpdXMKICAgICAgICBzZWxmLmNvbG91ciA9IGNvbG91cgogICAgCiAgICBAY2xhc3NtZXRob2QKICAgIGRlZiBnZW5lcmF0ZV9yYW5kb20oY2xzLCBjb2xvdXJzKToKICAgICAgICByYWRpdXMgPSByYW5kb20ucmFuZG9tKCkgKiAxMDAKICAgICAgICBjb2xvdXIgPSBjb2xvdXJzW3JhbmRvbS5yYW5kaW50KDAsIGxlbihjb2xvdXJzKSAtIDEpXQogICAgICAgIHJldHVybiBjbHMocmFkaXVzLCBjb2xvdXIpCiAgICAKICAgIGRlZiBhcmVhKHNlbGYpOgogICAgICAgIHJldHVybiBzZWxmLnJhZGl1cyAqKiAyICogbWF0aC5waQoKICAgIGRlZiBkZXNjcmlwdGlvbihzZWxmKToKICAgICAgICByZXR1cm4gIiVzICVzIHdpdGggcmFkaXVzOiAlLjJmLCBhcmVhOiAlLjJmIiAlIChzZWxmLmNvbG91ci50aXRsZSgpLCAKICAgICAgICAgICAgc2VsZi5fX2NsYXNzX18uX19uYW1lX18ubG93ZXIoKSwgc2VsZi5yYWRpdXMsIHNlbGYuYXJlYSgpKQoKY2xhc3MgRGlhbW9uZChTcXVhcmUpOgogICAgIyDRgNC+0LzQsSAo0YMg0LrQvtGC0L7RgNC+0LPQviDQstGB0LUg0YHRgtC+0YDQvtC90Ysg0YDQsNCy0L3Riywg0LrQsNC6INGDINC60LLQsNC00YDQsNGC0LApLCDQvdC+INC40LzQtdGO0YnQuNC5INGD0LPQu9GLINC/0L4gCiAgICAjIDYwINC4IDEyMCDQs9GA0LDQtNGD0YHQvtCyLgogICAgZGVmIGFyZWEoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuc2lkZSAqKiAyICogbWF0aC5zaW4obWF0aC5waSAqICg2MC8xODApKQoKCiMg0JXRgdC70Lgg0YHQvdCw0YfQsNC70LAg0L/RgNC+0YHRgtC+INCy0YDRg9GH0L3Rg9GOINGB0L7Qt9C00LDQtNC40Lwg0L/QsNGA0L7Rh9C60YMuCnMxID0gU3F1YXJlKDUpICAgICAgICAgICAgICAjINC60LLQsNC00YDQsNGCINGB0L4g0YHRgtC+0YDQvtC90L7QuSA1INC4INGH0ZHRgNC90YvQvCAo0LTQtdGE0L7Qu9GC0L3Ri9C8KSDRhtCy0LXRgtC+0LwuCnMyID0gU3F1YXJlKDEwLCAieWVsbG93IikgICAjINC20ZHQu9GC0YvQuSDQutCy0LDQtNGA0LDRgiDRgdC+INGB0YLQvtGA0L7QvdC+0LkgMTAuCiMg0J3QuNC60LDQutC4INGB0YLRgNC+0Log0YLQtdC60YHRgtCwINC90LjQutGD0LTQsCDQv9C+0LrQsCDQvdC1INC/0LjRgdCw0LvQvtGB0YwsINC90L4g0LfQsCBzMSDQuCBzMiDRgdGC0L7Rj9GCINGB0LDQvNGL0LUg0L3QsNGB0YLQvtGP0YnQuNC1CiMg0LrQstCw0LTRgNCw0YLQuNC60LgsINGBINC60L7RgtC+0YDRi9C8INC80L7QttC90L4g0YfRgtC+INGD0LPQvtC00L3QviDQtNC10LvQsNGC0YwuINCR0YvQuyDQsdGLINGDINC90LjRhSDQvNC10YLQvtC0IGRyYXcoKSwg0YHQtdC50YfQsNGBCiMg0LHRiyDRjyDQvNC+0LMg0LjRhSDQvdCw0YDQuNGB0L7QstCw0YLRjC4g0JjQu9C4INC90LUg0YHQtdC50YfQsNGBLgojINCQINCy0L7RgiDRgtC10L/QtdGA0Ywg0Y8g0YXQvtGH0YMg0L/QvtGB0LzQvtGC0YDQtdGC0Ywg0L7Qv9C40YHQsNC90LjQtSDQstGC0L7RgNC+0LPQviDQutCy0LDQtNGA0LDRgtCwOgpwcmludChzMi5kZXNjcmlwdGlvbigpKQoKIyDQotC10L/QtdGA0Ywg0Log0LPQtdC90LXRgNCw0YLQvtGA0YMg0L/QtdGA0LXQudC00ZHQvApjbGFzc2VzID0gW1NxdWFyZSwgQ2lyY2xlLCBEaWFtb25kXQojINCt0YLQviDQv9GA0L7RgdGC0L4g0YHQv9C40YHQvtC6INCy0YHQtdGFINC60LvQsNGB0YHQvtCyIChf0YLQuNC/0L7Qsl8g0YTQuNCz0YPRgCkuINCvINC40YUg0YLRg9C00LAg0LfQsNC/0LjRhdC90YPQuyDQtNC70Y8g0LvRg9C/0LAKIyDQtNCw0LvRjNC90LXQudGI0LXQs9C+INC70YPQv9CwINC/0L4g0Y3RgtC+0Lwg0YHQv9C40YHQutGDINC4INCz0LXQvdC10YDQsNGG0LjQuCDQuNGFINCy0YHQtdGFINC30LAg0L7QtNC40L0g0L/RgNC+0YXQvtC0LiDQnNC+0LbQvdC+LCDQutC+0L3QtdGH0L3QviwKIyDQuCDQutCw0Log0YLRiyAtINC+0YLQtNC10LvRjNC90L4g0LrQsNC20LTQvtCz0L4g0LrQu9Cw0YHRgdCwINGB0L7Qt9C00LDQstCw0YLRjCwg0LAg0L/QvtGC0L7QvCDQv9C10YDQtdC80LXRiNCw0YLRjCwg0L3QviDQv9GA0LXQtNGB0YLQsNCy0YwsCiMg0YfRgtC+INGDINGC0LXQsdGPIDEwMCDRgtCw0LrQuNGFINC60LvQsNGB0YHQvtCyIC0g0LfQsNC00L7Qu9Cx0LDQtdGI0YzRgdGPINC90LAg0LrQsNC20LTRi9C5INC40Lcg0L3QuNGFINC/0YPRgdC60LDQuSDQtNCw0LbQtSDQv9C+IDUsINC90L4KIyDQvtC00LjQvdCw0LrQvtCy0YvRhSDRgdGC0YDQvtC6INGC0YDQsNGC0LjRgtGMLiDQkCDRgtCw0Log0LfQsNC/0LjRhdC90YPQuyDQsiDRgdC/0LjRgdC+0Log0Lgg0L/RgNC10LrRgNCw0YHQvdC+LgoKCmZpZ3MgPSBbXSAgICAgICAjINCy0L7RgiDRjdGC0L4g0LrQsNC6INCy0L7RgiDRgNCw0Lcg0YHQv9C40YHQvtC6IF/RhNC40LPRg9GAXyAo0YLQsNC60LjRhSDQvtCx0YrQtdC60YLQvtCyLCDQutCw0LogczEg0LggczIpCm51bWZpZ3MgPSA1CgojINCU0LDQu9GM0YjQtSDRgdC+0LfQtNCw0LTQuNC8INC00LXRgdGP0YLQvtC6INC40YUgKG51bWZpZ3MgPSA1LCDQvdC+INC/0L4g0LTQstC1INC30LAg0L7QtNC90YMg0LjRgtC10YDQsNGG0LjRjiDRgdC+0LfQtNCw0ZHRgtGB0Y8pCmZvciBpIGluIHJhbmdlKG51bWZpZ3MpOgogICAgZmlnID0gY2xhc3Nlc1tyYW5kb20ucmFuZGludCgwLCBsZW4oY2xhc3NlcykgLSAxKV0KICAgICMgZmlnIC0g0L/RgNC+0YHRgtC+INGA0LDQvdC00L7QvNC90YvQuSDQutC70LDRgdGBINC40Lcg0YHQv9C40YHQutCwINCy0YvRiNC1LiAKICAgICMg0JIg0LTQsNC90L3Ri9C1INC80L7QvNC10L3Rgiwg0L3QsNC/0YDQuNC80LXRgCwg0LzQvtC20LXRgiDQsdGL0YLRjCwg0YfRgtC+IGZpZyA9PSBDaXJjbGUuCiAgICAKICAgIHNpZGVfb3JfcmFkID0gcmFuZG9tLnJhbmRvbSgpICogMTAwCiAgICBjb2xvdXIgPSBDT0xPVVJTW3JhbmRvbS5yYW5kaW50KDAsIGxlbihDT0xPVVJTKSAtIDEpXQogICAgIyDQotCw0Log0LrQsNC6INGDINC90LDRgSDQstGB0LUg0YTQuNCz0YPRgNGLINC40LzQtdGO0YIg0L7QtNC40L3QsNC60L7QstGL0LkgItCy0LjQtCIg0YHQvtC30LTQsNC90LjRjzog0LTQu9C40L3QsC/RgNCw0LTQuNGD0YEg0Lgg0YbQstC10YIsCiAgICAjINC80L7QttC90L4g0L3QtSDQtNC10LvQsNGC0Ywg0L7RgtC00LXQu9GM0L3QviDRhNGD0L3QutGG0LjQuCDQtNC70Y8g0LrQsNC20LTQvtCz0L4sINCwINC/0YDQvtGB0YLQviDRgdCz0LXQvdC10YDQuNGC0Ywg0YHQu9GD0YfQsNC50L3Ri9C1IAogICAgIyBzaWRlX29yX3JhZCDQuCBjb2xvdXIsINC60L7RgtC+0YDRi9C1INC80L7QttC90L4g0L/QtdGA0LXQtNCw0LLQsNGC0Ywg0LvRjtCx0L7QvNGDINC40Lcg0LrQu9Cw0YHRgdC+0LIuCiAgICAjINCSINGA0LXQsNC70YzQvdC+0YHRgtC4INC20LUsINC00L7QsdCw0LLQuNCyLCDQvdCw0L/RgNC40LzQtdGALCDRgtGA0LXRg9Cz0L7Qu9GM0L3QuNC6LCDQsdC+0LvRjNGI0LUg0YLQsNC6INC90LUg0YHQtNC10LvQsNGC0YwsINGC0LDQuiDQutCw0LoKICAgICMg0L7QvSDQvtC00L3QuNC8INC/0LDRgNCw0LzQtdGC0YDQvtC8INC90LUg0LfQsNC00LDRkdGC0YHRjyAo0YDQsNC30LLQtSDRh9GC0L4g0YDQsNCy0L3QvtCx0LXQtNGA0LXQvdC90YvQuSwg0L3QviDRjdGC0L4g0L7RgtC10LTQu9GM0L3Ri9C5CiAgICAjINGB0LvRg9GH0LDQuSkuINCU0LvRjyDRjdGC0L7Qs9C+INGPINC4INGB0LTQtdC70LDQuyDQutC70LDRgdGB0L7QstGL0Lkg0LzQtdGC0L7QtCBnZW5lcmF0ZV9yYW5kb20oKSwg0LrQvtGC0L7RgNGL0LkgCiAgICAjINGD0L3QuNC60LDQu9C10L0g0LTQu9GPINC60LDQttC00L7QuSDQvtGC0LTQtdC70YzQvdC+0Lkg0YTQuNCz0YPRgNGLLCDQuCDRgdC+0LfQtNCw0ZHRgtGB0Y8g0LjQvNC10L3QvdC+INCyINC60LvQsNGB0YHQtSwKICAgICMg0LAg0L3QtSDQs9C00LUt0YLQviDQvtGC0LTQtdC70YzQvdC+LgogICAgZmlndXJlID0gZmlnKHNpZGVfb3JfcmFkLCBjb2xvdXIpCiAgICBmaWdzLmFwcGVuZChmaWd1cmUpCiAgICAKICAgICMg0JTQvtCx0LDQstC40Lwg0LXRidGRINC+0LTQvdGDLCDQstC+0YHQv9C+0LvRjNC30L7QstCw0LLRiNC40YHRjCDRjdGC0LjQvCDRgdCw0LzRi9C8INC80LXRgtC+0LTQvtC8LgogICAgZmlnID0gY2xhc3Nlc1tyYW5kb20ucmFuZGludCgwLCBsZW4oY2xhc3NlcykgLSAxKV0KICAgIGZpZ3MuYXBwZW5kKGZpZy5nZW5lcmF0ZV9yYW5kb20oQ09MT1VSUykpCgoKIyDQkCDRgtC10L/QtdGA0Ywg0LLRi9Cy0LXQtNC10LwgX9C+0L/QuNGB0LDQvdC40LVfINGE0LjQs9GD0YDRiy4g0J/QviDQtNCy0LUg0YHRgtGA0L7QutC4INC90LAg0LrQsNC20LTRg9GOLCDQs9C00LUg0L/QtdGA0LLQsNGPIC0g0Y3RgtC+CiMg0LTQtdGE0L7Qu9GC0L3QvtC1INC/0LjRgtC+0L3QvtCy0YHQutC+0LUg0L7Qv9C40YHQsNC90LjQtSDQu9GO0LHQvtCz0L4g0L7QsdGK0LXQutGC0LAgLSDQutC70LDRgdGBINC4INC+0LHQu9Cw0YHRgtGMINCyINC/0LDQvNGP0YLQuCwgCiMg0LAg0LLRgtC+0YDQsNGPIC0g0LrQsNC6INGA0LDQtyDQvdCw0Ygg0LzQtdGC0L7QtCwg0LLQvtC30LLRgNCw0YnQsNGO0YnQuNC5INGC0LXQutGB0YIg0YEg0YDQsNC30YDQvNC10YDQsNC80Lgg0Lgg0YIu0LQuCiMgKNCd0LAg0YHQsNC80L7QvCDQtNC10LvQtSDQv9C10YDQstCw0Y8g0YHRgtGA0L7QutCwINGN0YLQviDRgNC10LfRg9C70YzRgtCw0YIg0LzQtdGC0L7QtNCwIF9fcmVwcl9fKCksINC60L7RgtC+0YDRi9C5INCyINC/0YDQtdC00YvQtNGD0YnQtdC5INCy0LXRgNGB0LjQuAojINC60L7QtNCwINC80L7QttC10YjRjCDRg9Cy0LjQtNC10YLRjC4KZm9yIGZpZyBpbiBmaWdzOgogICAgcHJpbnQoKQogICAgcHJpbnQoZmlnKQogICAgcHJpbnQoZmlnLmRlc2NyaXB0aW9uKCkp