Оригинал: Глава 12 Эволюция сотрудничества
Переводчик: Феликс Ли
Лицензия: CC BY-NC-SA 4.0
Гордо использует Google Translate
В последней главе мы задаем два вопроса, один из биологии, другой из философии:
Инструментами, которыми мы будем пользоваться для решения этих проблем, будут моделирование с использованием агентов и теория игр, которая представляет собой набор абстрактных моделей, предназначенных для описания различных способов взаимодействия агентов. Конкретнее, мы рассмотрим игру "Преступник против преступника".Код этой главы находится в chap12.ipynb
, который является Jupyter-ноутбуком в репозитории этого учебника. Дополнительная информация о применении этого кода см. в разделе ?.
Игра "Преступник против преступника" является примером из теории игр, но сама по себе она не представляет собой интересную игру. Наоборот, эта игра демонстрирует мотивацию и поведение человека. Вот её описание из Википедии (http://en.wikipedia.org/wiki/Prisoner%27s_dilemma):
Двое участников преступной группы были арестованы и помещены под стражу. Каждый преступник содержится в одиночной камере и не может общаться со своим сообщником. Прокурор не располагает достаточной информацией, чтобы доказать основное обвинение этим двум лицам. Он хочет приговорить каждого из них к более лёгкому обвинению сроком на два года. В то же время прокурор предлагает каждому преступнику сделку. У каждого есть возможность: (1) выдать своего сообщника, предоставив доказательства его вины, или (2) помочь своему сообщнику, оставшись молчаливым. Предложение такое:+ Если А и Б каждый выдают друг друга, они оба получат по два года лишения свободы.
Независимо от того, что делает Б, А лучше предать. И поскольку игра симметричная, анализ с точки зрения Б такой же: независимо от действий А, Б лучше тоже предать.
В самом простом варианте этой игры мы предполагаем, что А и Б не учитывают никаких других факторов. Они не могут общаться друг с другом, поэтому они не могут договариваться, давать обещания или угрожать друг другу. Они заботятся только о своих прямых целях — минимизации своего приговора; они не принимают во внимание никакие другие факторы.
Под этими предположениями рациональный выбор обоих агентов — предать. Это может быть хорошо, по крайней мере, с точки зрения уголовной юстиции. Но для заключённых это печально, так как очевидно, что они не могут достичь желаемого ими обоими результата. И эта модель применима к реальной жизни в других случаях, когда сотрудничество принесло бы большую пользу и было бы лучше для всех участников.Исследование этих ситуаций и методов выхода из этого затруднения является основным предметом исследования теории игр, но это не является главной темой данного раздела. Мы движемся в другом направлении.
С момента обсуждения проблемы заключённого в середине XX века она стала популярной темой исследований социальной психологии. По нашему анализу из предыдущего раздела можно сказать, что идеальный агент должен делать; трудно предсказать, что действительно сделают люди. К счастью, эксперименты уже были проведены [1].
[1] Вот недавний отчёт, который упоминает предыдущие эксперименты: Barreda-Tarrazona, Jaramillo-Gutiérrez, Pavan и Sabater-Grande, "Личные характеристики против опыта: Экспериментальное исследование сотрудничества в проблеме заключённого", Frontiers in Psychology, 2017; 8: 596. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5397528/. Если мы допустим, что люди достаточно умны, чтобы провести анализ (или понять его при интерпретации) и что они обычно действуют в своих интересах, то мы можем ожидать, что они почти всегда будут предавать. Но этого не происходит. В большинстве экспериментов уровень сотрудничества испытуемых значительно превышает прогнозы модели рационального агента [2].
[2] Есть отличный видеообзор того, что мы обсуждали до сих пор: https://www.youtube.com/watch?v=t9Lo2fgxWHw.Наиболее очевидное объяснение этого результата заключается в том, что люди не являются рациональными агентами, что должно никого не удивлять. Но почему же нет? Из-за недостатка ума для понимания ситуации или потому, что они намеренно противопоставляют свои интересы?
По результатам экспериментов, кажется, что хотя бы частичной причиной является чистый альтруизм: многие готовы нести затраты ради блага других. Перед тем как отправиться публиковаться в "Journal of Obvious Results", давайте спросим себя, почему это так:
[3] Я надеюсь, вы простите меня за использование слова "очевидно" вместо ссылки на экспериментальные данные здесь, где я хочу представить некоторые причины, не углубляясь слишком глубоко.Этот очевидный парадокс известен как "проблема альтруизма": почему гены альтруизма не исчезли? В биологическом сообществе существует множество возможных объяснений, включая взаимовыгодное альтруистическое поведение, сексуальный отбор, родственный отбор и групповой отбор. Вне научного сообщества существует еще больше объяснений. Я передаю это вам для исследования других гипотез; сейчас же я хочу сосредоточиться на одном из самых простых объяснений: возможно, альтруизм является адаптивным. Другими словами, гены альтруизма могут делать людей более способными выживать и размножаться.
Выяснилось, что тот же затрудняющий проблему "Проблема двух заключённых" также может помочь её решить.
В конце 1970-х годов политолог Университета Мичигана Роберт Экслрод организовал турнир по сравнению стратегий игры «Проблема двух заключённых» (PD).
Он пригласил участников представить свои стратегии в виде компьютерных программ, которые затем будут противостоять друг другу и накапливать очки. Конкретнее говоря, они играли в итеративную версию PD, где агенты проводили несколько раундов против одного и того же противника, поэтому их решения могли основываться на истории.В турнире Экслрода одна простая стратегия оказалась необычайно эффективной — так называемый «ответ на ответ», или TFT. TFT всегда сотрудничает во время первого раунда; после этого он повторяет любое действие своего противника из предыдущего раунда. Если противник продолжает сотрудничество, TFT тоже продолжает сотрудничество; если противник когда-либо предаст, то в следующем раунде TFT тоже предаст, но если противник снова начинает сотрудничать, TFT тоже будет сотрудничать.Дополнительная информация о этих турнирах и объяснение того, почему TFT такой успешный, можно найти в этом видео: https://www.youtube.com/watch?v=BOvAbjfJ0x0.
Просматривая успешные стратегии в этих турнирах, Экслрод заметил общие черты:
TFT обладает всеми этими свойствами.Турнир Экслрода предоставляет частичный ответ на вопрос об альтруизме: возможно, гены альтруизма являются универсальными, поскольку они являются адаптивными. Многие социальные взаимодействия могут моделироваться как вариации игры «Проблема двух заключённых», и в этой степени установка мозга на милость, баланс между ответом и справедливостью, может обеспечивать хорошее поведение в различных ситуациях. Однако стратегии в соревновании Акселродом были созданы людьми; они не эволюционируют. Нам следует рассмотреть возможность появления генов доброты, мщения и прощения через мутацию, успешного проникновения в популяцию других стратегий и защиты от последующих мутаций.## 12.4 Моделирование эволюции сотрудничества
Эволюция сотрудничества — это тема первой книги Акселрода, где он представил результаты соревнований по проблеме заключённого и обсудил влияние проблемы альтруизма. После этого он и другие исследователи изучили эволюционную динамику соревнований по проблеме заключённого, то есть как меняется распределение стратегий среди участников с течением времени. В остальной части этой главы я проведу версию этих экспериментов и покажу результаты.
Сначала нам нужна методика кодирования стратегий по проблеме заключённого в виде генотипов. В этом эксперименте я рассматриваю стратегии, при которых выбор каждого агента за каждый ход зависит только от двух предыдущих ходов противника. Я использую словарь для представления стратегии, который отображает два предыдущих хода противника в следующий ход агента.
Вот определение класса таких агентов:
class Agent:
keys = [(None, None),
(None, 'C'),
(None, 'D'),
('C', 'C'),
('C', 'D'),
('D', 'C'),
('D', 'D')]
def __init__(self, values, fitness=np.nan):
self.values = values
self.responses = dict(zip(self.keys, values))
self.fitness = fitness
keys
представляет собой последовательность ключей для каждого агента, где кортеж ('C', 'C')
указывает на сотрудничество противника за последние два хода; (None, 'C')
означает один ход и сотрудничество противника; (None, None)
означает, что ещё нет ходов.В конструкторе класса __init__
, values
представляют собой серию значений 'C'
или 'D'
, соответствующих ключам. Таким образом, если первый элемент значения равен 'C'
, значит этот агент будет сотрудничать во время первого хода. Если последний элемент значения равен 'D'
, значит агент будет предъявлять счет, если противник предал его за последние два хода.
В данном реализации генотип всегда предающего агента — 'DDDDDDD'
; генотип всегда сотрудничающего агента — 'CCCCCCC'
, а генотип TFT — 'CCDCDCD'
.
Класс Agent
предоставляет метод copy
, который позволяет другому агенту иметь такой же генотип, но с некоторой вероятностью мутации:
prob_mutate = 0.05
def copy(self):
if np.random.random() > self.prob_mutate:
values = self.values
else:
values = self.mutate()
return Agent(values, self.fitness)
Мутация заключается в том, чтобы выбрать случайное значение в генотипе и перевести его с 'C'
на 'D'
, или наоборот:
def mutate(self):
values = list(self.values)
index = np.random.choice(len(values))
values[index] = 'C' if values[index] == 'D' else 'D'
return values
Так как у нас есть агенты, нам также потребуется провести турнир.
Класс Tournament
упаковывает детали проведения игры PD:
payoffs = {
('C', 'C'): (3, 3),
('C', 'D'): (0, 5),
('D', 'C'): (5, 0),
('D', 'D'): (1, 1)
}
num_rounds = 6
def play(self, agent1, agent2):
agent1.reset()
agent2.reset()
for i in range(self.num_rounds):
resp1 = agent1.respond(agent2)
resp2 = agent2.respond(agent1)
``````markdown
pay1, pay2 = self.payoffs[(resp1, resp2)]
agent1.append(resp1, pay1)
agent2.append(resp2, pay2)
return agent1.score, agent2.score
payoffs
— это словарь, который отображает выбор агента на награду. Например, если два агента сотрудничают, каждый получает 3 очка. Если один предает, а другой сотрудничает, предатель получает 5 очков, а союзник — 0. Если оба предают, каждый получает 1 очко. Эти награды используются Акселродом в своих играх.
Функция play
запускает несколько раундов игры PD. Она использует следующие методы класса Agent
:
reset
: инициализирует агента перед первым раундом, сбрасывая его счет и историю ответов.respond
: спрашивает каждого агента на ответ, принимая во внимание предыдущий ответ противника.append
: обновляет каждого агента, сохраняя выбранные варианты и суммируя баллы за последовательные раунды.После завершения всех раундов, play
возвращает общую сумму очков для каждого агента. Я выбрал num_rounds = 6
, чтобы каждый элемент генотипа был доступен приблизительно одинаковое количество раз. Первый элемент доступен только в первом раунде или шестой частью времени. Два следующих элемента доступны только во втором раунде, то есть каждое из них доступно одной двенадцатой части времени. Последние четыре элемента доступны шестью разами, что составляет шестую часть времени, или в среднем по шесть раз.
```Класс Tournament
также предоставляет второй метод `melee`, который определяет, какие агенты будут сражаться друг с другом:
def melee(self, agents, randomize=True):
if randomize:
agents = np.random.permutation(agents)
n = len(agents)
i_row = np.arange(n)
j_row = (i_row + 1) % n
totals = np.zeros(n)
for i, j in zip(i_row, j_row):
agent1, agent2 = agents[i], agents[j]
score1, score2 = self.play(agent1, agent2)
totals[i] += score1
totals[j] += score2
for i in i_row:
agents[i].fitness = totals[i] / self.num_rounds / 2
Метод melee
принимает список агентов и булево значение randomize
, которое определяет, будут ли агенты сражаться каждый раз с одним и тем же соседом или будет ли случайным образом составлен матч.
Переменные i_row
и j_row
содержат индексы матчей. Массив totals
хранит общие очки каждого агента.
Внутри цикла мы выбираем двух агентов, вызываем метод play
и обновляем значения в массиве totals
. В конце вычисляем среднее количество очков за каждый раунд и против каждого соперника для каждого агента и сохраняем результат в свойстве fitness
каждого агента.
Simulation
Класс Simulation
этой главы основан на том, что был представлен в главе ?; единственное отличие заключается в методах __init__
и step
.
Это метод __init__
:
class PDSimulation(Simulation):
def __init__(self, турнир, агенты):
self.турнир = турнир
self.агенты = np.asarray(агенты)
self.инструменты = []
Объект класса Simulation
содержит объект Tournament
, последовательность агентов и последовательность объектов Instrument
(как и в главе ?).
Класс Tournament
также предоставляет второй метод melee
, который определяет, какие агенты будут сражаться друг с другом:
def melee(self, agents, randomize=True):
if randomize:
agents = np.random.permutation(agents)
n = len(agents)
i_row = np.arange(n)
j_row = (i_row + 1) % n
totals = np.zeros(n)
for i, j in zip(i_row, j_row):
agent1, agent2 = agents[i], agents[j]
score1, score2 = self.play(agent1, agent2)
totals[i] += score1
totals[j] += score2
for i in i_row:
agents[i].fitness = totals[i] / self.num_rounds / 2
Метод melee
принимает список агентов и булево значение randomize
, которое определяет, будут ли агенты сражаться каждый раз с одним и тем же соседом или будет ли случайным образом составлен матч.
Переменные i_row
и j_row
содержат индексы матчей. Массив totals
хранит общие очки каждого агента.
Внутри цикла мы выбираем двух агентов, вызываем метод play
и обновляем значения в массиве totals
. В конце вычисляем среднее количество очков за каждый раунд и против каждого соперника для каждого агента и сохраняем результат в свойстве fitness
каждого агента.
Simulation
Класс Simulation
этой главы основан на том, что был представлен в главе ?; единственное отличие заключается в методах __init__
и step
.
Это метод __init__
:
class PDSimulation(Simulation):
def __init__(self, tournament, agents):
self.tournament = tournament
self.agents = np.asarray(agents)
self.instruments = []
Объект класса Simulation
содержит объект Tournament
, последовательность агентов и последовательность объектов Instrument
(как и в главе ?).Вот метод step
:
def step(self):
self.турнир.melee(self.агенты)
Simulation.step(self)
Эта версия метода step
использует метод Tournament.melee
, который устанавливает свойство fitness
для каждого агента; затем он вызывает метод step
родительского класса, как это было показано в главе ?:
# класс Simulation
def step(self):
n = len(self.агенты)
fits = self.get_fitnesses()
# определяем, кто погибает
index_dead = self.choose_dead(fits)
num_dead = len(index_dead)
# заменяем погибших копиями живых
replacements = self.choose_replacements(num_dead, fits)
self.агенты[index_dead] = replacements
# обновляем любые инструменты
self.update_инструменты()
Метод Simulation.step
собирает адаптивность агентов в массив; затем он вызывает метод choose_dead
, чтобы определить, какие агенты погибают, и метод choose_replacements
, чтобы определить, какие агенты размножаются. Мой симулятор включает выживаемость различий, как в [какой-то] главе, но не включает размножение различий. Подробности можно найти в ноутбуке этой главы. В качестве одного из упражнений вы сможете исследовать эффекты размножения различий.
Tournament.melee
в этом популяционном составе, то сотрудничающий получит 1.5 очка за каждый ход, агент с TFT — 1.9 очка, а предатель — 3.33 очка. Этот результат указывает на то, что "всегда предаёт" должна быстро стать доминирующей стратегией.Однако "всегда предаёт" содержит семена саморазрушения; если лучшие стратегии становятся вымершими, предатели окажутся без жертв, их адаптивность упадёт, и они станут уязвимыми для вторжения со стороны сотрудничающих.На основании этого анализа трудно предсказать поведение системы: найдёт ли она стабильное равновесие или будет колебаться между различными генотипическими ландшафтами? Давайте запустим симуляцию, чтобы узнать!
Я начал с 100 одинаковых агентов, которые всегда предают, и запустил симуляцию на OnClickListener 5000 шагов:
tour = Tournament()
agents = make_identical_agents(100, 'DDDDDDD')
sim = PDSimulation(tour, agents)
Рисунок 12.1: Средняя адаптивность (очки, набранные в каждом раунде игры "Заточник")
Рисунок 12.1 показывает изменения средней адаптивности во времени (используется инструмент MeanFitness из [какой-то] главы). Начальная средняя адаптивность составляет 1, так как предатели получают всего 1 очко за каждый ход против другого предателя.
Через примерно 500 шагов средняя адаптивность увеличивается до почти 3, что соответствует ситуации, когда предатели сталкиваются с сотрудниками. Однако, как мы и предполагали, эта ситуация нестабильна. За следующие 500 шагов средняя адаптивность снижается ниже 2, затем снова возрастает до 3 и продолжает колебаться.Оставшаяся часть симуляции демонстрирует значительные изменения, однако, кроме одного большого падения, средняя адаптивность обычно находится в диапазоне от 2 до 3, с долгосрочной средней близкой к 2,5.
И это уже хорошо! Это не утопия сотрудничества, где средний балл за каждый ход составляет 3, но это значительно лучше, чем постоянное предательство. Это лучше, чем мы ожидали бы от естественного отбора самоинтересных агентов.
Для более глубокого понимания уровня адаптивности давайте рассмотрим больше инструментов. Класс Niceness измеряет степень сотрудничества генотипа каждого агента после каждого временного шага:
class Niceness(Instrument):
Рисунок 12.2: Средний уровень дружелюбия всех геномов в популяции (слева) и процент популяции, сотрудничавшей в первом раунде (справа).
Рисунок ? (слева) показывает результат: средний уровень дружелюбия быстро возрастает с 0 до 0,75, а затем колеблется между 0,4 и 0,85, достигая долгосрочного среднего значения около 0,65. Это довольно хорошо!
При более детальном рассмотрении начального движения мы можем отследить процент агентов, сотрудничавших в первом раунде. Вот этот прибор:
class Retaliating(Instrument):
def update(self, sim):
после_д = np.array([agent.values[2::2]
for agent in sim.agents])
после_с = np.array([agent.values[1::2]
for agent in sim.agents])
метрика = np.mean(после_д == 'Д') - np.mean(после_с == 'Д')
self.metrics.append(метрика)
```При реактивном поведении сравниваются количество элементов во всех геномах, где агент также отказывается после того, как противник отказывается (элементы 2, 4 и 6), с количеством элементов, где агент отказывается после того, как противник сотрудничает. Как можно заметить, результат отличается значительно (графики представлены в ноутбуке). В среднем различие этих значений составляет менее 0,1, поэтому если агент отказывается примерно в 30% случаев после сотрудничества противника, он может отказываться примерно в 40% случаев после отказа.
Этот результат слабо поддерживает утверждение, что успешная стратегия должна включать возможность реагировать. Возможно, не все агенты или даже большинство агентов должны реагировать; достаточно наличия некоторого уровня реактивности в популяции, чтобы предотвратить распространение чрезмерно реактивной стратегии.
Чтобы измерить прощение, я снова определил прибор, который проверяет, вероятнее ли агенты сотрудничать после Д-С по сравнению с С-Д. В моих симуляциях нет свидетельств этой конкретной формы прощения. С другой стороны, стратегии в этих симуляциях являются в какой-то степени необходимыми прощающими, так как они учитывают только историю за последние два раунда.## 12.8 Заключение
Конкурс Акселрода предлагает возможное решение проблемы альтруизма: быть добрым, но не слишком добрым, является адаптивным. Однако стратегии в первоначальных примерах были созданы людьми, а не эволюционными процессами, и распределение стратегий не менялось в течение конкурса. Это вызывает вопрос: стратегии вроде TFT могут хорошо работать при фиксированном人为设计策略, но будут ли они эволюционировать? Другими словами, смогут ли они возникнуть через мутацию в популяции, успешно конкурировать с предками и противостоять вторжению потомков?
Симуляции в этой главе показывают:+ Популяция предателей легко подвергается вторжению более дружелюбными стратегиями.
+ Популяция слишком дружелюбных также легко поддается вторжению предателями.
+ В результате средний уровень дружелюбия колеблется, но среднее количество дружелюбия обычно выше, а средняя степень приспособленности чаще всего ближе к уровню сотрудничества, чем к уровню предпочтения предателей.
+ В соревновании Александра TFT является успешной стратегией, однако это кажется не самой лучшей стратегией для развивающейся популяции. Возможно, вообще нет стабильной оптимальной стратегии.
+ Некоторый уровень отмщения может быть адаптивным, но полезность отмщения может не потребоваться для всех агентов. Если достаточно много агентов в популяции способны к отмщению, этого может оказаться достаточно для предотвращения вторжения предателей [4].> [4] Это вводит новый раздел в теории игр — проблему бесплатного проедания (см. <https://en.wikipedia.org/wiki/Free-rider_problem>).
Очевидно, что агенты в этих симуляциях просты, а игра «Пленник» представляет собой абстракцию ограниченного социального взаимодействия. Тем не менее, результаты этой главы дают некоторые представления о человеческой натуре. Может быть, наши склонности к сотрудничеству, отмщению и прощению являются врожденными, хотя частично. Эти черты являются результатом работы нашего мозга, который, как минимум частично, контролируется нашими генами. Может быть, наши гены таким образом строят наш мозг, так как гены эгоистичного мозга были бы маловероятны для распространения в истории эволюции человека.
Поэтому возможно, что именно поэтому эгоистичные гены создают бескорыстный мозг.
## 12.9 Упражнения
Код данной главы расположен в Jupyter-ноутбуке `chap12.ipynb`, находящемся в репозитории книги. Откройте ноутбук, прочитайте код и запустите его. Вы можете использовать этот ноутбук для выполнения упражнений данной главы. Мои решения представлены в ноутбуке `chap12soln.ipynb`.
Упражнение 1Симуляции данной главы зависят от произвольно выбранных условий и параметров. В качестве упражнения я рекомендую вам исследовать другие условия и посмотреть, как они влияют на результаты. Вот несколько советов:
1. Измените начальные условия: вместо того чтобы начинать с всех предателей, попробуйте начать со всех сотрудников, всех TFT или случайных агентов.
2. В `Tournament.melee` я перемешиваю игроков в начале каждого временного шага, так что каждый игрок сталкивается с двумя случайно выбранными игроками. А что будет, если вы не будете перемешивать? В этом случае каждый агент будет повторно играть против одних и тех же соседей. Это может сделать стратегию меньшинства более эффективной за счет использования локальности для вторжения большинства.
3. Поскольку каждый агент играет только с двумя другими агентами, результаты каждой игры могут сильно различаться: агент, который побеждает большую часть других агентов в любой игре, может просто иметь плохое везение, или наоборот. Что произойдет, если увеличить количество соперников для каждого агента в каждом раунде? Или если адаптивность агента после каждого шага будет средним значением его текущего балла и адаптивности от конца предыдущего раунда?
4. Я выбрал значения для функции `prob_survival` от 0.7 до 0.9, так что агенты с наименьшей адаптивностью (p = 0.7) выживают около 3.33 временных шага, а агенты с наибольшей адаптивностью выживают 10 временных шагов. Что произойдет, если сделать `prob_survival` более "агрессивным" или менее "агрессивным"?
1. Я выбрал `num_rounds = 6`, чтобы каждый элемент генома оказывал примерно одинаковое влияние на результаты игры. Но это намного меньше, чем значение, используемое Аллокродом в его экспериментах. Что произойдет, если увеличить `num_rounds`? Обратите внимание: если вы исследуете эффект этого параметра, возможно, вам придется модифицировать `Niceness`, чтобы измерять степень дружественности последних четырёх элементов генома, которая будет подвергаться всё большему выборочному давлению при увеличении `num_rounds`.
1. Моя реализация имеет разницу в выживаемости и случайное размножение. Что произойдет, если добавить разницу в размножении? Упражнение 2В моих симуляциях популяция никогда не сходилась в состояние, где большинство людей имели одинаковый, предположительно оптимальный генотип. Для этого результата есть две возможные интерпретации: либо нет оптимальной стратегии, так как каждый раз, когда популяция контролируется доминирующим генотипом, это создаёт возможность вторжения меньшинства; либо мутационная скорость достаточно высока, чтобы поддерживать множество генотипов, даже если большинство из них не являются оптимальными. Чтобы отличить эти интерпретации, попробуйте понизить частоту мутаций и посмотреть, что произойдет. Либо начните с случайной популяции без мутаций и запустите её до тех пор, пока не останется всего один генотип. Либо запустите с мутациями до тех пор, пока система не достигнет стабильного состояния; затем отключите мутацию и продолжайте запуск до тех пор, пока не останется всего один выживший генотип. Какие характеристики имеют генотипы в этих случаях?
Упражнение 3
В экспериментах с агентами они были "реактивными", потому что их выбор в каждом раунде зависел только от действий противника в предыдущих раундах. Рассмотрите исследование некоторых стратегий, которые также учитывают прошлые действия самих агентов. Такие стратегии могли бы различать мстительных противников и тех, кто предательски отказывается сотрудничать без провокации.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )