Як працює слухач подій?


125

Під час однієї з моїх сьогоднішніх лекцій про Unity ми обговорювали оновлення позиції гравця, перевіряючи кожен кадр, чи користувач натискає кнопку вниз. Хтось сказав, що це малоефективно, і нам слід використовувати замість цього слухача подій.

Моє запитання, незалежно від мови програмування чи ситуації, до якої він застосовується, як працює слухач подій?

Моя інтуїція припускає, що слухач події постійно перевіряє, чи подія була звільнена, тобто, за моїм сценарієм, це було б не інакше, ніж перевірка кожного кадру, якщо подію було знято.

Виходячи з дискусії на уроці, здається, що слухач подій працює по-іншому.

Як працює слухач подій?


34
Слухач події взагалі не перевіряє. Його називають, коли подія, що вона "слухає" пожежі.
Роберт Харві

13
Так, але як він "слухає", чи не буде це постійно перевіряти?
Gary Holiday

28
Ні. "Слухач подій", ймовірно, поганий вибір слів; насправді він взагалі не "слухає". Все, що слухає подія, це чекати, коли викличе цю подію, коли вона запускається, як і будь-який інший метод. Поки його не називають таким чином, він взагалі нічого не робить.
Роберт Харві

28
Кожен раз, коли ви перевіряєте, чи натиснута кнопка, це коштує вам циклів годин. Обробник подій (слухач) коштує вам лише тоді, коли кнопка насправді натиснута.
Роберт Харві

45
@RobertHarvey - не обов'язково, оскільки "слухачам" все ще потрібні постійні опитування на нижчому рівні. Ви просто підштовхуєте складність від власного шару коду глибше, до апаратних переривань чи будь-чого іншого. Так, це, як правило, буде більш ефективним, але не тому, що прослуховування перевершує опитування, це тому, що опитування на нижчому рівні є більш ефективним, ніж опитування на C # та 15 шарах абстракції між вами та обладнанням.
Давор Ждрало

Відповіді:


140

На відміну від наведеного вами прикладу опитування (де кнопка перевіряється у кожному кадрі), слухач подій не перевіряє, чи натиснута кнопка взагалі. Натомість його викликають при натисканні кнопки.

Можливо, термін "слухач подій" кидає вас. Цей термін говорить про те, що «слухач» активно робить щось для прослуховування, адже насправді він взагалі нічого не робить. "Слухач" - це лише функція або метод, який підписаний на подію. Коли подія запускається, викликається метод слухача ("обробник подій").

Перевага схеми події полягає в тому, що немає витрат, поки кнопка не буде фактично натиснута. Подія може бути оброблена таким чином, не відстежуючи, оскільки вона походить від того, що ми називаємо "апаратним перериванням", яке коротко попереджує запущений код для запуску події.

У деяких інтерфейсах користувача та ігрових рамок використовується щось, що називається "цикл повідомлень", який чергає події для виконання на деякий пізній (зазвичай короткий) часовий проміжок часу, але вам все одно потрібно апаратне переривання, щоб перенести цю подію в цикл повідомлень в першу чергу.


54
Можливо, варто зазначити причину відсутності витрат до натискання кнопки, оскільки кнопки "спеціальні", комп'ютер має перерви та інші спеціальні засоби, якими може користуватися ОС, які абстрагуються у додатках простору користувачів.
whatsisname

46
@whatsisname, хоча це дуже глибоко під кришкою, на практиці ігрові двигуни, ймовірно, не працюють з перервами, але насправді все ще опитують джерело події в циклі. Просто опитування є централізованим та оптимізованим, так що додавання більшої кількості слухачів подій не додає додаткового опитування та складності.
gntskn

7
@PieterGeerkens Я б здогадався, що gntskn означав, що в рамках циклу ігрового двигуна є крок, який перевіряє наявність будь-яких визначних подій. Події обробляються під час кожного циклу разом з усіма іншими діями один раз на цикл. Там не буде окремий цикл для перевірки на події.
Джошуа Тейлор

2
@Voo: Тим більше причин не вникати в цей рівень деталізації у цій публікації.
Роберт Харві

2
@Voo: Я кажу про такі кнопки, як фізичні клавіші на клавіатурі та кнопки миші.
whatsisname

52

