yandex-kit-logo

Пока был в отпуске сёрфил по просторам рунета и наткнулся на информацию о том, что Яндекс проводит кроме стажировок ещё и курсы. Меня заинтересовал курс, который именуется как КИТ — Курсы Информационных Технологий. Немного подумав решил отправить заявку. Через какое-то время мне пришло приглашение от яндекса пройти что-то напоминающее вступительный экзамен, однако до него долго руки не доходили, да и отпуск хотел провести в дали от компьютера, который каждый день вижу на работе. Когда собрался сдавать экзамен то обнаружил что это последний день подачи результатов, и тут уже не было смысла откладывать в долгий ящик и я приступил. Стоит отметить что Яндекс даёт достаточно большой выбор языков программирования для решения тестовых задачек, среди которых Java 6 и 7, Python, Delphi, C++, Си, Perl, Free Pascal, Bash. К сожалению не было варианта PHP, а на Delphi писал последний раз года 3 назад. C#, который я сейчас потихоньку познаю так же не оказалось в списке, поэтому решил, что пора попробовать пописать на Python, давно хотел начать, но как-то всё не было реальных задач. Под катом сами задания и решения для них на питоне. Сразу оговорюсь, писал на питоне впервые в жизни, сразу сходу, поэтому код может быть убогий, но тесты Яндекса он проходил.

Общая информация о КИТ 4

Компания Яндекс регулярно проводит набор на Курсы информационных технологий для студентов и молодых специалистов, проживающих в Москве и Подмосковье и желающих больше узнать о системном администрировании, операционной системе Linux и её применении в Яндексе. Курс состоит из теоретической и практической части. Первая часть включает в себя несколько лекций. Занятия проходят по будням вечером в московском офисе Яндекса. По окончании курса лекций все слушатели получают сертификаты. Завершающим этапом теоретического курса является экзамен. Слушатели, которые покажут лучшие результаты, получают приглашение на вторую часть курса — практикум по системному и сетевому администрированию в департаменте эксплуатации Яндекса. Студенты будут работать в различных подразделениях департамента и познакомятся с задачами, которые ежедневно решают наши специалисты. Если практика будет успешной, Яндекс может пригласить студентов остаться в Яндексе на постоянную работу. Выпускники курсов могут успешно работать системными администраторами, сетевыми инженерами или специалистами по информационной безопасности.

Во время проведения Яндекс КИТ 3, который стартовал 18 октября 2012 года, 42 из 50 слушателей успешно сдали теоретический экзамен. 12 человек, показавшие наилучшие результаты, были приглашены на практику в отделе системного администрирования Яндекса.

Теперь перейдём к самим заданиям Яндекс КИТ 4, которые нужно было решить для поступления на курсы.

Яндекс КИТ 4 Задание 1: hosts. Изменить имя хоста и домена в hosts

Ограничения

Ограничение времени 1 секунда
Ограничение памяти 64Mb
Ввод
стандартный ввод
Вывод
стандартный вывод

Легенда

В текстовом (ASCII, unix) файле hosts задается соответствие имён и адресов.
В подаваемом программе на стандартный вход файле имя машины bar нужно изменить на baz, а ее имя домена domain.tld нужно заменить на donemain.tld
Результат вывести на стандартный вывод

Формат ввода

127.0.0.1       localhost
192.168.1.10    foo.mydomain.org       foo
192.168.1.13    bar.domain.tld      bar.anotherdomain.tld  bar
213.180.204.62    ynandex.com      www.ynandex.com
# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters


Формат вывода


127.0.0.1       localhost
192.168.1.10 foo.mydomain.org foo
192.168.1.13 baz.donemain.tld baz.anotherdomain.tld baz
213.180.204.62 ynandex.com www.ynandex.com

The following lines are desirable for IPv6 capable hosts

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters



Пример 1



  <th>
    Вывод
  </th>
</tr>

<tr>
  <td>
    <pre><span style="font-size: 10px;">127.0.0.1   localhost

