Ke kākau ʻana i kahi bot telegram ma R (mahele 2): Hoʻohui i ke kākoʻo kauoha a me nā kānana memo i ka bot

В hoʻopuka mua Ua noʻonoʻo mākou pehea e hana ai i kahi bot, hoʻomaka i kahi laʻana o ka papa Bot a ua kamaʻāina i nā ʻano o ka hoʻouna ʻana i nā leka me ka hoʻohana ʻana iā ia.

Ma kēia ʻatikala hoʻomau wau i kēia kumuhana, no laila ke paipai nei au e hoʻomaka e heluhelu i kēia ʻatikala ma hope o ka heluhelu ʻana ʻO ka hapa mua.

I kēia manawa e noʻonoʻo mākou pehea e hoʻōla ai i kā mākou bot a hoʻohui i ke kākoʻo kauoha iā ia, a e kamaʻāina pū me ka papa. Updater.

I ka wā o ka ʻatikala, e kākau mākou i kekahi mau bots maʻalahi, ʻo ka mea hope, e pili ana i ka lā i hāʻawi ʻia a me ka code ʻāina, e hoʻoholo inā he lā ma kahi ʻāina i hāʻawi ʻia he hopena pule a i ʻole he lā hana e like me ka kalena hana. Akā, e like me ka wā ma mua, ʻo ke kumu o ka ʻatikala e hoʻomaʻamaʻa iā ʻoe me ka interface pack telegram.bot e hoʻoponopono i kāu mau pilikia ponoʻī.

Ke kākau ʻana i kahi bot telegram ma R (mahele 2): Hoʻohui i ke kākoʻo kauoha a me nā kānana memo i ka bot

ʻO nā ʻatikala āpau mai ka moʻo "Kākau i kahi bot telegram ma R"

  1. Hana mākou i kahi bot a hoʻohana iā ia e hoʻouna i nā leka ma ke kelepona
  2. Hoʻohui i ke kākoʻo kauoha a me nā kānana memo i ka bot

Nā mea

Inā makemake ʻoe i ka ʻikepili ʻikepili, makemake paha ʻoe i kaʻu telegram и Ukulele nā kahawai. Hoʻolaʻa ʻia ka hapa nui o nā mea i ka ʻōlelo R.

  1. Papa hana hou
  2. Mea lima lima
  3. E hoʻohui i ke kauoha mua i ka bot, ka mea mālama kauoha
  4. Mea hana memo a me nā kānana
  5. Hoʻohui i nā kauoha me nā ʻāpana
  6. Holo i ka bot ma ke kua
  7. hopena

Papa hana hou

Updater he papa ia e maʻalahi iā ʻoe ke hoʻomohala i kahi bot telegrama, a hoʻohana i ka papa ma lalo o ka puʻu Dispetcher. Haʻawina papa Updater e loaʻa i nā mea hou mai ka bot (ma ka ʻatikala mua ua hoʻohana mākou i ke ʻano no kēia kumu getUpdates()), a hoʻoili hou aku iā lākou i Dispetcher.

ʻO ka huli Dispetcher aia nā mea lawelawe āu i hana ai, ʻo ia hoʻi. mea papa Handler.

Mea lima lima

Me nā mea lawelawe āu e hoʻohui ai Dispetcher nā pane bot i nā hanana like ʻole. I ka manawa e kākau ai i kēia ʻatikala ma telegram.bot Ua hoʻohui ʻia nā ʻano mea lawelawe penei:

  • MessageHandler — Mea lawe memo
  • CommandHandler — Luna hooponopono kauoha
  • CallbackQueryHandler — Mea mālama ʻikepili no nā kī kī i hoʻouna ʻia mai Inline
  • ErrorHandler - Mea hoʻoponopono hewa i ka wā e noi ana i nā mea hou mai ka bot

E hoʻohui i ke kauoha mua i ka bot, ka mea mālama kauoha

Inā ʻaʻole ʻoe i hoʻohana i nā bots ma mua a ʻaʻole ʻoe i ʻike i ke ʻano o ke kauoha, pono e hoʻouna ʻia nā kauoha i ka bot me ka hoʻohana ʻana i ka slash i mua. / me he prefix.

E hoʻomaka mākou me nā kauoha maʻalahi, ʻo ia. E aʻo kāua i kā mākou bot e ʻōlelo aloha ma ke kauoha /hi.

