Нетронутый и уникальный код Боулинг


82

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

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

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

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


Вот полное определение нетронутой программы, скопированное по ссылке выше:

Давайте определим нетронутую программу как программу, которая сама по себе не имеет ошибок, но выдаст ошибку, если вы измените ее, удалив любую смежную подстроку из N символов, где 1 <= N < program length.

Например, трехсимвольная программа Python 2

`8`

является нетронутой программой, потому что все программы, возникающие в результате удаления подстрок длины 1, вызывают ошибки (на самом деле синтаксические ошибки, но могут быть ошибки любого типа):

8`
``
`8

а также все программы, возникающие в результате удаления подстрок длины 2, вызывают ошибки:

`
`

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


37
Снимаю шляпу перед вами за то, что вы смогли создать хороший боулинг-код !
ETHproductions

Если подпрограмма выполняется вечно, но не содержит ошибок, делает ли это ответ недействительным?
Дилнан

1
@dylnan «ошибка определяется как [...] прекратить [...] после конечного количества времени.»
user202729

3
@Baldrickk Нет, это не будет разрешено для этого вызова. (Если вы ссылаетесь на пример в вопросе, это демонстрация того, что такое нетронутая программа, но которая не удовлетворяет дополнительному требованию уникальных байтов.)
Эйдан Ф. Пирс,

1
Можем ли мы считать неопределенное поведение ошибкой, если на практике это обычно приводит к ошибке? Я думаю о чем-то похожем JMP <address outside of the program's memory>на сборку. В принципе, на реальном компьютере он может бесконечно зацикливаться или завершаться с ненулевой ошибкой, но обычно он вылетает эффектно.
Крис

Ответы:


23

Желе , 253 254 256 байт

M“¢£¥¦©¬®µ½¿€ÆÇÐÑ×ØŒÞßæçðıȷñ÷øœþ !"#%&'()*+,-./0145689:;<=>?@ABCDEFGHIJKNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|~¶°¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ƁƇƑƓƘⱮƝƤƬƲȤɓƈɗƒɠɦƙɱɲƥʠɼʂƭʋȥẠḄḌẸḤỊḲḶṂṆỌṚṢṬỤṾẈỴẒȦḂĊḊĖḞĠḢİĿṀṄȮṖṘṠṪẆẊẎŻḅḍẹḥịḳḷṃṇọṛṣṭụṿẉỵẓȧḃċḋėḟġḣŀṁṅȯṗṙṡṫẇẋẏż”L»«’Ɗạ‘}237$¤¡

Попробуйте онлайн! или проверить это!

Оказывается, языки игры в гольф могут чаша ...

  • +1 байт, работая в . Сейчас только «»не используются
  • +2 байта с с «». Теперь получите оптимальный результат!

Как?

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

Структура программы выглядит следующим образом:

M <239 character long string> L»«’Ɗạ‘}237$¤¡

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

Чтобы предотвратить Mдействие 0в полной программе, мы используем команду ¡quick, которая применяется Mнесколько раз, определяемых результатом ссылки, непосредственно предшествующей ей. В этом случае эта ссылка есть <239 character long string> L»«’Ɗạ‘}237$¤.

Lберет длину этой строки (239) и »«’Ɗуменьшает ее до 238. »«Часть ничего не делает, но Ɗ(последние три ссылки как монада) делает так, что если они будут удалены, произойдет ошибка. Затем берется абсолютная разница между результатом »«’Ɗи монадой, ‘}237$примененной к строке. увеличивается и является монадой, но }превращает это в диаду и применяет ее к правильному аргументу 237, уступая 238. Таким образом дает 0в полной программе.

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

Возможные подпрограммы:

  • Если какая-либо часть строки будет удалена, <string>..¤она будет отлична от нуля и Mбудет применена к ней 0, что приведет к ошибке.
  • Если какая-либо часть L»«’Ɗạ‘}237$будет удалена, то Mбудет применена 0или между строкой и числом будут операции, в результате чего TypeError.
  • Если какой-либо из ¤¡удален, Mприменяется к 0.
  • Если закрывающий символ строки и оба из них ’‘удаляются и не удаляются , все после Mпревращается в строку, поэтому Mбудет действовать 0.
    • Если строка закрывает символ и удаляется и не удаляется , все между и превращается в список целых чисел.
  • Если Mодин удален, есть a, EOFErrorпотому что ¡ожидает ссылку перед предыдущим nilad.
  • Если M“и любое количество символов после его удаления, будет, EOFErrorпотому что ¤ищет предшествующую ему ниладу, но не находит ее. 238не считается, потому что это часть монады.

Это в значительной степени охватывает все.

