Переписывание IBM на ассемблере + COBOL на C ++


13

Я работаю агентом / менеджером по прокату в компании по прокату автомобилей, работающей по системе проката, написанной в 1972 году. Я решил, что, возможно, пришло время обновить информацию. Для некоторой предыстории, вот короткий пример безумия, с которым нам приходится сталкиваться из этой программы ежедневно:

Агент по прокату должен помнить, что для печати на одном экране используется поле «MXC» в поле ACT (все основано на коротких кодах), что озадачивающе обозначает «Отображение MaXimum в контракте», в то время как на другом оно требует PR (для PRint) в поле ДЕЙСТВИЕ, но на нескольких экранах используется Y в поле PT (для PrinT), еще один экран использует Y в поле PRT (для PRinT), и еще один экран требует, чтобы пользователь нажимал ввод (но не ввод рядом с буквы, так как это новый символ строки, это должно быть ввод на цифровой клавиатуре), а затем F8, другой, но связанный экран требует просто F8, некоторые экраны имеют поле, помеченное PRT, которое должно быть для PRinT, но поле фактически ничего не делает, и печать выполняется автоматически после прохождения нескольких запросов, и еще больше экранов имеют поле, помеченное PRINT Y / N,который по умолчанию безразличен к Y для операций, в которых другое место уже доставляет документы, и к N для операций, в которых другому дилеру понадобятся документы.

Я решил, что смогу справиться с этой работой лучше, поэтому решил связаться с человеком в компании, который примет решение обновить его. В конце концов я связался с вице-президентом по ИТ, который отвечает за эту программу. Я извлекаю из него немного информации и узнаю, что у моей компании по прокату автомобилей написана программа проката на ассемблере мэйнфреймов IBM с небольшим количеством COBOL. Он говорит, что в данный момент открытых вакансий нет, но я должен В любом случае, отправьте ему по электронной почте мое резюме (на случай, если что-то откроется).

Это приводит меня к моим вопросам.

Первый - технический. С идеей улучшения сопровождения в будущем я думаю переписать его на языке более высокого уровня, чем на ассемблере. Мой опыт работы в C ++, так что для меня это очевидный выбор. Компания остро нуждается в более простом способе обновления программы, так как я недавно прочитал статью, в которой говорится, что человек, с которым я говорил, говорит, что команда усердно работала, и они с гордостью сообщают, что в программе теперь есть поддержка 5 -значные коды местоположения (вместо 4) и 8-значные автомобильные номера (вместо 7). Моя философия в отношении обновлений, даже в таких тяжелых ситуациях, соответствует философии Джоэла: http://www.joelonsoftware.com/articles/fog0000000069.html короче говоря, переписывание должно быть постепенным, а не выбрасывать все, что было раньше и начать все заново.

Существует ли простой способ интеграции сборки IBM с C ++, и если да, то как мне это сделать? Я смутно осведомлен о ключевом слове asm, но я не знаю, лучше ли использовать это или сделать что-то еще. Является ли такой план необоснованным? Я делаю большую часть своей работы над Linux с использованием g ++ и GNU make, поэтому ответы на эти вопросы приветствуются, но определенно не обязательны (поскольку я понятия не имею, какой системы сборки у них нет, но я подозреваю, что почти нет).

Второй вопрос более политический. Как мне убедить эту компанию в том, что им нужно переключиться? Теоретическая экономия затрат огромна (по моим оценкам, компания тратит дополнительно около миллиона долларов в год, просто на увеличение затрат на обучение, чтобы научиться взаимодействовать с программой), но мои предложенные изменения, вероятно, поставят все текущие программисты без работы, если они будут приняты, так что существует большое структурное сопротивление изменениям.

редактировать: я должен объяснить, почему мне изменить то, что компания уже имеет, кажется лучшим решением для меня. Я все еще открыт для других предложений, потому что это монстр программы, однако. У меня никогда раньше не было работы по программированию, поэтому, пожалуйста, исправьте меня в любом неправильном анализе, который я могу дать.