Code 1: Ke aʻo ʻana i ka bot e ʻōlelo aloha

library(telegram.bot)

# создаём экземпляр класса Updater
updater <- Updater('ТОКЕН ВАШЕГО БОТА')

# Пишем метод для приветсвия
say_hello <- function(bot, update) {

  # Имя пользователя с которым надо поздароваться
  user_name <- update$message$from$first_name

  # Отправка приветственного сообщения
  bot$sendMessage(update$message$chat_id, 
                  text = paste0("Моё почтение, ", user_name, "!"), 
                  parse_mode = "Markdown")

}

# создаём обработчик 
hi_hendler <- CommandHandler('hi', say_hello)

# добаляем обработчик в диспетчер
updater <- updater + hi_hendler

# запускаем бота
updater$start_polling()

E holo i ka laʻana code ma luna, ma hope o ka hoʻololi ʻana iā 'YOUR BOT TOKEN' me ka hōʻailona maoli i loaʻa iā ʻoe i ka hana ʻana i ka bot ma Hoike (Ua kamaʻilio wau e pili ana i ka hana ʻana i kahi bot i loko ʻatikala mua).

Palapala start_polling() keka Updater, ka mea i hoʻohana ʻia ma ka hope o ke code, hoʻomaka i kahi loop pau ʻole o ka noi ʻana a me ka hana ʻana i nā mea hou mai ka bot.

I kēia manawa e wehe mākou i Telegram a kākau i ke kauoha mua i kā mākou bot /hi.

Ke kākau ʻana i kahi bot telegram ma R (mahele 2): Hoʻohui i ke kākoʻo kauoha a me nā kānana memo i ka bot

I kēia manawa, hoʻomaopopo kā mākou bot i ke kauoha /hi, a ike i ke aloha ia makou.

Schematically, hiki ke hōʻike ʻia ke kaʻina hana o ke kūkulu ʻana i kahi bot maʻalahi e like me kēia.

Ke kākau ʻana i kahi bot telegram ma R (mahele 2): Hoʻohui i ke kākoʻo kauoha a me nā kānana memo i ka bot

  1. E hana i kahi laʻana o ka papa Updater;
  2. Hana mākou i nā ʻano, ʻo ia. nā hana a kā mākou bot e hana ai. I ka laʻana code he hana kēia say_hello(). ʻO nā hana āu e hoʻohana ai e like me nā ala bot pono e loaʻa i ʻelua mau manaʻo koi - bot и IeAIIeXIAaIEN, a hoʻokahi koho - ke kumu. Hoʻopaʻapaʻa bot, ʻo kāu bot kēia, me kāna kōkua hiki iā ʻoe ke pane i nā memo, hoʻouna i nā memo, a i ʻole e hoʻohana i nā ala ʻē aʻe i loaʻa i ka bot. Hoʻopaʻapaʻa IeAIIeXIAaIEN ʻO kēia ka mea i loaʻa i ka bot mai ka mea hoʻohana, ʻoiaʻiʻo, nā mea i loaʻa iā mākou ma ka ʻatikala mua e hoʻohana ana i ke ʻano getUpdates(). Hoʻopaʻapaʻa ke kumu hiki iā ʻoe ke hana i nā ʻikepili hou i hoʻouna ʻia e ka mea hoʻohana me ke kauoha, e hoʻi mākou i kēia kumuhana ma hope iki;
  3. Hana mākou i nā mea lawelawe, ʻo ia. Hoʻohui mākou i kekahi mau hana mea hoʻohana me nā ʻano hana i hana ʻia ma ka pae mua. ʻO ka mea nui, ʻo ka mea hoʻokele ka mea hoʻomaka, kahi hanana e kāhea ana i kekahi hana bot. I kā mākou hiʻohiʻona, ke hoʻouna ʻia nei ke kumu i kahi kauoha /hi, a hoʻokō ʻia e ka hui hi_hendler <- CommandHandler('hi', say_hello). Hoʻopaʻapaʻa hana mua CommandHandler() hiki iā ʻoe ke kuhikuhi i kahi kauoha, i kā mākou hihia hi, kahi e pane ai ka bot. ʻO ka hoʻopaʻapaʻa ʻelua e ʻae iā ʻoe e kuhikuhi i ke ʻano bot, e kāhea mākou i ke ʻano say_hello, e hoʻokō ʻia inā kāhea ka mea hoʻohana i ke kauoha i kuhikuhi ʻia ma ka hoʻopaʻapaʻa mua;
  4. A laila, hoʻohui mākou i ka mea hana i hana ʻia i ka mea hoʻouna o kā mākou papa Updater. Hiki iā ʻoe ke hoʻohui i nā mea lawelawe ma nā ʻano he nui; i ka laʻana ma luna, ua hoʻohana wau i ka mea maʻalahi loa, me ka hoʻohana ʻana i ka hōʻailona +ʻo ia updater <- updater + hi_hendler. Hiki ke hana like me ka hoʻohana ʻana i ke ʻano add_handler(), no ka papa Dispatcher, hiki iā ʻoe ke loaʻa i kēia ala e like me kēia: updater$dispatcher$add_handler();
  5. E hoʻolele i ka bot me ke kauoha start_polling().

Mea hana memo a me nā kānana

Ua noʻonoʻo mākou pehea e hoʻouna ai i nā kauoha i ka bot, akā i kekahi manawa pono mākou i ka bot e pane ʻaʻole wale i nā kauoha, akā i kekahi mau leka uila maʻamau. No ka hana ʻana i kēia, pono ʻoe e hoʻohana i nā mea lawe memo − MessageHandler.

maʻamau MessageHandler e pane mai i nā memo a pau e hiki mai ana. No laila, hoʻohana pinepine ʻia nā mea lawelawe me nā kānana. E aʻo kāua i ka bot e ʻōlelo aloha ʻaʻole wale ma ke kauoha /hi, akā, i ka wā e puka mai ai kekahi o kēia mau huaʻōlelo ma ka leka i hoʻouna ʻia i ka bot: aloha, aloha, aloha, hai, bonjour.

I kēia manawa ʻaʻole mākou e kākau i nā ala hou, no ka mea... Loaʻa iā mākou kahi ala e aloha ai ka bot iā mākou. ʻO nā mea a pau e pono ai mākou e hana, ʻo ka hana ʻana i ka kānana pono a me ka mea lawe leka.

Code 2: E hoʻohui i kahi mea lawe memo a kānana

library(telegram.bot)

# создаём экземпляр класса Updater
updater <- Updater('ТОКЕН ВАШЕГО БОТА')

# Пишем метод для приветсвия
## команда приветвия
say_hello <- function(bot, update) {

  # Имя пользователя с которым надо поздароваться
  user_name <- update$message$from$first_name

  # Отправляем приветсвенное сообщение
  bot$sendMessage(update$message$chat_id, 
                  text = paste0("Моё почтение, ", user_name, "!"),
                  parse_mode = "Markdown",
                  reply_to_message_id = update$message$message_id)

}

# создаём фильтры
MessageFilters$hi <- BaseFilter(function(message) {

  # проверяем, встречается ли в тексте сообщения слова: привет, здравствуй, салют, хай, бонжур
  grepl(x           = message$text, 
        pattern     = 'привет|здравствуй|салют|хай|бонжур',
        ignore.case = TRUE)
  }
)

# создаём обработчик 
hi_hendler <- CommandHandler('hi', say_hello) # обработчик команды hi
hi_txt_hnd <- MessageHandler(say_hello, filters = MessageFilters$hi)

# добаляем обработчики в диспетчер
updater <- updater + 
             hi_hendler +
             hi_txt_hnd

# запускаем бота
updater$start_polling()

E holo i ka laʻana code ma luna, ma hope o ka hoʻololi ʻana iā 'YOUR BOT TOKEN' me ka hōʻailona maoli i loaʻa iā ʻoe i ka hana ʻana i ka bot ma Hoike (Ua kamaʻilio wau e pili ana i ka hana ʻana i kahi bot i loko ʻatikala mua).

E ho'āʻo kākou e hoʻouna i ka bot i nā memo i loaʻa nā huaʻōlelo aloha i helu ʻia ma mua:
Ke kākau ʻana i kahi bot telegram ma R (mahele 2): Hoʻohui i ke kākoʻo kauoha a me nā kānana memo i ka bot