Слухач подій, схожий на підписку на розсилку електронної пошти (ви реєструєтесь, щоб отримувати оновлення, передача яких пізніше ініціюється відправником), а не нескінченно оновлюючи веб-сторінку (де саме ви ініціюєте передачу інформації).

Система подій реалізована за допомогою об'єктів подій, які керують списком абонентів. Зацікавлені об’єкти (називаються абонентами , слухачами , делегатами тощо) можуть підписатися на повідомлення про подію шляхом виклику методу, який підписується на подію, через що подія додає їх до свого списку. Всякий раз , коли подія звільнено (термінологія може також включати в себе: називається , спрацьовує , викликається , запуск і т.д.), він викликає відповідний метод по кожному з абонентів, щоб повідомити їм про подію, проходячи по будь-якому контекстної інформації , яку вони повинні розуміти , що трапилось.


38

Коротка незадовільна відповідь полягає в тому, що програма отримує сигнал (подія) і що рутина викликається лише в той момент.

Чим довше пояснення дещо більше.

Звідки беруться події клієнта?

Кожна сучасна програма має внутрішній, як правило, напівприхований "цикл подій", який передає події правильним компонентам, які повинні їх отримувати. Наприклад, подія "клацання" надсилається кнопці, поверхня якої видно за поточними координатами миші. Це на найпростішому рівні. Насправді ОС робить багато цієї диспетчеризації, оскільки деякі події та деякі компоненти отримуватимуть повідомлення безпосередньо.

Звідки беруться події програми?

Операційні системи відправляють події, як вони відбуваються. Вони роблять це реактивно, повідомляючи їх власними водіями.

Як драйвери генерують події?

Я не фахівець, але напевно, деякі користувачі CPU переривають: обладнання, яким вони керують, піднімає шпильку на ЦП, коли з'являються нові дані; центральний процесор вимикає драйвер, який обробляє вхідні дані, які в кінцевому підсумку генерують (чергу) подій, які слід відправити, а потім повертають управління назад в ОС.

Отже, як бачите, ваша програма насправді взагалі не працює. Це купа процедур, які звільняються ОС (сорти) у разі подій, але решту часу нічого не робить.


є помітні винятки, наприклад, ігри для одного разу, які можуть робити інакше


10
Ця відповідь пояснює, чому не відбувається опитування для подій клацання миші в браузері. Апаратне забезпечення генерує переривання => драйвер вирішує його на OS подія => браузер вирішує його на DOM event => JS-движок запускає слухача для цієї події.
Тібос

@Tibos afaict він також стосується подій на клавіатурі, подій таймера, подій у фарбах тощо
Sklivvz

19

Термінологія

  • подія : тип речі, що може статися.

  • Стрільба події : специфічне виникнення події; подія, що відбувається

  • Слухач подій : Щось, на що дивляться стрілянини подій.

  • Обробник подій : щось, що відбувається, коли слухач події виявляє запуск події.

  • Абонент події : відповідь, яку повинен викликати обробник події.

Ці визначення не залежать від реалізації, тому їх можна реалізувати різними способами.

Деякі з цих термінів зазвичай помилково сприймаються як синоніми, оскільки користувачам часто не потрібно розрізняти їх.

Загальні сценарії

  1. Програмно-логічні події.

    • Подія , коли який - або метод викликається.

    • Випал події є конкретним викликом до цього методу.

    • Прослуховувач подій є гак в методі події , який називається на кожному пострілі подій , який викликає обробник події.

    • Оброблювач подій викликає набір абонентів подій.

    • Передплатник події (и) виконувати будь-які дії (s) система означає , що станеться у відповідь на виникнення події.

  2. Зовнішні події.

    • Подія є зовнішнім подією , яке може бути виведено з спостережуваних.

    • Стрілянина події - це коли те, що зовнішнє подія може бути визнано таким, що стався.

    • Слухач події як - то виявляє пуски події, часто шляхом опитування спостережної (s), то він викликає обробник події при виявленні події стрільби.

    • Оброблювач подій викликає набір абонентів подій.

    • Передплатник події (и) виконувати будь-які дії (s) система означає , що станеться у відповідь на виникнення події.

Опитування проти вставлення гаків у механізм стрільби події

Справа інших, що опитування часто не є необхідним. Це тому, що слухачі подій можуть бути реалізовані, якщо вистріли події автоматично викликають обробник подій, що часто є найефективнішим способом реалізації речей, коли події є подіями на системному рівні.