Во-первых, это готовое решение.

Из моих бесед с несколькими менеджерами среднего звена о подобных вещах одной из главных проблем при переходе на новую систему является большое количество лояльных сотрудников, которые работают в компании десятилетиями и уже знакомы с системой. , Если бы у меня была возможность изменить то, что у нас есть, я мог бы поддерживать текущий интерфейс в своего рода «режиме совместимости». Пользователи уже должны войти в систему, чтобы использовать текущую систему, поэтому я мог бы добавить возможность активировать настройку, когда пользователи входят в систему «в первый раз» (после того, как я сделаю это изменение), где им предоставляется возможность использовать либо «классический» интерфейс или «новый» интерфейс. Я не найду готовое решение, которое позволяет это,

Моя компания также владеет программным обеспечением, которое мы используем; мы не лицензируем это. Это означает, что менеджмент, с которым я сейчас разговариваю, - это те же люди, которые могут на самом деле разрешить мне внести изменения. При использовании стороннего решения мне нужно было бы получить одобрение от моей компании в дополнение к обеспечению любых необходимых прав со стороны компании, которая разработала продукт, который мы используем, что добавляет дополнительное препятствие. Это также потребовало бы от компании убеждения отказаться от «своего» продукта и взять какой-то другой продукт, что кажется большим препятствием, чем попытка обновить то, что у нас есть, но я вполне могу ошибаться в этом вопросе.

Наконец, заглядывая в будущее, я не просто хочу улучшить пользовательский интерфейс и исправить несколько ошибок. После того, как я обновлю эти «срочные» вопросы, я надеялся обновить фундаментальный подход компании к технологии. Потратив 1-2 года на решение подобных проблем, я планировал вернуться к руководству и предложить более радикальные изменения. Есть много способов работы компании, которые могут быть существенно улучшены с помощью технологий, которые они просто не используют прямо сейчас. Например, каждый регион в значительной степени работает одинаково. Местный крупный аэропорт является центральным центром распространения автомобилей. Они в основном отправляются по мере необходимости. Тем не менее, аэропорт используется в качестве домашней базы для всех операций. Они отправят двух человек в одной машине ко мне, чтобы забрать у нас одну машину, которая нам не нужна, затем вернитесь в аэропорт с автомобилем, на котором они приехали, плюс то, что они забирают обратно (мы в 32 милях от аэропорта). Затем они приедут на расстоянии 5 миль от нас на двух машинах, чтобы отвезти одну из них, а затем вернутся на другой машине в аэропорт. Они делают это, даже если машина, которую мы отослали, - та же самая машина, которая им нужна рядом с нами. Я работаю в компании около двух лет, и мне кажется, что они отклоняются от этого только в самых экстремальных ситуациях нехватки автомобилей (примерно три раза). Я бы заменил 4 человек, работающих в каждом регионе, на автоматизированную систему планирования, которая определяет, куда едут машины, и постараюсь найти путь, который потребует наименьшего количества времени + мили + водителей, чтобы доставить все машины туда, где они должны быть, как пример исправлений более высокого уровня надеюсь когда-нибудь добавить.

Однако, прежде чем мне будет удобно предлагать все это, я чувствую, что было бы полезно получить контроль над компанией и базой кода, выполняя меньшие задачи, такие как обновление интерфейса. Такие решения, как аутсорсинг или иное, устранят эту возможность.


3
Посмотрите на эмулятор Hercules - в основной ОС мэйнфрейма IBM много магии, которую нужно эмулировать.
Ян Рамин

Я бы честно посмотрел на «повторить с начала» (плохая шутка C64). Если серьезно, проверьте спецификации и посмотрите, что может потребоваться для написания нового графического интерфейса самостоятельно. Пока интерфейс базы данных одинаков, и это займет много времени и исследований, чтобы определить, тогда вы великолепны и готовы заработать $ # && денег :)