127.0.1.1 pooh
87.250.250.203 foo.domain.tld foo
77.88.21.3 bar.domain.tld bar.mydomain.ru bar
10.188.132.60 mirror.ruopen.ru

The following lines are desirable for IPv6 capable hosts

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

  <td>
    <pre><span style="font-size: 10px;">127.0.0.1   localhost

127.0.1.1 pooh
87.250.250.203 foo.domain.tld foo
77.88.21.3 baz.donemain.tld baz.mydomain.ru baz
10.188.132.60 mirror.ruopen.ru

The following lines are desirable for IPv6 capable hosts

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters



Ввод


Пример 2



  <th>
    Вывод
  </th>
</tr>

<tr>
  <td>
    <pre><span style="font-size: 10px;">127.0.0.1   localhost

127.0.1.1 pooh
87.250.250.203 foobar.domain.tld foobar
77.88.21.3 bar.domain.tld bar.mydomain.ru bar
10.188.132.60 mirror.ruopen.ru

The following lines are desirable for IPv6 capable hosts

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

  <td>
    <pre><span style="font-size: 10px;">127.0.0.1   localhost

127.0.1.1 pooh
87.250.250.203 foobar.domain.tld foobar
77.88.21.3 baz.donemain.tld baz.mydomain.ru baz
10.188.132.60 mirror.ruopen.ru

The following lines are desirable for IPv6 capable hosts

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters



Ввод


Пример 3



  <th>
    Вывод
  </th>
</tr>

<tr>
  <td>
    <pre><span style="font-size: 10px;">127.0.0.1   localhost

127.0.1.1 pooh
87.250.250.203 foobarbaz.domain.tld foobarbaz
77.88.21.3 bar.domain.tld bar.mydomain.ru bar
10.188.132.60 mirror.ruopen.ru

The following lines are desirable for IPv6 capable hosts

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

  <td>
    <pre><span style="font-size: 10px;">127.0.0.1   localhost

127.0.1.1 pooh
87.250.250.203 foobarbaz.domain.tld foobarbaz
77.88.21.3 baz.donemain.tld baz.mydomain.ru baz
10.188.132.60 mirror.ruopen.ru

The following lines are desirable for IPv6 capable hosts

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters



Ввод


Пример 4



  <th>
    Вывод
  </th>
</tr>

<tr>
  <td>
    <pre><span style="font-size: 10px;">127.0.0.1   localhost

127.0.1.1 pooh
87.250.250.203 foobar.domain.tld foobar
2a02:6b8::11:11 bar.domain.tld bar
10.188.132.60 mirror.ruopen.ru

The following lines are desirable for IPv6 capable hosts

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

  <td>
    <pre><span style="font-size: 10px;">127.0.0.1   localhost

127.0.1.1 pooh
87.250.250.203 foobar.domain.tld foobar
2a02:6b8::11:11 baz.donemain.tld baz
10.188.132.60 mirror.ruopen.ru

The following lines are desirable for IPv6 capable hosts

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters



Ввод


Пример 5



  <th>
    Вывод
  </th>
</tr>

<tr>
  <td>
    <pre><span style="font-size: 10px;">127.0.0.1   localhost

127.0.1.1 pooh
87.250.250.203 foobar.domain.tld foobar
2a02:6b8::11:11 bar.domain.tld bar bar.mydomain.org
10.188.132.60 mirror.ruopen.ru

The following lines are desirable for IPv6 capable hosts

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

  <td>
    <pre><span style="font-size: 10px;">127.0.0.1   localhost

127.0.1.1 pooh
87.250.250.203 foobar.domain.tld foobar
2a02:6b8::11:11 baz.donemain.tld baz baz.mydomain.org
10.188.132.60 mirror.ruopen.ru

The following lines are desirable for IPv6 capable hosts

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters



Ввод


Примечания



