Найти все однозначные префиксы набора строк


12

Для выполнения этой задачи вы должны реализовать Abbrevмодуль Ruby как можно меньше кода.

Вызов

  • Входными данными будут все, что имеет ваш язык в виде массива (массив, список, последовательность и т. Д.) Строк. Вы можете написать функцию или принять слова, разделенные запятыми, в STDIN.

  • Затем вы должны вычислить набор однозначных префиксов для этих строк. Это означает, что вы должны вернуть хеш (или карту, объект и т. Д.) Сокращений в их исходные строки.

    • «Префикс» - это подстрока исходной строки, начинающаяся с начала строки. Например, «преф» является префиксом слова «префикс».

    • Однозначный префикс один , что может означать только одно слово. Например, если вы вводите car,cat, то caэто не однозначный префикс, потому что он может означать «автомобиль» или «кошка».

    • Исключением из этого правила является то, что слово всегда является префиксом самого себя. Например, если у вас есть ввод, например car,carpet, car:carдолжен быть в вашем выводе.

  • Затем вы можете вернуть хеш / карту / объект / и т.д. от вашей функции (или сделать эквивалент на вашем языке), или распечатать его в STDOUT в key:valueпарах в форме f:foo,fo:foo,.... (Пары ключ-значение также могут быть разделены пробелами, если это делает ваш код короче.)

Контрольные примеры

Input  code,golf,going
Output c:code,co:code,cod:code,code:code,gol:golf,golf:golf,goi:going,goin:going,going:going

Input  pie
Output p:pie,pi:pie,pie:pie

Input  pie,pier,pierre
Output pie:pie,pier:pier,pierr:pierre,pierre:pierre

Input  a,dog
Output a:a,d:dog,do:dog,dog:dog

правила

  • Входные данные не будут содержать дубликаты элементов.

  • Ваш вывод может быть в любом порядке; Вы не должны сортировать это.

  • Вы не можете использовать встроенный Abbrevмодуль / функцию / что-то вроде Ruby.

  • Это , поэтому выиграет самый короткий код в байтах!


Должен ли stdout быть именно таким форматом? Или я могу сделать key:value\nkey:value\nkey:value...?
подземный

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

@PeterTaylor Хорошая идея; изм.
Дверная ручка

1
Можно ли печатать один и тот же ключ несколько раз (с одним и тем же значением)?
xnor

Ответы:


1

APL (46)

(Да, кодировка APL вписывается в байт, с запасом места.)

{↑{∆/⍨2=⍴∆←(⊂⍵),∆/⍨⊃¨⍵∘⍷¨∆}¨∪⊃,/{↑∘⍵¨⍳⍴⍵}¨∆←⍵}

Это функция, которая принимает список строк и возвращает матрицу 2 на N, где каждая строка содержит однозначный префикс и слово, которому она принадлежит:

{↑{∆/⍨2=⍴∆←(⊂⍵),∆/⍨⊃¨⍵∘⍷¨∆}¨∪⊃,/{↑∘⍵¨⍳⍴⍵}¨∆←⍵}'code' 'golf' 'going'
 c      code  
 co     code  
 cod    code  
 code   code   
 gol    golf  
 golf   golf  
 goi    going 
 goin   going 
 going  going 

Объяснение:

  • ∆←⍵: сохранить правильный аргумент в .
  • {↑∘⍵¨⍳⍴⍵}¨∆: для каждого элемента , получить возможные префиксы этого элемента:
    • ⍳⍴⍵: получить список с 1длиной
    • ↑∘⍵¨: для каждого из этих чисел, получить столько элементов из .
  • ∪⊃,/: объединить списки вместе и принять уникальные значения.
  • {... : для каждого из уникальных префиксов:
    • ∆/⍨⊃¨⍵∘⍷¨∆: выберите слова, которые начинаются с этого префикса
    • (⊂⍵),: также заключите префикс и объедините
    • ∆/⍨2=⍴∆←: вернуть список, только если есть два элемента (префикс и одно совпадающее слово)
  • : превратить список кортежей в матрицу

Ссылка сейчас не работает ...
user202729

3

Python 2,7 - 146 141 байт

l=raw_input().split(',')
for w in l:
 for a in range(len(w)):
    e=w[:a+1]
    if e==w or len(filter(lambda b:b.startswith(e),l))==1:print e+':'+w

Обратите внимание, что отступ в строках 4 и 5 не 4 пробела, это побочный эффект интерпретатора уценки SE. Это буквенный символ табуляции, поэтому только один байт.

Технически это не совсем соответствует спецификации, но я изменю это, если пояснится дверная ручка. Он использует новые строки вместо запятых для разделения вывода. Например:

$ python2 abbreviations.py <<< code,golf,golfing
c:code
co:code
cod:code
code:code
golf:golf
golfi:golfing
golfin:golfing
golfing:golfing

Новое: мне удалось избавиться от 5 символов, назначив строку, которую я проверяю, переменной e. Это означает, что мне нужно печатать eтолько w[:a]три раза. Это также означает, что я сохраняю символы, делая e=w[:a+1]и изменяя ...range(1,len(w)+1)на range(len(w)).


Объяснение:

l=raw_input().split(',') # Gets a line of input from stdin and splits it at every ',' to make a list
for w in l: # For each word in that list...

 for a in range(1,len(w)+1): # For each number a from 1 to the length of that word...

    if (w[:a]==w # w[:a] gets the string w up to the ath index. For example, 'aeiou'[:3] == 'aei'.
                 # We're testing every possible w[:a] to see if it's a unique abbreviation.
                 # However, a word is always its own abbreviation, so we hardcode that in by testing
                 # if w[:a] is the same as w.

or len(filter( # filter takes a function and an iterable as an argument, and returns a list of every
               # element of that iterable where that_function(that_element) returns a True-y value

lambda b:b.startswith(w[:a]),l) # We define an anonymous function that returns True for any string
                                # that begins with our current w[:a]. We filter for words that return
                                # True.

)==1): # If exactly one word returns True for this, it's a unique abbreviation!

     print w[:a]+':'+w # Print the abbreviation, a colon, and the full word.

Вы могли бы использовать sum(b.startswith(e) for b in l)вместоlen(filter(lambda b:b.startswith(e),l))
Никлас Б.

Вы также можете сократить b.startswith(e)до b.find(e)==0или b[:a+1]==eи проверить <2счет вместо ==1.
xnor

Также сделайте e=""\n for a in w:\n\te+=aвместо того, for a in range(len(w)):\n\te=w[:a+1]чтобы сэкономить 10 символов
WorldSEnder

Я сделал разглаженную версию здесь для всех, кому это нужно gist.github.com/stuaxo/c371b2d410191a575b763b74719856c8
Стюарт Аксон,

3

J - 47 символов

(,.~~.@,~[:(#~1-1({.\e."_1]\.){."1)@;(<\,.<)&.>)

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

   'code';'golf';'going'
+----+----+-----+
|code|golf|going|
+----+----+-----+

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

;@|.@,@((<&>',:'),."1,.~~.@,[:(#~1-1({.\e."_1]\.){:"1)@;(<,.<\)&.>)

Объяснение взрывом:

(,.~~.@,[:(#~1-1({.\e."_1]\.){."1)@;(<\,.<)&.>) NB. unambiguous prefixes
                                    (     )&.>  NB. for each string:
                                     <\         NB.   take all prefixes
                                       ,.<      NB.   pair each with string
        [:                         ;            NB. gather up "partial" hashes
          (#~1-                  )@             NB. remove those rows where:
               1({.\        ){."1               NB.   each key
                    e."_1                       NB.   is an element of
               1(        ]\.){."1               NB.   the rest of the keys
 ,.~                                            NB. hash each word to itself
       ,                                        NB. add these rows to hash
    ~.@                                         NB. remove duplicate rows

Примеры:

   (,.~~.@,[:(#~1-1({.\e."_1]\.){."1)@;(<\,.<)&.>) 'pie';'pier';'pierre'
+------+------+
|pie   |pie   |
+------+------+
|pier  |pier  |
+------+------+
|pierre|pierre|
+------+------+
|pierr |pierre|
+------+------+
   NB. 1-char words have to be made into lists with ,
   (,.~~.@,[:(#~1-1({.\e."_1]\.){."1)@;(<\,.<)&.>) (,'a');'dog'
+---+---+
|a  |a  |
+---+---+
|dog|dog|
+---+---+
|d  |dog|
+---+---+
|do |dog|
+---+---+
   NB. "key:value," format, reversed order to save chars
   ;@|.@,@((<&>',:'),."1,.~~.@,[:(#~1-1({.\e."_1]\.){:"1)@;(<,.<\)&.>) 'code';'golf';'going'
goin:going,goi:going,gol:golf,cod:code,co:code,c:code,going:going,golf:golf,code:code,

2

Haskell 96 87

import Data.List
i=inits
f a=a>>= \x->[(y,x)|y<-i x,y/="",y`notElem`(a>>=i)\\i x||y==x]

Безголовая версия:

 import Data.List
 f a = concatMap (\x ->
     [(y, x) |
      y <- inits x,
      y /= "",
      y `notElem` concatMap inits a \\ inits x || y == x]
     ) a

Пример:

> f ["pi","pier","pierre"]
[("pi","pi"),("pier","pier"),("pierr","pierre"),("pierre","pierre")]

Я использовал initsфункцию, которая находит все префиксы списка / строки. Это считается обманом?


1
Вы можете заменить concatMapна то (=<<), что есть в Prelude. Спасает вас 10 символов.
Rhymoid

@Rhymoid Спасибо. Я удалил, concatMapно не могу сохранить больше 9 символов.
Лортабак

Ой, подождите, вы правы; Хаскелл считает >>=\ одной лексемой. Извините за это ...
Rhymoid

2

Питон 3 (97)

c=','
S=c+input()
for w in S.split(c):
 e=w
 while e:e<w<w*S.count(c+e)or print(e+':'+w);e=e[:-1]

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

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

Мы подсчитываем вхождения префикса eво входных данных путем поиска Sподстрок в исходной строке ввода, разделенных запятыми ','+e. Мы добавляем запятую к входной строке перед этим. Это добавление вызывает дополнительный пустой строковый элемент, когда мы split, но это не имеет никакого эффекта, потому что у него нет непустых подстрок.

Чтобы проверить случай, когда подстрока eявляется целым словом w, мы сравниваем их, используя оператор сравнения строк. Это сравнивает лексикографически, поэтому короткие префиксы меньше. Двойное сравнение не выполняется , если либо e==wили S.count(c+e)<2.

Если бы распечатка выводов в форме e,wбыла разрешена, я бы сохранил символ, написав e+c+wвместо этого.

Кредит undergroundmonorail от которого ответа я основывал мою общую структуру кода.


(e<w)*S.count(c+e)>1можно сыграть в гольф, e<w<w*S.count(c+e)чтобы спасти 2 персонажа.
Исаак

@isaacg Спасибо! Я добавил вашу оптимизацию.
xnor

1

Руби, 114

def f(l);h={};l.each{|w|w.size.times{|i|k=w[0..i];h[k]=h[k]&&0||w}};h.delete_if{|k,v|v==0};l.each{|w|h[w]=w};h end

Ungolfed:

def f(list)
  hash = {}
  list.each do |word|
    word.size.times do |i|
      key = word[0..i]
      h[key] = (hash[key] && 0) || word
    end
  end
  hash.delete_if{|key, value| v==0}
  list.each{|word| hash[word] = word}
  hash 
end

1

к4 (70)

не особенно в гольф; я уверен, что это может быть короче

очень похоже на J импл. выше, я думаю - в основном просто собирает все (правильные) префиксы, снова удаляет слова из префиксов (для обработки "car"/ "carpet"case), группирует их в классы эквивалентности, выбирает классы только с одним элементом, сокращает их от списков до строки и добавляет в карту из строк для себя.

f:{(x!x),*:'{(&1=#:'x)#x}{x@=y@:&~y in x}.,/'+{1_'(c#,x;(!c:#x)#\:x)}'x}

некоторые тесты

обратите внимание, что в k/ qстрока представляет собой список символов, поэтому строку, содержащую только один символ, необходимо пометить как таковую с помощью унарной ,функции; & mmwrt список строк, содержащих только одну строку

Они используют q«сек showфункции, которая имеет встроенную форматированию для некоторых структур данных, чтобы сделать результаты более удобными для чтения:

  .q.show f("code";"golf";"going")
"code" | "code"
"golf" | "golf"
"going"| "going"
,"c"   | "code"
"co"   | "code"
"cod"  | "code"
"gol"  | "golf"
"goi"  | "going"
"goin" | "going"
  .q.show f@,"pie"
"pie"| "pie"
,"p" | "pie"
"pi" | "pie"
  .q.show f("pie";"pier";"pierre")
"pie"   | "pie"
"pier"  | "pier"
"pierre"| "pierre"
"pierr" | "pierre"
  .q.show f(,"a";"dog")
,"a" | ,"a"
"dog"| "dog"
,"d" | "dog"
"do" | "dog"
  .q.show f("car";"carpet")
"car"   | "car"
"carpet"| "carpet"
"carp"  | "carpet"
"carpe" | "carpet"

1

JavaScript - 212

w=prompt(o=[]).split(",");w.map(function(k,l){for(i=0;++i<k.length;){p=k.slice(0,i);if(w.filter(function(r,t){return t!=l}).every(function(r){return r.indexOf(p)}))o.push(p+":"+k)}o.push(k+":"+k)});console.log(o)

Начальный гольф.

Входные данные:

code,golf,going

Выход:

["c:code", "co:code", "cod:code", "code:code", "gol:golf", "golf:golf", "goi:going", "goin:going", "going:going"]


1

Perl, 93 77

С переводом строки и отступом для удобства чтения:

sub f{
    (map{
        $h{$x}=[($x=$`.$&,$_)x!$h{$x}]while/./g;
        $_,$_
    }@_),map@$_,values%h
}

Слишком поздно и слишком долго, но я рад, что наконец-то стало меньше 100. Функция возвращает список, который можно присвоить хеш-переменной:

%h = f(qw/code golf going pie pier pierre/);
print "$_ $h{$_}\n" for sort keys %h;

и

perl prefix.pl
c code
co code
cod code
code code
goi going
goin going
going going
gol golf
golf golf
pie pie
pier pier
pierr pierre
pierre pierre

На самом деле, возвращаемый список еще не отфильтрован - построение хеша завершается в момент его назначения, т.е. вне функции. Если это не достаточно чисто / справедливо, добавьте 3 для подсчета и поместите содержимое функции в фигурные скобки, предварительно добавив +- тогда функция вернет 'истинную' ссылку на хеш.


1

Q: 44 байта

{x!p@'(?0,&:)'p in\:&1=#:'=,/p:`$(-1_)\'$x}

ПРИМЕЧАНИЯ

  • Язык Q имеет внутреннее ядро ​​с внутренним именем K4 (используется в этом ответе и другом ранее ответе на этот вопрос)

  • Для проверки кода загрузите интерпретатор (kx.com, бесплатно для некоммерческого использования, поддержка Windows, Linux, Mac)

Интерпретатор допускает два синтаксиса:

  • многословный (более читаемые имена, отдельные имена для мотивов и диад, больше библиотек, ...). Загрузить исходный файл с расширением q или интерактивный интерпретатор

  • компактный (функциональное внутреннее ядро, однобуквенные операторы, одна буква для обоих использует монаду / диаду, ...). Загрузите исходный файл с расширением k или интерактивный интерпретатор в режиме k (запись \ при запросе). Код должен быть проверен в этом режиме

Код определяет лямбду (анонимная функция). Чтобы дать имя функции, нам нужен префикс name: (ex f: {..}), поэтому требуется 46 байт.

ТЕСТОВОЕ ЗАДАНИЕ

(предполагая именованную функцию: в противном случае подставьте код f)

f `code`golf`going

`code`golf`going!(`code`cod`co`c;`golf`gol;`going`goin`goi)

возвращает словарь (синтаксические ключи! значения). Ключи представляют собой список символов (`symb`symb ..), а значения представляют собой список символов. Если мы выполним предложение в интерактивном интерпретаторе, у нас будет более удобное представление (каждый ключ и соответствующие значения находятся в отдельной строке)

code | `code`cod`co`c
golf | `golf`gol
going| `going`goin`goi

ОБЪЯСНЕНИЕ

x является неявным аргументом в пользу лямбды

$x преобразовать список символов в список строк

(-1_)\ перебирает каждый элемент списка символов

(читается как для каждой строки вычисляет префиксы (при итерации есть последний символ строки (-1_), до пустой строки)

$ снова преобразуется в список символов (список всех префиксов)

p: и назначает р

,/ уничтожить все (объединяет и создает одноуровневую структуру)

= классифицировать -> для каждого уникального префикса, связывает соответствующие слова

#:' вычисляет длину (количество слов, связанных с каждым префиксом)

1= истина, если длина = 1 (однозначно), ложь в противном случае

& где -> индекс истинных элементов

p in\: определяет для всех префиксов, находятся ли они в однозначном префиксе

(..)' применяется (..) к каждому значению справа (однозначный префикс)

?0,&: -> отличный 0 объединенный где (чтобы справиться со словами как префикс себя)

p@ преобразовать индексы в символы

x!.. создать словарь с x (словами) в качестве ключей и .. в качестве значений

Читать как:

  • Создать и вернуть словарь со словами в качестве ключей и значений.

  • ... значения индексов в разных позициях 0 (все слова) и где однозначный префикс

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

  • ... выводит список классификации всех уникальных символов с соответствующими словами

  • ... префиксы рассчитываются путем повторения удаления последнего символа каждого слова


1

PHP 7.0, 67 байт (после испытания)

for(;a&$c=$s[++$k]??($s=$argv[++$i])[$k=+$t=!1];)echo$t.=$c,":$s,";

принимает входные данные из аргументов командной строки; печатает запятую; беги с -nr.

для более нового PHP добавьте один байт: замените &aна ""<.

для более старого PHP используйте эти 70 байтов:

PHP, 70 байт

for(;a&$s=$argv[++$i];)for($k=+$t="";a&$c=$s[$k++];)echo$t.=$c,":$s,";

1

Брахилог , 23 байта

∋Xa₀Y;?↔⟨∋a₀⟩ᶜ1∧Y;X|∋gj

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

Принимает ввод в виде списка через входную переменную и генерирует список [key, value]пар через выходную переменную. Любая входная строка, которая не является префиксом другой входной строки, будет сгенерирована как собственный префикс дважды, хотя заголовок в TIO скрывает это, используя для получения полный список вместо .

 X                         X
∋                          is an element of
                           the input variable
    Y                      and Y
  a₀                       is a prefix of
 X                         X.
             ᶜ             The number of ways in which
        ⟨∋  ⟩              an element can be selected from
     ;?↔⟨   ⟩              the input variable
    Y; ↔⟨ a₀⟩              such that it has Y as a prefix
              1            is equal to 1.
               ∧Y          Y is not necessarily 1,
                   |       and the output variable
                Y;X        is the list [Y, X].
                   |       If every choice from the first rule has been taken already,
                           the output variable is
                    ∋      an element of
                   |       the input variable
                     gj    paired with itself.

Если дубликаты в выходных данных не допускаются, добавьте три байта, чтобы обернуть все это {}ᵘ, если не существует более короткого способа либо исключить что-то, что является префиксом самого себя, либо сгенерировать каждую необходимую выходную пару без дополнительного правила ∋gj.
Несвязанная строка


1

APL (Dyalog Classic) , 38 байт

благодарит Эрика Outgolfer за напоминание мне использовать однобайтовую кодировку символов

{⊃,/⍵{b,¨⍨(⊂¨⍵~⊃,/a~⊂⍵)∪b←⊂⊂⍺}¨a←,⍵}

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


1
Хм ... Я не вижу здесь ни одного плохого персонажа, которого вы не могли бы использовать с SBCS Адама ...: P
Эрик Аутгольфер

не замечая, я снова выбрал неверную версию интерпретатора ... спасибо, что сократили вдвое количество моих байтов :)
ngn

0

Python (127)

Поэтому я не мог комментировать @undergroundmonorail, но я думал, что лучше использовать словарный подход? Я уверен, что с некоторым пониманием списка / словаря это также может быть значительно сокращено, но я не могу заставить его работать с треском от диктата.

i=raw_input().split(",")
d = {}
for x in i:
    for c in range(1,len(x)+1):
        if x[:c] in d:
            del d[x[:c]]
        else:
            d[x[:c]]=x
print d

Печать выведет словарь, неупорядоченный.

РЕДАКТИРОВАТЬ: Ааа я пропустил машину: автомобиль / автомобиль: ковер критерии. Может быть, проверка длины?


Может быть, я что-то упускаю, но, похоже, поочередно добавляются и удаляются записи префикса каждый раз, когда они встречаются, поэтому не появится ли неоднозначный префикс, если он встречается в 3 словах?
xnor

0

Groovy - 212 символов

Golfed:

c="collectEntries";f="findAll";def g={def h=[:].withDefault{[]};it.each{def w->w.size().times{ h[w[0..it]] << w}};(h."$f"{k,v->v.size()==1}."$c"{k,v->[k,v[0]]}).plus(h."$f"{k,v->v.contains(k)}."$c"{k,v->[k,k]})}

пример вывода:

println g(["code","golf","going"])

[c:code, co:code, cod:code, code:code, gol:golf, golf:golf, goi:going, goin:going, going:going]

Ungolfed:

def g = { def list ->
    def hash = [:].withDefault{[]}
    list.each {
        def word -> word.size().times{ hash[word[0..it]] << word }
    }

    def map = hash.findAll{ k,v -> v.size() == 1 }.collectEntries{ k,v -> [k,v[0]] }
    map.plus(hash.findAll{ k,v -> v.contains(k) }.collectEntries{ k,v -> [k,k] }
    map
}


0

Зш , 95 байт

local -A m
for w;{m[$w]=$w;x=
for c (${(s::)w})x+=$c&&[ ${(M)@:#$x*} = $w ]&&m[$x]=$w
}
local m

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

Единственный способ «вернуть» ассоциативный массив в Bash / Zsh - это объявить его без localключевого слова и затем обратиться к нему в родительской области. Это спасло бы один байт. Однако ввод-вывод через переменные обычно не одобряется, поэтому вместо этого мы печатаем определение массива.

local -A m                          # declare m as associative
                                    # "local" is shorter than "typeset"/"declare"
for w;{                             # for each word
    m[$w]=$w                        # the word is a prefix of itself
    x=                              # ensure x is empty
    for c (${(s::)w})               # for each character in the word
        x+=$c &&                    # append to x (building a prefix
          [ ${(M)@:#$x*} = $w ] &&  # if the only match is the word itself:
          m[$x]=$w                  # ... then x is a prefix of w
}
local m                             # print m

0

Рубин , 84 байта

Просто заметил, что уже существует решение для Ruby, да ладно. Это в основном улучшает старое решение, выбирая префиксы более умным способом (устраняя необходимость добавлять каждое слово в качестве «префикса» в конце) и подсчитывая префиксы для проверки уникальности перед добавлением их в хеш, вместо перезаписи значения пустышка, если есть дубликат, а затем стирание записи.

->w{h={};w.map{|e|(1..e.size).map{|i|w.count{|d|d[0,i]==e[0,i]}<2?h[e[0,i]]=e:0}};h}

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

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