8
Если текущая система действительно работает, у вас должна быть очень веская причина, чтобы заплатить за клиента. Кроме того, вы, скорее всего, будете сильно недооценивать объем работы, необходимый для воспроизведения текущей системы - просто подумайте, что сначала вам нужно полностью понять текущую систему - сделав переписывание еще более дорогим, чем первоначальная оценка. Это не для того, чтобы вас обескуражить, а просто для того, чтобы вы действительно знали, какую именно задачу вы можете подписать, ДО того, как вы не сможете отступить. Кроме того, сделайте свою работу добавочной - другими словами, пока оставайтесь на мейнфрейме.

Я боюсь, что эмуляция системы будет очень трудной, что привело меня к поиску способа внесения небольших модульных изменений, а не попыток начать с нуля.
Дэвид Стоун

@David Stone Я когда-то был в проекте, мы сделали «выбрать новый или старый интерфейс». Он быстро пошел в ад разработки - код был тесно связан с интерфейсом, и быстро if (m_newInterface)код спагетти начал появляться по всей базе кода. Разъединение и рефакторинг заняли достаточно много времени, и, когда это было сделано, большинство пользователей уже перешли на новый интерфейс (думаю, несколько лет).
Vitor Py

Ответы:


4

Ограничиваясь техническим фронтом ...

Я предлагаю вам начать с определения среды, в которой работает приложение. «Мэйнфрейм» может означать несколько разных вещей, учитывая возраст приложения, это может быть CICS или IMS . Также возможно, что авторы оригинала написали свое собственное задание.

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

Что еще нужно учитывать, учитывая возраст приложения, так это то, что Ассемблер, с которым вы хотите интегрировать C ++, предшествовал существованию языковой среды (LE). Таким образом, если ассемблер не был обновлен для соответствия требованиям LE, у вас будут некоторые трудности, так как C и C ++ соответствуют LE и требуют, чтобы их вызывающие и вызывающие абоненты также соответствовали.

Еще один момент для рассмотрения: если это приложение работает на умирающем мэйнфрейме, возможно, вы пытаетесь интегрироваться с приложением, которое работает на неподдерживаемом аппаратном и программном обеспечении. Это мало чем отличается от попытки интеграции с приложением, написанным в 1989 году и работающим на DOS 4.01 на его оригинальном оборудовании.


Приложение может даже использовать TPF , что сделает преобразование чрезвычайно трудным.
Гилберт Ле Блан

13

Вы прыгаете пистолет. Из вашего описания видно, что вы не до конца поняли текущую техническую среду (какая конкретно ОС, где и как хранятся данные, существуют ли интерфейсы к другим системам и т. Д.). Но еще более важно: серьезный план должен учитывать альтернативы частичной или полной внутренней переписке программного обеспечения, а именно готового программного обеспечения, переписывания сторонних продуктов, программного обеспечения как услуги и т. Д.

Каким бы ни был путь компании, в первую очередь, ей необходим тщательный анализ того, что сегодня делает программное обеспечение и каковы требования к новому решению.

Так почему бы вам не предложить этот анализ?


7
+1 Это единственный ответ, который предлагает полный анализ существующих приложений и требований компании, прежде чем предлагать техническое решение. Напоминает мне старую шутку: ты начинаешь кодировать - я пойду узнаю, чего они хотят.

Это хороший момент, и мне определенно нужно больше информации, прежде чем я начну выполнять эту работу. Отчасти проблема в том, что я спрашивал, и только когда я связался с вице-президентом компании, я нашел кого-то, кто действительно знал какие-либо детали. Я позвонил в несколько офисов, в том числе в службу технической поддержки, и ни один из них не смог рассказать мне, например, на каком языке программирования была написана программа. Однако у меня есть некоторые причины для отказа от готового решения, которое я отредактирую в мой оригинальный вопрос.
Дэвид Стоун

7

Я удивлен, что вы получили такой вежливый ответ!

Давайте посмотрим на это с их точки зрения.

Они успешно управляют тридцатилетней системой, возможно, с сотнями тысяч строк кода, интерфейсами, возможно, с двадцатью другими системами, которые воплощают бизнес-процессы, которые развивались в течение сорока лет.