Ранее я не использовал, «»‘потому что последние два не могут быть включены в строку, потому что они соответствуют символу, чтобы сформировать вещи, отличные от строк. «не может быть в “”строке, но я не знаю почему.


31

Haskell , 39 45 50 52 60 байт

main=do{(\𤶸	陸 ⵙߜ 新->pure fst)LT
EQ[]3
2$1}

Идентификатор mainдолжен иметь тип IO aдля некоторого типа a. Когда программа выполняется, вычисление mainвыполняется, и его результат отбрасывается. В этом случае его тип IO ((a,b)->a).

Результатом является применение функции (λ a b c d e f → return fst), константы с шестью аргументами, возвращающей функцию fst (которая дает первый элемент 2-кортежа), введенной в монаду IO. Шесть аргументов LT(перечисление меньше чем), EQ(перечисление равенства), пустой список [], 3, 2и 1.

То, что будет пробелами, заменяется уникальными символами, которые считаются пробелами: табуляция, неразрывный пробел, подача формы, вертикальная табуляция, OGHAM SPACE MARK, обычный пробел, перевод строки и возврат каретки. Если какой-либо из них отсутствует, будет иметь место несоответствие в количестве аргументов. Имена параметров выбираются как трех- или четырехбайтовые символы UTF-8 𤶸陸ⵙ商ߜ新, тщательно выбирая символы, которые не приводят к дублированию байтов.

Спасибо @BMO за его ценный вклад.

Шестнадцатеричный дамп:

00000000: 6d61 696e 3d64 6f7b 285c f0a4 b6b8 09ef  main=do{(\......
00000010: a793 c2a0 e2b5 990c e595 860b df9c e19a  ................
00000020: 80e6 96b0 2d3e 7075 7265 2066 7374 294c  ....->pure fst)L
00000030: 540a 4551 5b5d 330d 3224 317d            T.EQ[]3.2$1}

Попробуйте онлайн!


Хм, '\109999'похоже, действительно, по крайней мере, в GHC 8.2.2. '\10999a'выдает лексическую ошибку.
chepner

@chepner: Я только что протестировал с GHC 8.2.2 и также 𚶯выдает лексическую ошибку.
ბიმო

2
@chepner: крупнейший полукокс maxBound :: Char, т.е. '\1114111'. Примечание: цифры десятичные по умолчанию, так что если вы хотите , шестигранника, вы должны Погружаете xпосле того , как \ , например '\x10999a'.
Ними

@nimi Aaa, и я думаю, что мы установили, как часто я на самом деле использую экранирование Unicode :) Использование правильной формы для шестнадцатеричных значений, \x10ffffработает нормально и \x110000выдает ошибку вне допустимого диапазона, как и следовало ожидать.
chepner

25

Python 2 ,  20 21 33 39 45  50 байт

Сейчас очень много совместных усилий!

+2 благодаря Эйдану Ф. Пирсу (заменить sorted({0})на map(long,{0}))

+8 благодаря dylnan (использование \и новая строка для замены пробела; предложения перейти от 0математического выражения; замена -1на -True; использование шестнадцатеричного числа)

+11 благодаря Angs ( 4*23+~91-> ~4836+9*1075/2потом позже ~197836254+0xbCABdDF-> ~875+0xDEAdFBCbc%1439/2*6)


if\
map(long,{~875+0xDEAdFBCbc%1439/2*6})[-True]:q

Попробуйте онлайн! Или посмотрите пакет подтверждения

0xDEAdFBCbcявляется шестнадцатеричным и оценивается как 59775106236.
~является побитовым дополнением, поэтому ~875оценивает -876.
%является оператором по модулю, поэтому 0xDEAdFBCbc%1439оценивается в 293.
/целочисленное деление, так что 0xDEAdFBCbc%1439/2оценивается как 146.
*умножение, так что xDEAdFBCbc%1439/2*6оценивается в 876.
+это дополнение, так что ~875+xDEAdFBCbc%1439/2*6оценивает 0.
... без зачистки версия также оценивается как 0.

{0}является setсодержащим единственным элементом, 0.

Вызов sortedс setаргументом a приводит к получению списка, который может быть проиндексирован с помощью [...].

Без sortedкода ({0})просто выдаст, setи это не может быть проиндексировано таким же образом, if({0})[-True]:qподнял бы TypeError.

Индексирование в Python основано на 0 и допускает отрицательное индексирование с обратной стороны и Trueэквивалентно 1, следовательно, sorted({0})[-True]находит элемент 0, в то время как sorted({0})[True]вызовет IndexError, так как будет sorted({})[-True]и sorted({0})[]недопустимый синтаксис.

0, Который находится в falsey так теле if, q, никогда не выполняется, однако , если бы это было приподнять , NameErrorтак как qне была определена.

Так как непустой список является правдивым, мы не можем урезать if[-1]:qни то, ни другое.

Посмотрите комплект подтверждения, чтобы увидеть: подтверждение того, что байты уникальны; все ошибки; и успех самого кода.


17

C (tcc) , x86_64, 29 31 33 39 40 байт

main[]={(23*8),-~0xABEDFCfebdc%95674+1};

Возвращает 0 . Спасибо @feersum за предложение прописных шестнадцатеричных цифр.

Попробуйте онлайн!

Как это устроено

Присвоение записывает два целых числа ( 184 и 49664 ) в ячейку памяти main . С 32-битными целыми числами и порядком байтов с прямым порядком байтов точные байты равны b8 00 00 00 00 c2 00 00.

Поскольку tcc не объявляет определенный массив как .data ( как это делает большинство компиляторов), поэтому переход к main выполняет машинный код, на который он указывает.

  • b8 00 00 00 00( mov eax, imm32) сохраняет int 0 в регистре eax.

  • c2 00 00( ret imm16) выталкивает 0 дополнительных байтов из стека и возвращает. (Значение в регистре eax является возвращаемым значением функции).


Ссылка TIO показывает ошибку сегментации для меня.
pppery

15

> <> , 122 байта

e"~l=?!z6-d0p}xwutsrqonmkjihgfcba`_]\[>ZYXWVUTSRQPONMLKJIHGFEDCB@<:98754321/,+*)('&%$# .	|{Ay

Попробуйте онлайн!

Ничего не делает. Основано на том же формате, что и мой ответ « Программирование нетронутого мира» .

Сначала мы проверяем, что длина кода равна 122, и, если это не так, выдают ошибку. ><>Программы не могут завершиться без использования ;команды, но если эта команда находится в программе, мы можем просто удалить все перед ней, чтобы программа немедленно завершилась. Чтобы бороться с этим, мы используем pкоманду для размещения ;в коде во время выполнения. Для этого мы вычитаем 6 из Aи помещаем его после p.

Вероятно, я добавлю большинство других значений выше 127, как только выясню правильные двухбайтовые значения. Пропущены 5 значений v^;и две новые строки.

Из 7502 подпрограмм 7417 из них допустили ошибку из-за недопустимых инструкций, 72 из-за переполнения памяти и 13 из-за нехватки памяти.


13

JavaScript, 42 байта

if([0XacdCADE*Proxy.length]!=362517948)田
  • Удаление i, fили ifвызовет SyntaxError: missing ; before statement;
  • Удаление вызовет SyntaxError: expected expression, got end of script;
  • Удаление 1 или 2 байтов из приведет к Invalid or unexpected token;
  • Изменение логического выражения вызовет либо ошибку синтаксиса, либо ошибку ссылки на

00000000: 6966 285b 3058 6163 6443 4144 452a 5072  if([0XacdCADE*Pr
00000010: 6f78 792e 6c65 6e67 7468 5d21 3d33 3632  oxy.length]!=362
00000020: 3531 3739 3438 29e7 94b0                 517948)...


9

Brain-Flak , 2 байта

<>

Попробуйте онлайн!

В качестве альтернативы, [], {}или (). Снятие одного кронштейна приводит к тому, что другой кронштейн становится бесподобным.

Доказательство того, что это оптимальное решение:

Программа Brain-Flak состоит из нилад (пара скобок самостоятельно) или монад (пара скобок, содержащих 1 или более нилад). Монада не может быть в нетронутой программе, так как вы можете просто удалить одну или несколько nilads. Точно так же вы не можете иметь более одной nilad в программе, так как вы можете удалить одну из них, не нарушая программу.

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


6

Ада, 110 байт (латиница 1)

Возможно, лучший ответ, который вы получите из любого языка, используемого в промышленности?

HexDump:

0000000: 7061 636b 4167 4520 6266 686a 6c6d 6f71  packAgE bfhjlmoq
0000010: 7274 7576 7778 797a e0e1 e2e3 e4e5 e6e7  rtuvwxyz........
0000020: e8e9 eaeb eced eeef f0f1 f2f3 f4f5 f6f8  ................
0000030: f9fa fbfc fdfe 0d69 730b 656e 6409 4246  .......is.end.BF
0000040: 484a 4c4d 4f51 5254 5556 5758 595a c0c1  HJLMOQRTUVWXYZ..
0000050: c2c3 c4c5 c6c7 c8c9 cacb cccd cecf d0d1  ................
0000060: d2d3 d4d5 d6d8 d9da dbdc ddde 3b0a       ............;.