За аналогією, вам не потрібно щодня перевіряти поштову скриньку, якщо поштовий працівник стукає у ваші двері та передає пошту безпосередньо вам.

Однак слухачі подій також можуть працювати шляхом опитування. Опитування не обов'язково має перевіряти конкретне значення чи інше, що спостерігається; він може бути складнішим. Але в цілому сенс опитування полягає в тому, щоб зробити висновок про те, коли якась подія сталася такою, що на неї можна реагувати.

За аналогією, ви повинні кожен день перевіряти свою поштову скриньку, коли працівник поштового зв’язку просто скидає пошту в неї. Вам не доведеться виконувати цю дільничну роботу, якби ви могли доручити поштовому працівникові постукати у ваші двері, але це часто не є можливим.

Логіка ланцюга подій

У багатьох мовах програмування ви можете записати подію, яка щойно викликається при натисканні клавіші на клавіатурі або в певний час. Хоча це зовнішні події, не потрібно їх опитувати. Чому?

Це тому, що операційна система опитує для вас. Наприклад, Windows перевіряє такі речі, як зміни стану клавіатури, і якщо вона виявить, вона зателефонує абонентам подій. Отже, коли ви підписуєтесь на подію на клавіатурі, ви фактично підписуєтесь на подію, яка сама є підписником на подію, яка опитується.

За аналогією, скажіть, що ви живете в квартирному комплексі, а працівник поштового зв’язку скидає пошту в зону отримання комунальної пошти. Потім працівник, схожий на операційну систему, може перевірити цю пошту для всіх, доставляючи пошту до квартир тих, хто щось отримав. Це позбавляє всіх інших від проблем опитування області надходження пошти.


Моя інтуїція припускає, що слухач події постійно перевіряє, чи подія була звільнена, тобто, за моїм сценарієм, це було б не інакше, ніж перевірка кожного кадру, якщо подію було знято.

Виходячи з дискусії на уроці, здається, що слухач подій працює по-іншому.

Як працює слухач подій?

Як ви підозрювали, подія може діяти шляхом опитування. І якщо подія якимось чином пов’язана із зовнішніми подіями, наприклад, натисканням клавіші клавіатури, опитування має відбутися в якийсь момент.

Так само вірно, що події не обов'язково повинні включати опитування. Наприклад, якщо подія відбувається при натисканні кнопки, то слухач подій цієї кнопки - це метод, який може закликати рамка GUI, коли визначить, що натискання кнопки натискає кнопку. У цьому випадку опитування все ж повинно відбуватися, щоб виявити клацання миші, але слухач миші є більш пасивним елементом, з'єднаним із механізмом примітивного опитування через ланцюжок подій.

Оновлення: на низькому рівні апаратного опитування

Виявляється, що USB-пристрої та інші сучасні протоколи зв'язку мають досить захоплюючий набір мережевих протоколів для взаємодій, що дозволяє пристроям вводу-виводу, включаючи клавіатури та миші, займатися тимчасовими топологіями.

Цікаво, що " переривання " є досить імперативними, синхронними речами, тому вони не обробляють спеціальні топології мереж. Щоб виправити це, " переривання " були узагальнені в асинхронні пакети з високим пріоритетом, які називаються " транзакції переривання " (в контексті USB) або " перерви з сигналізацією повідомлення " (в контексті PCI). Цей протокол описаний у специфікації USB:

введіть тут опис зображення

- " Малюнок 8-31. Масштабний стан / управління / переривання OUT станції хоста транзакцій " в "Універсальна специфікація послідовних шин, версія 2" , надрукована сторінка-222; PDF-сторінка-250 (2000-04-27)

Суть полягає в тому, що пристрої вводу-виводу та компоненти зв'язку (як USB-концентратори) в основному діють як мережеві пристрої. Отже, вони надсилають повідомлення, що вимагає опитування своїх портів тощо. Це зменшує потребу у виділених апаратних лініях.

Операційні системи , такі як Windows , здається, обробляти сам процес опитування, наприклад , як описано в документації MSDN для USB_ENDPOINT_DESCRIPTOR«з , який описує , як управляти тим, як часто для Windows опитує контролер USB хост для переривання / ізохронними повідомлень:

bIntervalЗначення містить інтервал опитування для переривання і ізохронних кінцевих точок. Для інших типів кінцевої точки це значення слід ігнорувати. Це значення відображає конфігурацію пристрою в прошивці. Водії не можуть його змінити.

Інтервал опитування разом зі швидкістю пристрою та типом хост-контролера визначають частоту, з якою драйвер повинен ініціювати переривання або ізохронну передачу. Значення в bIntervalне відображає фіксовану кількість часу. Це відносне значення, і фактична частота опитування також буде залежати від того, чи працюють пристрій та контролер USB-хоста з низькою, повною або високою швидкістю.

- "Структура USB_ENDPOINT_DESCRIPTOR" , Hardware Dev Center, Microsoft

Нові протоколи підключення монітора, як DisplayPort, схоже, роблять те саме:

Багатопотоковий транспорт (MST)

  • MST (багатопотоковий транспорт) додано в DisplayPort Ver.1.2

    • У версії 1.1а було доступно лише SST (однопотоковий транспорт)
  • MST транспортує декілька потоків A / V через один роз'єм

    • До 63 потоків; не "Потік за провулок"

      • Жодна синхронність не передбачається серед транспортованих потоків; один потік може перебувати в періоді спокою, а інший - ні
    • Транспорт, орієнтований на зв’язок

      • Шлях від джерела потоку до цільового потоку потоку, встановленого за допомогою транзакцій з повідомленнями через AUX CHʼs до початку передачі потоку

      • Додавання / видалення потоку, не впливаючи на інші потоки

введіть тут опис зображення

-Slide # 14 від "DisplayPortTM Ver.1.2 Огляд" (2010-12-06)

Ця абстракція дозволяє отримати деякі акуратні функції, як-от запуск 3 моніторів з одного з'єднання:

Багатопотоковий транспорт DisplayPort також дозволяє з'єднувати три або більше пристроїв разом, але в протилежному, менш орієнтованому на споживача конфігурації: одночасно керувати кількома дисплеями з одного вихідного порту.

- "DisplayPort" , Вікіпедія

У концептуальному сенсі відмовлятись від цього полягає в тому, що механізми опитування дозволяють отримати більш узагальнені послідовні комунікації, що приголомшливо, коли ви хочете отримати більш загальну функціональність. Отже, апаратне забезпечення та ОС проводять багато опитувань для логічної системи. Тоді споживачі, які підписуються на події, можуть насолоджуватися тими деталями, якими обробляє їх система нижчого рівня, без необхідності писати власні протоколи опитування / передачі повідомлень.

Зрештою, такі події, як натискання клавіш, здаються, проходять через досить цікаву серію подій, перш ніж потрапити на імперативний механізм запуску подій програмного рівня.


Щодо останнього абзацу, там, як правило, не проводиться опитування на низькому рівні, операційна система реагує на апаратні переривання, які викликаються периферійними пристроями. Комп'ютер, як правило, має багато підключених пристроїв (миша, клавіатура, дисководи, мережеві карти), і опитування їх усіх буде дуже неефективним.
Бармар

Однак ваші аналогії з доставкою пошти - саме те, як я б пояснив активність вищого рівня.
Бармар

1
@Barmar Я знаю, коли пристрої переходили на з'єднання USB, багато говорили про те, як вони перейшли від прямого генерування переривань (як це робить клавіатура PS / 2) до необхідності опитування (як це робить клавіатура USB), і деякі джерела стверджують що опитування проводиться ЦП. Але інші джерела стверджують, що це робиться на спеціалізованому контролері, який перетворює опитування в переривання для процесора.
Нат

@Barmar Чи траплялось би ви знати, що правильно? Я, мабуть, бачив, що більше джерел стверджують, що процесор проводить опитування, ніж інакше, але спеціалізований контролер для цього, здається, має більше сенсу. Я маю на увазі, я думаю, що Arduino та інші вбудовані пристрої, як правило, вимагають від центрального процесора для проведення опитування, але я не знаю про пристрої типу x86.
Nat

1
Якщо хто-небудь може підтвердити, щоб я міг оновити цю відповідь, я думаю, що сучасні пристрої вводу-виводу, наприклад, підключені через USB, безпосередньо записують у пам'ять , минаючи керування процесора (і це те, чому вони швидкі / ефективні та безпека небезпека часом ). Потім потрібна сучасна ОС для опитування пам'яті, щоб перевірити наявність нових повідомлень.
Нат