Вероятно, они, вероятно, являются экспертами в своей области, и поэтому считают C ++ шагом вниз по сравнению с «High Level Assembler Language» от IBM, дав ему полное название. Язык ассемблера IBM чрезвычайно мощный, а язык "MACRO" - лучшая реализация языка предварительной обработки / шаблонов.

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

C ++ просто не поможет. В среде, где работает приложение, нет графической библиотеки. (Существует графическая библиотека 3270, но она вряд ли будет поддерживаться в C ++, так как никто не использует ее, и есть полная клиентская библиотека "X", но для ее использования вам необходимо находиться в другой среде.)

У них есть пользовательский интерфейс, который далек от совершенства, но хорошо известен и быстр. Опытный оператор заполняет форму примерно в три раза быстрее, используя зеленый экран, а не эквивалентный графический интерфейс. Плюс они могут обратить внимание на клиента, пока они касаются типа.

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


4

У меня была похожая проблема несколько лет назад в BellSouth. Я просто написал код на языке COBOL для сканирования программ на ассемблере побайтно, выделил коды операций и операнды, преобразовал команды перехода в переходы и преобразовал инструкции сравнения в IF. Эта программа преобразовывала инструкции DC в эквивалентный код деления данных COBOL и, при необходимости, преобразовывала ходы, zaps и т. Д.

Как только это было сделано, я написал вторую программу для преобразования IF и GOTO в IF-THEN, с перемещениями и тому подобным в линиях между этими кластерами (на самом деле это было не так уж сложно - секрет заключается в том, чтобы вставить IF и В противном случае, когда вы перечитываете 1-й этап "пиджин" кобол "задом наперед").

IF-THEN-ELSER искал ситуации, когда он находил ссылку GOTO в непосредственной близости от метки, которую можно было безопасно удалить (уменьшив количество ссылок на 1). Вы запускаете эту программу IF-THEN-ELSER итеративно (то есть вы запускаете ее снова и снова, останавливаясь только тогда, когда ваш последний проход не может найти способ внести какие-либо изменения). Большая часть критической работы выполняется этим if-then-elser, чей продукт на COBOL должен быть тщательно проверен и проверен опытным, компетентным программистом на языке ассемблера (а именно, мной). По моему опыту, мое «если-то-эльзер» смогло устранить более 90 процентов GO TO, вытекающих из исходных инструкций ветвления.

Я полагаю, что с этого момента можно перейти к прямому преобразованию в C (или C ++) - языки, с которыми я также знаком. Однако в BellSouth нашим целевым языком был COBOL / II. Всегда есть небольшая сложность, которая возникает в ситуациях, когда у оставшейся метки есть несколько ссылок GO TO (много раз, эти ситуации обрабатываются с помощью COBOL PERFORMs, но иногда могут быть просто представлены конструкциями OR и AND).

Я думаю, что было бы неплохо создавать код в элегантно блочной структуре COBOL / II с EVALUATE (конструкциями Case) и 88 условными именами уровня. Добавление этих завершающих штрихов привело к другой паре программ, которые оказались полезными для программ на языке COBOL, а не для программ, преобразованных из ассемблера.

Я не знаю, поможет ли это.

Как уже отмечали другие, вы должны вести этот процесс с осторожностью. Это помогает иметь 10-12-летний опыт программирования на ассемблере, информируя ваши процессы принятия решений. Нам, имеющим этот опыт, трудно найти больше.

И последнее замечание: тогда мы писали только на ассемблере, потому что компиляторы для языков высокого уровня создавали громоздкий, неэффективный объектный код. Сегодняшние «оптимизирующие» компиляторы COBOL не имеют таких же вредных привычек. ----------


2

Совет Джоэла, как правило, здравый, но в этом случае полная перезапись просрочена. В идеале, переписать с боевым топором, так как то, с чем вы имеете дело здесь, является монстром.