Скомпилируйте, сохранив любой файл, заканчивающийся .adsи работающий gcc -c <filename>. Создает исполняемый файл, который ничего не делает. (Невозможно предоставить ссылку на TIO, поскольку TIO помещает код в .adbфайл и gccпо умолчанию пытается найти для них подходящую спецификацию)

В основном объявляет пакет с именем, в котором используются заглавные / строчные латинские буквы. Требуется различный символ пробела для каждого из пробелов, поэтому он использует пробел, CR, LF и TAB.

Как это выглядит в версии vim:

packAgE bfhjlmoqrtuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ^Mis^Kend^IBFHJLMOQRTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ;

Как это устроено

В Аде даже спецификации могут быть скомпилированы. Спецификации похожи на заголовочные файлы c, но более полнофункциональны и могут компилировать некоторый основной код. Чтобы быть действительной, любая спецификация должна иметь формат: package <NAME> is ... end <NAME>;с <NAME>соответствием. Хорошая вещь об Аде - то, что она полностью нечувствительна к регистру. Таким образом, пока ваше имя имеет прописные и строчные варианты, вам будет хорошо идти!

Трудной частью было получить скомпилированный модуль. Обычно программы Ada имеют «основную» процедуру или функцию, лежащую вне любого пакета, который станет конечным исполняемым файлом. К сожалению, для процедур требуется beginключевое слово, которое приводит к слишком большому числу es (известно только 2 случая), в то время как для функций требуется returnключевое слово, которое приводит к слишком большому числу ns. Таким образом, мне пришлось просто скомпилировать пакет.


5

C, 8 байтов

main(){}

Ничего не делает.

Попробуйте онлайн!


1
Может быть, я не понимаю проблему, но как насчетmain(){short x;}
Джерри Иеремия

@JerryJeremiah: нет, main(){short;}компилируется только с warning: useless type name in empty declaration. Я думаю, что C99 и C ++ требуют явного возвращаемого типа, чтобы int main(или, возможно, unsigned main) мог работать, но не с gcc, который только предупреждает даже с -std=c11.
Питер Кордес

@JerryJeremiah: return 0;может быть возможно с C89, где нет return 0конца в конце main. Согласно другим ответам, выход с ненулевым статусом может считаться неудачей. Влияет ли добавление флагов компилятора, например, -Werrorна счет в боулинге кода? Потому что строгое соблюдение нарушений C11 может позволить гораздо более длительную программу. Хм, #include<>что-то, а затем использовать это; вы не можете удалить и include, и использование, и если оно завершится неудачно без прототипа или макроса def, вы выиграете.
Питер Кордес

@PeterCordes Я думал об этом, но mainи includeоба содержат i, так что вы не можете иметь оба. Аналогично для объявления и использования функции. Кроме того, с помощью returnвообще придумать это.
Крис

упс, я забыл про требование уникальных байтов; конечно int mainне может работать.
Питер Кордес

4

JavaScript, 22 байта

with(0xF?JSON:[])parse

Попробуйте онлайн!

Возможные ошибки

При изменении он выдаст одну из следующих ошибок 1 :

[some_identifier] is not defined
expected expression, got ')'
expected expression, got ':'
expected expression, got '?'
expected expression, got ']'
expected expression, got end of script
identifier starts immediately after numeric literal
missing ( before with-statement object
missing ) after with-statement object
missing : in conditional expression
missing ] after element list
missing exponent
missing hexadecimal digits after '0x'
missing octal digits after '0o'
unexpected token: ')'
unexpected token: ']'
unexpected token: identifier

1. Точное количество явных ошибок зависит от двигателя. Этот список был создан с помощью SpiderMonkey (Firefox).


4

Python 3 + Flask-Env , 7 13 14 17 байт

import\
flask_env

Нет TIO, потому что он не имеет flask-env.

Найдено самое длинное имя модуля, которое не имеет пересечения importи не имеет цифр в конце имени. _sha256длиннее, но 256само по себе не ошибка. Я нашел одну библиотеку, b3j0f.syncкоторая на один байт длиннее, но я не смог заставить ее правильно импортировать.

  • +1 байт, заменив пробел после importна \<newline>. Вынос одного или обоих вызывает ошибку.

Там все еще могут быть более длинные варианты, чем flask_env, я действительно не делал исчерпывающий поиск, но я просмотрел ~ 70 000 модулей. Открыт для предложений.


256работает без ошибок.
Эйдан Ф. Пирс

@ AidanF.Pierce Спасибо, исправлено.
Дилнан