No laila, ʻo ka mea mua, ua aʻo mākou i ka bot ʻaʻole wale e ʻōlelo aloha, akā e pane i kahi aloha. Ua hana mākou i kēia me ka hoʻohana ʻana i ka hoʻopaʻapaʻa pane_i_meka_id, i loaʻa ma ke ʻano sendMessage(), pono ʻoe e hoʻoili i ka id o ka memo āu e makemake ai e pane. Hiki iā ʻoe ke kiʻi i ka memo id penei: update$message$message_id.

Akā ʻo ka mea nui a mākou i hoʻohui ai i kahi kānana i ka bot me ka hoʻohana ʻana i ka hana BaseFilter():

# создаём фильтры
MessageFilters$hi <- BaseFilter( 

  # анонимная фильтрующая функция
  function(message) {

    # проверяем, встречается ли в тексте сообщения слова приветствия
    grepl(x           = message$text, 
          pattern     = 'привет|здравствуй|салют|хай|бонжур',
          ignore.case = TRUE)
  }

)

E like me kāu i ʻike ai, pono e hoʻohui ʻia nā kānana i ka mea MessageFilters, ka mea i loaʻa mua i kahi pūʻulu liʻiliʻi o nā kānana i hana ʻia. I kā mākou laʻana, i ka mea MessageFilters ua hoʻohui mākou i kahi mea hi, he kānana hou kēia.

E hana BaseFilter() pono ʻoe e hele i ka hana kānana. ʻO ka mea nui, ʻo kahi kānana he hana wale nō e loaʻa ai kahi memo a hoʻi mai oiaio ai ole ia, wahahee. I kā mākou laʻana, ua kākau mākou i kahi hana maʻalahi, me ka hoʻohana ʻana i ka hana kumu grepl() nānā i ka kikokikona memo a inā pili ia i ka ʻōlelo maʻamau привет|здравствуй|салют|хай|бонжур hoʻi oiaio.

A laila, hana mākou i kahi mea lawe memo hi_txt_hnd <- MessageHandler(say_hello, filters = MessageFilters$hi). Hoʻopaʻapaʻa hana mua MessageHandler() ʻO ke ala e kāhea ai i ka mea hoʻoponopono, a ʻo ka hoʻopaʻapaʻa ʻelua ʻo ia ka kānana e kapa ʻia ai. I kā mākou hihia, ʻo ia ka kānana a mākou i hana ai MessageFilters$hi.

ʻAe, i ka hopena, hoʻohui mākou i ka mea hoʻouna i ka mea hana i hana ʻia hi_txt_hnd.

updater <- updater + 
             hi_hendler +
             hi_txt_hnd

E like me kaʻu i kākau ai ma luna, i loko o ka pūʻolo telegram.bot a me ka manao MessageFilters Aia kekahi pūʻulu o nā kānana i kūkulu ʻia i hiki iā ʻoe ke hoʻohana:

  • pau — Nā memo a pau
  • kikokikona — Text messages
  • kauoha — Kauoha, i.e. nā memo e hoʻomaka me /
  • pane — Nā memo i pane i kekahi memo
  • leo — Nā memo i loaʻa kahi faila leo
  • palapala - Nā memo me kahi palapala i hoʻouna ʻia
  • kiʻi - Nā memo me nā kiʻi i hoʻouna ʻia
  • sticker - Nā memo me kahi mea hoʻopili i hoʻouna ʻia
  • wikiō — Nā memo me ka wikiō
  • leo - Nā leka leo
  • hoʻokaʻaʻike - Nā memo i loaʻa ka ʻike telegram a ka mea hoʻohana
  • wahi - Nā memo me ka geolocation
  • wahi - Nā memo i hoʻouna ʻia
  • pāʻani — Pāʻani

Inā makemake ʻoe e hoʻohui i kekahi mau kānana i hoʻokahi mea hoʻohana e hoʻohana wale i ka hōʻailona | - ma ke ʻano he loiloi OR, a hoailona & e like me ke akamai И. No ka laʻana, inā makemake ʻoe e kāhea ka bot i ke ʻano like ke loaʻa iā ia kahi wikiō, kiʻi a palapala paha, e hoʻohana i kēia hiʻohiʻona e hana i kahi mea lawe memo:

handler <- MessageHandler(callback, 
  MessageFilters$video | MessageFilters$photo | MessageFilters$document
)

Hoʻohui i nā kauoha me nā ʻāpana