8

Потягніть проти Push

Існує дві основні стратегії, щоб перевірити, чи відбулася подія чи досягнуто конкретного стану. Наприклад, уявіть, що чекаєте важливої ​​доставки:

  • Потягніть : кожні 10 хвилин спускайтеся до своєї поштової скриньки і перевіряйте, чи вона доставлена,
  • Натисніть : скажіть хлопцеві доставки, щоб зателефонував вам, коли він здійснить доставку.

Підхід " тягнення" (також його називають опитуванням) простіший: його можна реалізувати без будь-якої особливої ​​функції. З іншого боку, це часто менш ефективно, оскільки ви ризикуєте зробити додаткові перевірки, не маючи на що показати.

З іншого боку, push- підхід, як правило, більш ефективний: ваш код працює лише тоді, коли він має щось робити. З іншого боку, він вимагає існування механізму для реєстрації слухача / спостерігача / зворотного виклику 1 .

1 На жаль, у моєї поштової машини, як правило, немає такого механізму.


1

Про єдність конкретного - немає іншого способу перевірити вхід гравця, окрім опитування кожного кадру. Щоб створити слухач подій, вам все одно знадобиться такий об'єкт, як "система подій" або "менеджер подій", щоб зробити опитування, тому це лише підштовхне проблему до іншого класу.

Зрозуміло, що після того, як у вас є менеджер подій, ви маєте лише один клас, який опитує вхід у кожен кадр, але це не дає явних переваг щодо продуктивності, оскільки тепер цей клас має перебирати слухачів і називати їх, які залежно від вашої гри дизайн (як, наприклад, скільки слухачів є і як часто гравець використовує введення), насправді може бути дорожчим.

Крім усього цього, пам’ятайте про золоте правило - передчасна оптимізація - корінь усього зла , що особливо вірно у відеоіграх, де часто процес візуалізації кожного кадру стоїть стільки, що невеликі оптимізації сценарію, як це, є абсолютно незначними.


Я не бачив би цикл центральних подій як оптимізацію, але як написання більш зрозумілого, зрозумілого коду на противагу опитуванню, розповсюдженому по всій базі коду. Це також дозволяє "синтетичні" події та події, які не надходять від опитування ігрового двигуна.
BlackJack

@BlackJack Я погоджуюсь, і я зазвичай сам це кодую, але ОП запитав про продуктивність. До речі, Unity має напрочуд багато сумнівних рішень щодо дизайну коду, як це, як, наприклад, статичні функції майже скрізь.
Данно

1

Якщо у вас в ОС / Framework не буде певної підтримки, яка обробляє такі події, як натискання кнопок або переповнення таймера або надходження повідомлення - вам доведеться реалізувати цей інструмент виклику слухачів подій, використовуючи опитування в будь-якому разі (десь під ним).

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

  1. Код виглядає більш чистим та ізольованим (якщо, звичайно, він реалізований правильно)
  2. Код, заснований на обробниках подій, краще витримує зміни (оскільки ви зазвичай змінюєте лише деякі обробники подій)
  3. Якщо ви переходите на платформу з підтримкою підпорядкованих подій - ви можете повторно використовувати наявні обробники подій і просто позбутися коду опитування.

Висновок - вам пощастило взяти участь у дискусії та засвоїли одну альтернативу опитуванням. Шукайте можливість застосувати цю концепцію на практиці, і ви оціните, наскільки елегантним може бути код.


1

Більшість циклів подій побудовані над деяким примітивом мультиплексування опитування, що надається операційною системою. В Linux цей примітив часто є poll(2) системним викликом (але може бути старим select). У програмах GUI сервер відображення (наприклад, Xorg або Wayland ) спілкується (через сокет (7) або трубу (7) ) з вашою програмою. Читайте також про протоколи та архітектуру системи X Window .

Такі опитувальні примітиви є ефективними; ядро на практиці пробудить ваш процес, коли буде зроблено деяке введення даних (і деяке переривання обробляється).