Я не уверен, что именно добавить, так как вы уже привели достаточно веские аргументы в пользу этого. Моя единственная рекомендация - полностью пропустить C ++ и перейти прямо к веб-интерфейсу системы аренды, так как это, вероятно, будет еще проще для подготовки рабочих и сэкономит вам большую часть работы над пользовательским интерфейсом (а также намного легче получить новую кровь в проекте или даже просто отдать все это на аутсорсинг).

Что касается существующих программистов на COBOL - возможно, они могут помочь с документированием существующей системы и с процессом миграции.


2
+1: это не работа для C ++
6502

2
@ 6502: почему бы и нет? Опыт ОП в C ++. Выяснить, как бороться со старой системой, достаточно плохо. Изучение другого языка не поможет. Компетентный программист, использующий инструменты, которые программист компетентен, сможет заставить его работать намного лучше, чем старая система, независимо от языка.
In silico

1
@ In silico: По моему мнению, для достаточно большого проекта такого размера вы сэкономите время, изучая более подходящий язык, например, Python, чем C ++. Предположим, что Python там не было, для достаточно большого проекта такого рода IMO окупится написанием вашего собственного Python на C ++ и его кодированием с использованием этого вместо того, чтобы делать все это на C ++. C ++ - очень приятный язык, и его сильная сторона в том, что дизайн не хочет оставлять места под C ++ и над ассемблером. Совершенно бессмысленно здесь. Вы бы предложили написать все, используя ПЛИС, если бы это была область знаний автора?
6502

3
@ 6502: я не согласен. С надлежащей, современной техникой, хорошо спроектированными библиотеками и знанием языка все эти вопросы не имеют значения. (Это верно для любого языка, конечно.) И люди разработали крупномасштабные системы и программное обеспечение на C ++, которое работает просто отлично и, похоже, не имеет проблем с использованием C ++. Тот факт, что вы не будете использовать C ++ для этой работы, не означает, что другие не смогут использовать его и использовать его хорошо. Это для ОП, чтобы решить. Я уверен, что вы достаточно продуктивны на других языках, и обязательно продолжайте в том же духе.
In silico

1
In silico: Очевидно, что теоретически все может быть реализовано с чем угодно (включая brainf k). Это не значит, что все инструменты эквивалентны. Я думаю, что для бизнес-приложения, имеющего код, который легко писать и читать (даже не специалистам), гораздо важнее скорости вычислений. Также что-то вроде неопределенного поведения - слишком высокая цена, чтобы платить за ненужную близость к металлу. Если для вас C ++ является хорошим выбором для бизнес-логики в качестве приложения для ввода данных, то мне интересно, есть ли для вас ** что-нибудь, для чего C ++ является плохим выбором ...
6502

2

Что касается технического аспекта, многое будет зависеть от качества - модульности - кода ассемблера. Некоторые программисты понимали важность создания модулей с конкретными, ограниченными функциями и понятным, простым параметризованным интерфейсом, используя стандартные соглашения о связях подпрограмм IBM. Однако подавляющее большинство, как правило, создавало монолитные чудовища.

С первым вариантом возможно повторное использование, и не должно быть так сложно разобраться в «склеивании» между C ++ и ассемблером, при условии, что ваши модули ассемблера используют стандартные (или, по крайней мере, согласованные) последовательности вызова. Однако, по всей вероятности, ассемблерный код будет беспорядочным. Хотя можно было написать структурированный ассемблер, мало кто так делал, и почти невозможно будет различить какой-либо «дизайн», с которого можно начинать переписывание.

С другой стороны, ассемблер 360/370 является довольно высокоуровневым по сравнению с современными микропроцессорами и намного проще, и C иногда считается «ассемблером высокого уровня». Я работал в компании СУБД, чей продукт был полностью ассемблерным, и наш главный архитектор полагал, что машинный код ассемблера можно будет перевести на C (для будущей переносимости). Я скептически отношусь, но дело в том, что расстояние не такое большое, как вы думаете.

Не знаю, полезно ли это. Как я уже сказал, я думаю, что это сильно зависит от качества и размера исходного кода.