Ua ʻike mua mākou i ke ʻano o nā kauoha, pehea e hana ai, a pehea e hoʻoikaika ai i ka bot e hoʻokō i ke kauoha i makemake ʻia. Akā i kekahi mau hihia, ma waho aʻe o ka inoa kauoha, pono mākou e hāʻawi i kekahi ʻikepili e hoʻokō ai.

Aia ma lalo kahi laʻana o ka bot i hāʻawi ʻia i ka lā a me ka ʻāina, e hoʻihoʻi iā ʻoe i ke ʻano o ka lā mai ka kalena hana.

Hoʻohana ka bot ma lalo i ka API kalena hana isdayoff.ru.

Code 3: Bot e hōʻike i ka lā a me ka ʻāina

library(telegram.bot)

# создаём экземпляр класса Updater
updater <- Updater('1165649194:AAFkDqIzQ6Wq5GV0YU7PmEZcv1gmWIFIB_8')

# Пишем метод для приветсвия
## команда приветвия
check_date <- function(bot, update, args) {

  # входящие данные
  day     <- args[1]  # дата
  country <- args[2]  # страна

  # проверка введённых параметров
  if ( !grepl('\d{4}-\d{2}-\d{2}', day) ) {

    # Send Custom Keyboard
    bot$sendMessage(update$message$chat_id, 
                    text = paste0(day, " - некорреткная дата, введите дату в формате ГГГГ-ММ-ДД"),
                    parse_mode = "Markdown")

  } else {
    day <- as.Date(day)
    # переводим в формат POSIXtl
    y <- format(day, "%Y")
    m <- format(day, "%m")
    d <- format(day, "%d")

  }

  # страна для проверки
  ## проверяем задана ли страна
  ## если не задана устанавливаем ru
  if ( ! country %in% c('ru', 'ua', 'by', 'kz', 'us') ) {

    # Send Custom Keyboard
    bot$sendMessage(update$message$chat_id, 
                    text = paste0(country, " - некорретктный код страны, возможнные значения: ru, by, kz, ua, us. Запрошены данные по России."),
                    parse_mode = "Markdown")

    country <- 'ru'

  }

  # запрос данных из API
  # компоновка HTTP запроса
  url <- paste0("https://isdayoff.ru/api/getdata?",
                "year=",  y, "&",
                "month=", m, "&",
                "day=",   d, "&",
                "cc=",    country, "&",
                "pre=1&",
                "covid=1")

  # получаем ответ
  res <- readLines(url)

  # интрепретация ответа
  out <- switch(res, 
                "0"   = "Рабочий день",
                "1"   = "Нерабочий день",
                "2"   = "Сокращённый рабочий день",
                "4"   = "covid-19",
                "100" = "Ошибка в дате",
                "101" = "Данные не найдены",
                "199" = "Ошибка сервиса")

  # отправляем сообщение
  bot$sendMessage(update$message$chat_id, 
                  text = paste0(day, " - ", out),
                  parse_mode = "Markdown")

}

# создаём обработчик 
date_hendler <- CommandHandler('check_date', check_date, pass_args = TRUE)

# добаляем обработчик в диспетчер
updater <- updater + date_hendler

# запускаем бота
updater$start_polling()

E holo i ka laʻana code ma luna, ma hope o ka hoʻololi ʻana iā 'YOUR BOT TOKEN' me ka hōʻailona maoli i loaʻa iā ʻoe i ka hana ʻana i ka bot ma Hoike (Ua kamaʻilio wau e pili ana i ka hana ʻana i kahi bot i loko ʻatikala mua).

Ua hana mākou i kahi bot i hoʻokahi wale nō ala i kāna arsenal check_date, ua kapa ʻia kēia ʻano e ke kauoha o ka inoa like.

Akā, ma kahi o ka inoa kauoha, pono kēia ʻano iā ʻoe e hoʻokomo i ʻelua mau palena, ka code ʻāina a me ka lā. A laila, nānā ka bot inā he hopena pule ka lā i hāʻawi ʻia ma ka ʻāina i ʻōlelo ʻia, he lā pōkole, a i ʻole he lā hana e like me ka kalena hana mana.