Часть строк могут быть пустыми, в каждой строке текст после символа # считается комментарием и игнорируется. Вместо чтения стандартного ввода и записи в стандартный вывод допускается читать данные из файла input.txt и записывать в output.txt



Решение задачи


Так как мне было интересно поработать с файлами а не стандартным вводом и выводом, то я решил использовать для решения задач информацию из примечания. Здесь и далее читаем файл input.txt, пишем вывод в файл output.txt

import re
f = open(r’input.txt’)
lines = f.readlines()
f.close()
result = []
for line in lines:
regexpdomain = r’(.\s)(bar.domain.tld)(\s.)’
replacement = r’\1 baz.donemain.tld\3’
currentline = re.sub(regexpdomain, replacement, line)
regexpbar = r’(.)(\sbar)([\s|.].)’
replacement = r’\1 baz\3’
currentline = re.sub(regexpbar, replacement, currentline)
regexplastdomain = r’(.)(\sbaz.domain.ltd)(\s.)’
replacement = r’\1 baz\3’
currentline = re.sub(regexpbar, replacement, currentline)
result.append(currentline)
f = open(r’output.txt’, ‘w’)
f.writelines(result)
f.close()


Можно конечно было изменить количество проходов регуляркой, но мне было так удобнее, главное что валидационные тесты яндекса этот код прошёл.


Результат:






        <td>
          <div>
            Result
          </div>
        </td>

        <td>
          <div>
            Time
          </div>
        </td>
      </tr>

      <tr>
        <td>
          1
        </td>

        <td>
          <div>
            OK
          </div>
        </td>

        <td>
          <div>
            42ms / 2.9 MB
          </div>
        </td>
      </tr>

      <tr>
        <td>
          2
        </td>

        <td>
          <div>
            OK
          </div>
        </td>

        <td>
          <div>
            44ms / 2.9 MB
          </div>
        </td>
      </tr>

      <tr>
        <td>
          3
        </td>

        <td>
          <div>
            OK
          </div>
        </td>

        <td>
          <div>
            50ms / 2.9 MB
          </div>
        </td>
      </tr>
    </table>
  </td>

  <td align="left" width="" height="">
    <table>
      <colgroup> <col /> <col /> <col /></colgroup> <tr>
        <td>
          <div>
            Test
          </div>
        </td>

        <td>
          <div>
            Result
          </div>
        </td>

        <td>
          <div>
            Time
          </div>
        </td>
      </tr>

      <tr>
        <td>
          4
        </td>

        <td>
          <div>
            OK
          </div>
        </td>

        <td>
          <div>
            43ms / 2.9 MB
          </div>
        </td>
      </tr>

      <tr>
        <td>
          5
        </td>

        <td>
          <div>
            OK
          </div>
        </td>

        <td>
          <div>
            42ms / 2.9 MB
          </div>
        </td>
      </tr>

      <tr>
        <td>
          6
        </td>

        <td>
          <div>
            OK
          </div>
        </td>

        <td>
          <div>
            47ms / 2.9 MB
          </div>
        </td>
      </tr>
    </table>
  </td>

  <td align="left" width="" height="">
    <table>
      <colgroup> <col /> <col /> <col /></colgroup> <tr>
        <td>
          <div>
            Test
          </div>
        </td>

        <td>
          <div>
            Result
          </div>
        </td>

        <td>
          <div>
            Time
          </div>
        </td>
      </tr>

      <tr>
        <td>
          7
        </td>

        <td>
          <div>
            OK
          </div>
        </td>

        <td>
          <div>
            42ms / 2.9 MB
          </div>
        </td>
      </tr>

      <tr>
        <td>
          8
        </td>

        <td>
          <div>
            OK
          </div>
        </td>

        <td>
          <div>
            42ms / 2.9 MB
          </div>
        </td>
      </tr>

      <tr>
        <td>
          9
        </td>

        <td>
          <div>
            OK
          </div>
        </td>

        <td>
          <div>
            44ms / 2.9 MB
          </div>
        </td>
      </tr>

      <tr>
        <td>
          10
        </td>

        <td>
          <div>
            OK
          </div>
        </td>

        <td>
          <div>
            43ms / 2.9 MB
          </div>
        </td>
      </tr>
    </table>
  </td>