Я пробовал import *[hawkey]и похожий, но, к сожалению, не работает ...
Dylnan

1
hawkey отсутствует в стандартной библиотеке, так что это «Python with hawkey» (вероятно, может быть лучше с другим модулем)
Джонатан Аллан

@JonathanAllan Хорошая мысль.
Должны

3

R , 14 байтов

(Sys.readlink)

Попробуйте онлайн!

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

Эта первая попытка не сработала, но я многому научился, пытаясь!

dontCheck({family;NROW})


2

Perl 5, 3 байта

y=>

=>это «толстая запятая», которая цитирует голое слово слева. Так что это эквивалентно

"y",

который ничего не делает.

Без жирной запятой y- оператор транслитерации, который недопустим, если три одинаковых символа не повторяются позже.

Жирная запятая сама по себе тоже недействительна, как =и в >одиночку.


2

брейкфук , 2 байта

[]

Попробуйте онлайн!

Вдохновленный ответом Brain-Flak Джо Кинга . Это оптимально, потому что единственная ошибка в Brainfuck - это несоответствующие скобки. (Еще раз спасибо Джо Кингу за эту информацию.)


Ага. Единственная ошибка, с которой может столкнуться брейкфак, - непревзойденные скобки
Джо Кинг,


1

Стандартный ML , 22 байта

val 1089=op-(765,~324)

Попробуйте онлайн! op-(a,b)это обезвоженная форма a-b. ~обозначает унарный минус, поэтому мы на самом деле вычисления 765+324. Это выражение соответствует шаблону на константе 1089. Это совпадение успешно, если программа не была подделана и ничего не делает.

Если совпадение не удается из-за того, что некоторые цифры были удалены, каждый получает unhandled exception: Bind. Удаление op-приводит к ошибке типа, потому что кортеж соответствует int. Все другие удаления должны привести к синтаксической ошибке.


1

Swift 4 , 19 байт

[].contains{1 !=
0}

Попробуйте онлайн!

Все возможные ошибки, которые я нашел:

  • Удаление любого из [, ], {или }приведет к синтаксической ошибке
  • Удаление [].приведет кUse of unresolved identifier 'contains'
  • Удаление .приведет кConsecutive statements on a line must be separated by ';'
  • Удаление []приведет кReference to member 'contains' cannot be resolved without a contextual type
  • Удаление {1 !=␊0}приведет кExpression resolves to an unused function
  • Удаление 1 !=␊0приведет кMissing return in a closure expected to return 'Bool'
    • Удаление новой строки приведет к '!=' is not a prefix unary operator
    • Удаление места приведет к '=' must have consistent whitespace on both sides
    • Удаление !=приведет кMissing return in a closure expected to return 'Bool'
      • Также удаление новой строки приведет к Consecutive statements on a line must be separated by ';'
      • Удаление пробела и новой строки (и ноль или одна из цифр) приведет к Contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored
  • Удаление [].containsприведет кClosure expression is unused

Некоторые другие интересные программы (по одной в каждой строке):

[].isEmpty
[:].values
[1:2]

Это содержит два as
caird coinheringaahing



0

Сетчатка , 2 байта

Я не удивлюсь, если это оптимально ...

()

Попробуйте онлайн!

Регулярное выражение содержит пустую группу. Удаление парен будет вызывать ошибку разбора из-за несоответствующих скобок.

Другие решения: \(, \), \[, \], \*, \+, \?,a]


a]не ошибка
jimmy23013

@ jimmy23013 Ах, я не знаю, как я это пропустил. Откат.
mbomb007

-2

C (gcc) , 73 75 байтов

#include <ftw.h>
ABCEGHIJKLMNOPQRSUVXYZabjkmopqrsvxz234567890(){g FTW_D-1;}

Попробуйте онлайн!

На основании ответа @Steadybox, спасибо @Angs за обнаружение серьезной ошибки.

Да, это грязная хак (потому что на самом деле использует #defineс -DABCEGHIJKLMNOPQRSUVXYZabjkmopqrsvxz234567890=mainи -Dg=return), но я не вижу никакого правила , которое запрещает такую опцию компилятора.


Первую строку можно убрать, чтобы программа не была нетронутой
Angs

@Angs Спасибо, исправлено (с ценой добавления других опций компилятора)
trolley813

8
Не Согласно мете сообщению , ваше сообщение уже не на языке C, но C89 + -DABCEGHIJKLMNOPQRSUVXYZabjkmopqrsvxz234567890=main+ -Dg=return, так что я бы утверждать , что это использует выдуманный язык , специально разработанный для вызова , который запрещен по умолчанию.
Деннис

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