Конкретніше, ваша бібліотека інструментів віджетів спілкується з вашим дисплейним сервером, чекаючи повідомлень і відправляючи ці повідомлення у свої віджети. Бібліотеки інструментарію, такі як Qt або GTK, є досить складними (мільйони рядків вихідного коду). Ваша клавіатура та миша обробляються лише процесом відображення сервера (який переводить такі входи на повідомлення про події, що надсилаються клієнтським програмам).

(Я спрощую; насправді все набагато складніше)


1

У системі, що базується на опитуванні, підсистемі, яка може захотіти знати, коли відбувається якась конкретна дія, потрібно буде запустити якийсь код будь-коли, коли ця дія може відбутися. Якщо є багато підсистем, на які кожна з них повинна реагувати протягом 10 мс від якоїсь необов'язково унікальної події, всі вони повинні перевірити хоча б 100 разів / секунду, чи відбулася їх подія. Якщо ці підсистеми перебувають у різних потокових процесах (або, що ще гірше, є процесами), це потребує перемикання кожного такого потоку чи процесу 100x / секунду.

Якщо багато речей, за якими будуть дивитися додатки, є досить схожими, може бути ефективнішим мати централізовану одну підсистему моніторингу - можливо, керовану таблицею - яка може дивитися багато речей і спостерігати, чи змінилася якась із них. Наприклад, якщо є 32 комутатори, наприклад, платформа може мати функцію зчитування всіх 32 комутаторів одночасно одним словом, що дозволяє коду монітора перевірити, чи змінилися якісь перемикачі між опитуваннями, а якщо ні - ні турбуйтеся про те, який код може їх зацікавити.

Якщо існує багато підсистем, які хочуть отримувати сповіщення про щось, якщо спеціальна підсистема моніторингу сповіщає інші підсистеми, коли трапляються події, які їх цікавлять, може бути ефективнішим, ніж кожна підсистема опитує власні події. Створення спеціальної підсистеми моніторингу у випадках, коли ніхто не зацікавлений у будь-яких подіях, однак, означало б чисту трату ресурсів. Якщо є лише кілька підсистем, які зацікавлені у подіях, вартість спостереження за подіями, які їх цікавлять, може бути меншою, ніж витрати на створення загальної цільової підсистеми моніторингу, але беззбитковість Точка буде суттєво відрізнятися між різними платформами.


0

Слухач події - це як вухо, яке чекає повідомлення. Коли подія відбувається, підпрограма, обрана як слухач подій, працює з використанням аргументів події.

Завжди є два важливі дані: момент, коли відбувається подія, і об'єкт, де ця подія відбувається. Інший аргумент - це більше даних про те, що сталося.

Слухач події визначає реакцію на те, що відбувається.


0

Слухач подій дотримується шаблону публікації / підписки (як підписник)

У своєму найпростішому вигляді видавничий об’єкт підтримує перелік інструкцій підписників, які слід виконати, коли щось потрібно опублікувати.

У ньому буде якийсь subscribe(x)метод, де х залежить від того, як призначений обробник подій для обробки події. Коли викликається підписка (x), x додається до списку видавців інструкцій / посилань абонентів.

Видавець може містити всю, певну логіку поводження з подією або жодну з них. Він може просто вимагати посилань на передплатників, щоб сповістити / перетворити їх за вказаною логікою, коли подія відбувається. Він може не містити логіки і вимагати абонентських об'єктів (методів / слухачів подій), які можуть обробляти подію. Найімовірніше містити суміш обох.

У разі події видавець повторить і виконає свою логіку для кожного елемента у своєму списку інструкцій / посилань передплатників.

Наскільки б складним не виглядав обробник подій, в його основі він дотримується цієї простої схеми.

Приклади

Для прикладу слухача подій ви надаєте метод / функцію / інструкцію / слухача подій методу Subscribe () обробника подій. Обробник подій додає метод до свого списку зворотних викликів абонентів. Коли подія відбувається, обробник подій перебирає список і виконує кожен зворотний виклик.

На прикладі реального світу, коли ви підписуєтесь на розсилку новин на Stack Exchange, у таблицю бази підписників буде додано посилання на ваш профіль. Коли настає час опублікувати інформаційний бюлетень, посилання буде використано для заповнення шаблону бюлетеня, і воно буде надіслане на ваш електронний лист. У цьому випадку x - це просто посилання на вас, а видавець має набір внутрішніх інструкцій, які використовуються для всіх передплатників.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.