I mea e hiki ai i ke ala a mākou e hana ai e ʻae i nā ʻāpana ʻē aʻe me ke kauoha, e hoʻohana i ka hoʻopaʻapaʻa pass_args = TRUE ma ka hana CommandHandler(), a i ka wā e hana ai i kahi ʻano hana, me ka hoʻohui ʻana i nā hoʻopaʻapaʻa i koi ʻia bot, IeAIIeXIAaIEN hana i kahi koho - ke kumu. ʻO ke ala i hana ʻia ma kēia ala e ʻae i nā ʻāpana āu e kau ai i ka bot ma hope o ka inoa kauoha. Pono e hoʻokaʻawale ʻia nā ʻāpana e kahi ākea; e hoʻouna ʻia lākou i ke ʻano ma ke ʻano he vector kikokikona.

E hoʻomaka a hoʻāʻo i kā mākou bot.

Ke kākau ʻana i kahi bot telegram ma R (mahele 2): Hoʻohui i ke kākoʻo kauoha a me nā kānana memo i ka bot

Holo i ka bot ma ke kua

ʻO ka hana hope a mākou e hoʻopau ai, ʻo ia ka hoʻomaka ʻana i ka bot ma hope.

No ka hana ʻana i kēia, e hahai i ka algorithm i wehewehe ʻia ma lalo nei:

  1. E mālama i ka code bot i kahi faila me ka extension R. I ka hana ʻana ma RStudio, hana ʻia kēia ma o ka papa kuhikuhi File, hui Mālama i ....
  2. E hoʻohui i ke ala i ka waihona bin, aia ma ka waihona āu i hoʻokomo ai i ka ʻōlelo R, i ka ʻaoʻao Path, nā kuhikuhi. maanei.
  3. E hana i kahi waihona kikokikona maʻamau e kākau ai i 1 laina: R CMD BATCH C:UsersAlseyDocumentsmy_bot.R... Ma kahi o C:UsersAlseyDocumentsmy_bot.R e kākau i ke ala i kāu palapala bot. I ka manawa like, he mea nui ka loaʻa ʻole o nā huaʻōlelo Cyrillic a i ʻole nā ​​​​wāwae ma ke ala, no ka mea pilikia paha kēia i ka holo ʻana i ka bot. E mālama, a hoʻololi i kona hoʻonui me txt maluna o 'ōpeʻapeʻa.
  4. E wehe i ka Windows Task Scheduler, he nui nā ala e hana ai i kēia, no ka laʻana, wehe i kekahi waihona a komo i ka helu %windir%system32taskschd.msc /s. Hiki ke ʻike ʻia nā ʻano hana ʻē aʻe maanei.
  5. Ma ka ʻaoʻao ʻākau kiʻekiʻe o ka mea hoʻonohonoho, kaomi "E hana i ka hana ...".
  6. Ma ka ʻaoʻao "General", hāʻawi i kāu hana i kahi inoa maʻamau, a hoʻololi i ka hoʻololi i ka mokuʻāina "Run for all users".
  7. E hele i ka "Actions" tab, kaomi "Create". Ma ke kahua "Program or script", kaomi "Browse", e ʻimi i ka mea i hana ʻia ma ka lua 'ōpeʻapeʻa waihona a kaomi iā OK.
  8. Kaomi OK a, inā pono, e hoʻokomo i ka ʻōlelo huna no kāu moʻokāki ʻōnaehana hana.
  9. E ʻimi i ka hana i hana ʻia ma ka mea hoʻonohonoho, koho iā ia a kaomi i ke pihi "Run" ma ka ʻaoʻao ʻākau lalo.

Holo kā mākou bot ma hope a e hana ana a hiki i kou ho'ōki ʻana i ka hana, a i ʻole e hoʻopau i kāu PC a i ʻole kikowaena kahi i hoʻomaka ai.

hopena

Ma kēiaʻatikala, ua noʻonoʻo mākou pehea e kākau ai i kahi bot piha piha i hiki ʻole ke hoʻouna wale i nā memo, akā e pane pū i nā memo a me nā kauoha. Ua lawa ka ʻike i loaʻa e hoʻoponopono i ka hapa nui o kāu mau pilikia.

E kamaʻilio ka ʻatikala aʻe e pili ana i ka hoʻohui ʻana i kahi kīpē i ka bot no ka hana maʻalahi.

Kau inoa i kaʻu telegram и Ukulele nā kahawai.

Source: www.habr.com

Pākuʻi i ka manaʻo hoʻopuka