</tr>



Test


Как видно из репорта мы с этим кодом уложились в 1 секунду и 64мб памяти.


Яндекс КИТ 4 Задание 2: shadow. Сосчитать незаблокированных пользователей в shadow


Ограничения


Ограничение времени 1 секунда
Ограничение памяти 64Mb
Ввод
стандартный ввод
Вывод
стандартный вывод

Легенда

В текстовом (ASCII, unix) файле формата shadow задается информация о паролях и сроке действия учетных записей пользователей. Напишите программу, которая в подаваемом на стандартный вход файле формата shadow считает незаблокированные учетные записи и выводит их количество на стандартный выход.

Формат ввода

Каждая строка файла содержит 9 полей, разделённых двоеточиями (":";), в первом поле хранится имя пользователя, во втором — зашифрованный пароль. Заблокированные учетные записи содержат во втором поле символ "звездочка"; ("*";) или восклицательный знак ("!";).

Формат вывода

Неотрицательное число в текстовом десятичном виде в кодировке ASCII

Примечания

Записи с пустым полем пароля считаются незаблокированными. Вместо чтения стандартного ввода и записи в стандартный вывод допускается читать данные из файла input.txt и записывать в output.txt

Решение задачи

import re
f = open(r'input.txt')
lines = f.readlines()
f.close()
counter = 0
asterisk = 0
voskls = 0
for line in lines:
    res = line.split(":")
    res = [res[1]]
    for password in res:
        matchObj = re.match(r'.*(\*).*', password)
        if matchObj:
            asterisk = asterisk+1;
        matchObj = re.match(r'.*(!).*', password)
        if matchObj:
            voskls = voskls+1;
result = len(lines) - (voskls+asterisk)
f = open(r'output.txt', 'w')
f.write("%i" % (result))
f.close()

Результат:

Test
Result
Time
1
OK
41ms / 2.9 MB
Test
Result
Time
2
OK
43ms / 2.9 MB
3
OK
44ms / 2.9 MB
Test
Result
Time
4
OK
46ms / 2.9 MB
5
OK
44ms / 2.9 MB

И опять мы уложились в выделенные ресурсы.

Яндекс КИТ 4 Задание 3: nsswitch.conf. В nsswitch.conf установить приоритет преобразования имен через dns перед файлом hosts

Ограничения

Ограничение времени 1 секунда
Ограничение памяти 64Mb
Ввод
стандартный ввод
Вывод
стандартный вывод

Легенда

В файле nsswitch.conf задаются источники данных для службы имен библиотеки языка Си. Измените файл nsswitch.conf так, чтобы приоритет был у DNS.

Формат ввода