1

Я не могу сказать, шутка ли это или нет - ваша компания серьезно работает над кодом, изначально написанным 39 лет назад? Если он работает в System / 360, вам придется скомпилировать g ++ из исходного кода ...

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

Что касается убеждения компании в том, что вам нужно переключиться, вам нужно указать на конкретные причины, которые повысят эффективность, приведут к снижению затрат и / или покажут, что то, что вы используете сейчас, в настоящее время наносит некоторый вред.

Еще один комментарий - я думаю, что другие компании по прокату автомобилей присоединились к остальным из нас в 21 веке; Я хотел бы немного подумать, чтобы увидеть, как они это делают (я полагаю, на веб-основе), и, возможно, смоделировать это после одной из этих систем (то есть, не изобретать колесо).

Удачи!


5
Для систем мэйнфреймов весьма распространено использование кодовых баз, начатых в 60-х или 70-х годах. Именно благодаря этому IBM поддерживает свои мэйнфреймы zSeries и ОС, обратно совместимые с 360. В бизнес-модели компании по прокату автомобилей (или банка, или страховой компании) ничего не изменилось с тех пор. Конечно, вы можете добавить веб-интерфейс, но что изменилось в способе хранения автомобилей в базе данных?
Бо Перссон

У zOS есть собственный компилятор C ++ в комплекте с препроцессорами для CICS и DB2. Так что нет необходимости в g ++.
Джеймс Андерсон

5
Во-вторых, для крупных корпораций довольно распространено использование мэйнфрейм-кода 30-летней давности. Это в целом надежно, производительно и делает свою работу. Это также имеет тенденцию быть очень плохо документированным.
Джеймс Андерсон

3
@ Крис, почему 39-летний код не должен быть запущен? Это становится устаревшим в 30? 20? Испытанный в бою производственный код может быть старым, но все же отлично справляться с работой. Любое переписывание нужно , чтобы добраться до того же уровня, что и старая программа , прежде чем он имеет какие - либо преимущества в одном оплате сборов.

1
@ Крис, совсем немного быстрее, чем хорошо написанное приложение «зеленого экрана», и я знаю это по личному опыту, будучи парнем из Java в магазине Cobol. Я искренне верю, что вы все искренне недооцениваете объем работы, необходимой для подачи аналогичного заявления. Кроме того, код не ржавеет. Просто быть старым не является достаточной причиной, чтобы это исправить.

0

Теоретически не должно быть труда убедить высшее руководство заменить старую систему, если вы можете показать им, что это спасет их мегабакс. И это будет. Все труднее будет найти программистов для обслуживания этой системы, и эти программисты будут становиться все дороже и дороже. Это не вопрос «если», это вопрос «когда». Это действительно должно быть обновлено.

Однако вопрос заключается в том, можете ли вы убедить их не только в том, что он нуждается в обновлении (и они, вероятно, знают об этом в любом случае), но в том, что это должен быть внутренний проект. Особенно если в команде только ты. Довольно часто такая важная замена передается на аутсорсинг. Может даже быть какое-то готовое программное обеспечение, доступное для рассмотрения. Эти варианты необходимо изучить, и ваши менеджеры будут настаивать на том, что произойдет, если они разумны.

Что касается задачи, то, если бы вы это сделали, я действительно считаю, что в этом случае может быть уместным переписывание бульдозером. Аргумент Джоэла не применим в каждом случае. Однако я не мог знать, не видя этого.


0
  1. О дополнительных изменениях не может быть и речи.

  2. Вероятно, будет доступно готовое решение. Есть много предприятий по прокату автомобилей.

  3. Если в качестве последнего средства вам нужно переписать его, сначала потратьте некоторое время на размышления о том, как будет работать новая система.
    После того, как вы определили функциональность и интерфейсы, вы можете выбрать инструменты разработки, которые лучше всего соответствуют потребностям (и вашим навыкам).

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

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


1
Если вы не сделаете это постепенно, проект, скорее всего, потерпит неудачу.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.