В строке файла, подаваемого на стандартный ввод, начинающейся со слова hosts, задается порядок преобразования имен в адреса. Если слово files в этой строке идет раньше слова dns — содержимое файла /etc/hosts имеет приоритет перед DNS (и наоборот). В строке могут встречаться и другие слова (например, ldap). В файле могут быть другие строки. Часть строк может быть комментариями (первый символ #).

Формат вывода

Все строки входного файла вывести на стандартный вывод в неизменном виде, кроме строки, начинающейся со слова hosts, в которой слово dns переставить на первое после слова hosts место.

Примечания

Вместо чтения стандартного ввода и записи в стандартный вывод допускается читать данные из файла input.txt и записывать в output.txt

Решение задачи

В данный момент оно проходит только часть тестов, его я не успел доделать, так как изначально не учёл что могут быть дополнительные директивы в строке hosts, например у dns’а бывает директива [!UNAVAIL=return].

import re
f = open(r'input.txt')
lines = f.readlines()
f.close()
tmplines = []

for line in lines:
    regexp = r'^hosts:\s*(.*)'
    res = re.findall(regexp, line)
    if res:
        #print res
        regdns = r'(.*)(files)(.*)(dns\s?\[?.*\]?) (.*)'
        regrepl = r'\g<1>\g<4> \g<2>\g<3>\g<5>'
        currentline = re.sub(regdns, regrepl, line)
        line = currentline
    tmplines.append(line)

f = open(r'output.txt', 'w')
f.writelines(tmplines)
f.close()

В этом коде нужно поправить регулярку, так как в случае если dns стоит последним, то оно не обрабатывается (кстати это мой первый опыт применения регулярок, до этого обходился без них).

Результат:

Test
Result
Time
1
OK
43ms / 2.9 MB
Test
Result
Time
2
OK
42ms / 2.9 MB
Test
Result
Time
3
WA
42ms / 2.9 MB

WA означает Wrong Answer, то есть что-то не правильно обработалось. В 3ем тесте как раз dns стоит в конце, спасибо саппорту яндекса за подсказку, сам я не сообразил ибо делал это в последние минуты возможности сдачи теста (почти в 12 часов ночи сидя на работе). Кстати из-за этого задания я и не смог поступить на КИТ.

Яндекс КИТ 4 Задание 4: mtr. В выводе mtr найти “худший”; маршрутизатор

Ограничения

Ограничение времени 1 секунда
Ограничение памяти 64Mb
Ввод
стандартный ввод
Вывод
стандартный вывод

Легенда

В выводе команды LANG=C mtr —report —report-cycles 9 —no-dns ya.ru найти строку с "худшими"; значениями. Искомой считается строка (в порядке приоритета):

  1. с наибольшим процентом потерянных пакетов
  2. с наибольшим стандартным отклонением (StDev) времени отклика
  3. с наибольшим средним временем отклика

Вывести номер этой строки.

Формат ввода

HOST: pooh                        Loss%   Snt   Last   Avg  Best  Wrst StDev
1.|-- 84.201.169.254             0.0%     9    1.3   1.3   1.0   2.4   0.5
2.|-- 37.9.74.134                0.0%     9    1.6  18.4   1.2 121.4  39.8
3.|-- 87.250.239.11              0.0%     9    3.5  14.6   1.5 110.1  35.8
4.|-- 87.250.239.45              0.0%     9    3.2   8.4   2.9  48.5  15.0
5.|-- 87.250.239.143             0.0%     9    8.1  21.2   2.3  73.4  24.1
6.|-- 87.250.250.203             0.0%     9    3.5  13.9   2.1  97.7  31.4

Формат вывода

2

Примечания

Вместо чтения стандартного ввода и записи в стандартный вывод допускается читать данные из файла input.txt и записывать в output.txt

Решение задачи

import re
f = open(r'input.txt')
lines = f.readlines()
f.close()
linestemp = []

for line in lines:
    regexp = r'^[\ ]{2}(\d*)\.(\|--)?\s*([A-z0-9\-\.\?]*)\s*([0-9\.]*)%?\s*([0-9\.]*)\s*([0-9\.]*)\s*([0-9\.]*)\s*([0-9\.]*)\s*([0-9\.]*)\s*([0-9\.]*)'
    res = re.findall(regexp, line)
    if res:
       linestemp.append(res[0])

def getMaxLost(list):
    result = []
    list.sort(key=sortByLosts)
    result.append(list[-1][0])
    result.append(list[-1][3])
    return result
def sortByLosts(input):
        return float(input[3])
def countMaxLost(list):
    counter = 0
    maxlost = getMaxLost(list)
    for elem in list:
        if elem[3] == maxlost[1]:
            counter = counter+1
    return counter

def getMaxStDev(list):
    result = []
    list.sort(key=sortByStDev)
    result.append(list[-1][0])
    result.append(list[-1][9])
    return result
def sortByStDev(input):
        return float(input[9])
def countMaxStDev(list):
    counter = 0
    maxlost = getMaxStDev(list)
    for elem in list:
        if elem[9] == maxlost[1]:
            counter = counter+1
    return counter

def getMaxAvg(list):
    result = []
    list.sort(key=sortByAvg)
    result.append(list[-1][0])
    result.append(list[-1][6])
    return result
def sortByAvg(input):
        return float(input[6])
def countMaxAvg(list):
    counter = 0
    maxlost = getMaxAvg(list)
    for elem in list:
        if elem[6] == maxlost[1]:
            counter = counter+1
    return counter

def getBad(listiems):
    if countMaxLost(listiems) > 1:
        if countMaxStDev(listiems) > 1:
            return getMaxAvg(listiems)
        else:
            return getMaxStDev(listiems)
    else:
        return getMaxLost(listiems)

result = getBad(linestemp)
toprint = result[0]
f = open(r'output.txt', 'w')
f.write("%s" % (toprint))
f.close()

Результат:

Test
Result
Time
1
OK
44ms / 2.9 MB
Test
Result
Time
2
OK
43ms / 2.9 MB
Test
Result
Time
3
OK
43ms / 2.9 MB
4
OK
43ms / 2.9 MB

Яндекс КИТ 4 Задание 5: nginx. Посчитать пиковое число запросов в секунду по журналу access.log веб-сервера nginx

Ограничения

Ограничение времени 1 секунда
Ограничение памяти 64Mb
Ввод
стандартный ввод
Вывод
стандартный вывод

Легенда

Веб-серверы записывают каждый запрос в файл стандартного формата access.log
В журнал access.log попадает время с точностью до секунды, в которое был выполнен запрос. В подаваемом на стандартный вход файле посчитайте максимальное число запросов в секунду, которое было получено сервером и выведите это число на стандартный выход.

Формат ввода

127.0.0.1 - - [02/Sep/2013:13:12:19 +0400] "GET /ubuntu/dists/precise/Release HTTP/1.1" 200 3011 "http://localhost/ubuntu/dists/precise/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/28.0.1500.71 Chrome/28.0.1500.71 Safari/537.36"
10.10.10.10 - - [02/Sep/2013:13:12:36 +0400] "GET / HTTP/1.0" 200 612 "-" "-"
10.10.10.10 - - [02/Sep/2013:17:45:36 +0400] "GET /ubuntu/dists/precise/Release HTTP/1.1" 200 3011 "-" "Wget"
10.10.10.10 - - [02/Sep/2013:17:45:36 +0400] "GET /ubuntu/dists/precise/main/binary-i386/Release HTTP/1.1" 200 96 "-" "Wget"

Формат вывода

2

Примечания

Вместо чтения стандартного ввода и записи в стандартный вывод допускается читать данные из файла input.txt и записывать в output.txt Каждый запрос занимает в файле одну строку, при отображении примера журнала в броузере последняя строка может ошибочно быть "разорвана";.

Решение задачи

import re
f = open(r'input.txt')
lines = f.readlines()
f.close()
maximal = 0
templines = {}
for line in lines:
    regexp = r'^(.*) - -\s\[(.*)\]\s(.*)'
    key = re.findall(regexp, line)
    key = key[0][1]
    if templines.has_key(key):
        templines[key] = templines.get(key) + 1
    else:
        templines[key] = 1;
for timeuse in templines:
    if templines[timeuse] > maximal:
        maximal = templines[timeuse]
f = open(r'output.txt', 'w')
f.write("%i" % (maximal))
f.close()

Результат:

Test
Result
Time
1
OK
43ms / 2.9 MB
Test
Result
Time
2
OK
58ms / 2.9 MB

Заключение

Вот как то так всё это и делалось. Как только руки дойдут попробую доделать задание 3, и проапдейтить этот пост.  Хоть я и не смог поступить на КИТ, однако для меня это стало хорошим началом для изучения python.

Буду благодарен за конструктивную критику кода, советы и рекомендации.

Комментарии

comments powered by Disqus