text: import html
  import json
  import random
  from datetime import datetime
  from typing import Optional, List
  import time
  import locale
  
  import requests
  from telegram.error import BadRequest, Unauthorized
  from telegram import Message, Chat, Update, Bot, MessageEntity, InlineKeyboardMarkup
  from telegram import ParseMode
  from telegram.ext import CommandHandler, run_async, Filters
  from telegram.utils.helpers import escape_markdown, mention_html, mention_markdown
  
  from emilia import dispatcher, OWNER_ID, SUDO_USERS, SUPPORT_USERS, WHITELIST_USERS, BAN_STICKER, spamcheck, MAPS_API
  from emilia.__main__ import STATS, USER_INFO
  from emilia.modules.disable import DisableAbleCommandHandler
  from emilia.modules.helper_funcs.extraction import extract_user
  from emilia.modules.helper_funcs.filters import CustomFilters
  from emilia.modules.helper_funcs.msg_types import get_message_type
  from emilia.modules.helper_funcs.misc import build_keyboard_alternate
  
  from emilia.modules.languages import tl
  from emilia.modules.sql import languages_sql as lang_sql
  import emilia.modules.sql.feds_sql as feds_sql
  from emilia.modules.helper_funcs.alternate import send_message
  
  # Change language locale to Indonesia
  # Install language:
  # - sudo apt-get install language-pack-id language-pack-id-base manpages
  # locale.setlocale(locale.LC_TIME, 'id_ID.UTF-8')
  
  RUN_STRINGS = (
      "Kemana Anda pikir Anda akan pergi?",
      "Hah? apa? apakah mereka lolos?",
      "ZZzzZZzz... Hah? apa? oh... hanya mereka lagi, lupakan saja.",
      "Kembali kesini!",
      "Tidak terlalu cepat...",
      "Jangan lari-lari di ruangan! 😠",
      "Jangan tinggalkan aku sendiri bersama mereka!! 😧",
      "Anda lari, Anda mati.",
      "Lelucon pada Anda, saya ada di mana-mana 😏",
      "Anda akan menyesalinya...",
      "Anda juga bisa mencoba /kickme, saya dengar itu menyenangkan 😄",
      "Ganggulah orang lain, tidak ada yang peduli 😒",
      "Anda bisa lari, tetapi Anda tidak bisa bersembunyi.",
      "Apakah itu semua yang kamu punya?",
      "Saya di belakang Anda...",
      "Larilah sesuka kalian, Anda tidak dapat melarikan diri dari takdir",
      "Kita bisa melakukan ini dengan cara mudah, atau dengan cara yang sulit.",
      "Anda tidak mengerti, bukan?",
      "Ya, kamu sebaiknya lari!",
      "Tolong, ingatkan aku betapa aku peduli?",
      "Saya akan berlari lebih cepat jika saya adalah Anda.",
      "Itu pasti orang yang kita cari.",
      "Semoga peluang akan selalu menguntungkan Anda.",
      "Kata-kata terakhir yang terkenal.",
      "Dan mereka menghilang selamanya, tidak pernah terlihat lagi.",
      "\"Oh, lihat aku! Aku sangat keren, aku bisa lari dari bot!\" - orang ini",
      "Ya ya, cukup ketuk /kickme saja 😏",
      "Ini, ambil cincin ini dan pergi ke Mordor saat Anda berada di sana.",
      "Legenda mengatakan, mereka masih berlari...",
      "Tidak seperti Harry Potter, orang tuamu tidak bisa melindungimu dariku.",
      "Ketakutan menyebabkan kemarahan. Kemarahan menyebabkan kebencian. Kebencian menyebabkan penderitaan. "
      "Jika Anda terus berlari ketakutan, Anda mungkin menjadi Vader berikutnya.",
      "Darah hanya menyebabkan darah, dan kekerasan melahirkan kekerasan. Tidak lebih. Balas dendam hanyalah nama lain untuk pembunuhan."
      "Jika anda terus berlari dan mengganggu yang lain, maka saya akan membalaskan dendam untuk yang terganggu.",
      "Teruskan, tidak yakin kami ingin Anda di sini.",
      "Anda seorang penyi- Oh. Tunggu. Kamu bukan Harry, lanjutkan berlari.",
      "DILARANG BERLARI DI KORIDOR! 😠",
      "Vale, deliciae.",
      "Siapa yang membiarkan anjing-anjing itu keluar?",
      "Itu lucu, karena tidak ada yang peduli.",
      "Ah, sayang sekali. Saya suka yang itu.",
      "Terus terang, aku tidak peduli.",
      "Saya tidak peduli dengan anda... Jadi, lari lebih cepat!",
      "Anda tidak bisa MENANGANI kebenaran!",
      "Dulu, di galaksi yang sangat jauh... Seseorang pasti peduli dengan dia.",
      "Hei, lihat mereka! Mereka berlari dari Emilia yang tak terelakkan ... Lucu sekali 😂",
      "Han menembak lebih dulu. Begitu juga saya.",
      "Apa yang kamu kejar? kelinci putih?",
      "Sepertinya dokter akan mengatakan... LARI!",
  )
  
  SLAP_TEMPLATES = (
      "{user1} {hits} {user2} dengan {item}.",
      "{user1} {hits} {user2} di mukanya dengan {item}.",
      "{user1} {hits} {user2} dengan keras menggunakan {item}.",
      "{user1} {throws} sebuah {item} ke {user2}.",
      "{user1} meraih sebuah {item} dan {throws} itu di wajah {user2}.",
      "{user1} melempar sebuah {item} ke {user2}.",
      "{user1} mulai menampar konyol {user2} dengan {item}.",
      "{user1} menusuk {user2} dan berulang kali {hits} dia dengan {item}.",
      "{user1} {hits} {user2} dengan sebuah {item}.",
      "{user1} mengikat {user2} ke kursi dan {throws} sebuah {item}.",
      "{user1} memberikan dorongan ramah untuk membantu {user2} belajar berenang di lava."
  )
  
  ITEMS = (
      "wajan besi cor",
      "ikan tongkol",
      "tongkat pemukul baseball",
      "pedang excalibur",
      "tongkat kayu",
      "paku",
      "mesin pencetak",
      "sekop",
      "monitor CRT",
      "buku pelajaran fisika",
      "pemanggang roti",
      "potret Richard Stallman",
      "televisi",
      "lima ton truk",
      "gulungan lakban",
      "buku",
      "laptop",
      "televisi lama",
      "karung batu",
      "ikan lele",
      "gas LPG",
      "tongkat pemukul berduri",
      "pemadam api",
      "batu yang berat",
      "potongan kotoran",
      "sarang lebah",
      "sepotong daging busuk",
      "beruang",
      "sekarung batu bata",
  )
  
  THROW = (
      "melempar",
      "melempar",
      "membuang",
      "melempar",
  )
  
  HIT = (
      "memukul",
      "memukul",
      "menampar",
      "memukul",
      "menampar keras",
  )
  
  GMAPS_LOC = "https://maps.googleapis.com/maps/api/geocode/json"
  GMAPS_TIME = "https://maps.googleapis.com/maps/api/timezone/json"
  
  
  @run_async
  @spamcheck
  def runs(update, context):
      send_message(update.effective_message, random.choice(tl(update.effective_message, "RUN_STRINGS")))
  
  @run_async
  @spamcheck
  def slap(update, context):
      args = context.args
      msg = update.effective_message  # type: Optional[Message]
  
      # reply to correct message
      reply_text = msg.reply_to_message.reply_text if msg.reply_to_message else msg.reply_text
  
      # get user who sent message
      #if msg.from_user.username:
      #    curr_user = "@" + escape_markdown(msg.from_user.username)
      #else:
      curr_user = "{}".format(mention_markdown(msg.from_user.id, msg.from_user.first_name))
  
      user_id = extract_user(update.effective_message, args)
      if user_id and user_id != "error":
          slapped_user = context.bot.get_chat(user_id)
          user1 = curr_user
          #if slapped_user.username:
          #    user2 = "@" + escape_markdown(slapped_user.username)
          #else:
          user2 = "{}".format(mention_markdown(slapped_user.id, slapped_user.first_name))
  
      # if no target found, bot targets the sender
      else:
          user1 = "{}".format(mention_markdown(context.bot.id, context.bot.first_name))
          user2 = curr_user
  
      temp = random.choice(tl(update.effective_message, "SLAP_TEMPLATES"))
      item = random.choice(tl(update.effective_message, "ITEMS"))
      hit = random.choice(tl(update.effective_message, "HIT"))
      throw = random.choice(tl(update.effective_message, "THROW"))
  
      repl = temp.format(user1=user1, user2=user2, item=item, hits=hit, throws=throw)
  
      send_message(update.effective_message, repl, parse_mode=ParseMode.MARKDOWN)
  
  
  @run_async
  def get_bot_ip(update, context):
      """ Sends the bot's IP address, so as to be able to ssh in if necessary.
          OWNER ONLY.
      """
      res = requests.get("http://ipinfo.io/ip")
      send_message(update.effective_message, res.text)
  
  
  @run_async
  @spamcheck
  def get_id(update, context):
      args = context.args
      user_id = extract_user(update.effective_message, args)
      if user_id and user_id != "error":
          if update.effective_message.reply_to_message and update.effective_message.reply_to_message.forward_from:
              user1 = update.effective_message.reply_to_message.from_user
              user2 = update.effective_message.reply_to_message.forward_from
              text = tl(update.effective_message, "Pengirim asli, {}, memiliki ID `{}`.\nSi penerus pesan, {}, memiliki ID `{}`.").format(
                      escape_markdown(user2.first_name),
                      user2.id,
                      escape_markdown(user1.first_name),
                      user1.id)
              if update.effective_message.chat.type != "private":
                  text += "\n" + tl(update.effective_message, "Id grup ini adalah `{}`.").format(update.effective_message.chat.id)
              send_message(update.effective_message, 
                  text,
                  parse_mode=ParseMode.MARKDOWN)
          else:
              user = context.bot.get_chat(user_id)
              text = tl(update.effective_message, "Id {} adalah `{}`.").format(escape_markdown(user.first_name), user.id)
              if update.effective_message.chat.type != "private":
                  text += "\n" + tl(update.effective_message, "Id grup ini adalah `{}`.").format(update.effective_message.chat.id)
              send_message(update.effective_message, text,
                                                  parse_mode=ParseMode.MARKDOWN)
      elif user_id == "error":
          try:
              user = context.bot.get_chat(args[0])
          except BadRequest:
              send_message(update.effective_message, "Error: Unknown User/Chat!")
              return
          text = tl(update.effective_message, "Id Anda adalah `{}`.").format(update.effective_message.from_user.id)
          text += "\n" + tl(update.effective_message, "Id grup tersebut adalah `{}`.").format(user.id)
          if update.effective_message.chat.type != "private":
              text += "\n" + tl(update.effective_message, "Id grup ini adalah `{}`.").format(update.effective_message.chat.id)
          send_message(update.effective_message, text, parse_mode=ParseMode.MARKDOWN)
      else:
          chat = update.effective_chat  # type: Optional[Chat]
          if chat.type == "private":
              send_message(update.effective_message, tl(update.effective_message, "Id Anda adalah `{}`.").format(update.effective_message.from_user.id),
                                                  parse_mode=ParseMode.MARKDOWN)
  
          else:
              send_message(update.effective_message, tl(update.effective_message, "Id Anda adalah `{}`.").format(update.effective_message.from_user.id) + "\n" + tl(update.effective_message, "Id grup ini adalah `{}`.").format(chat.id),
                                                  parse_mode=ParseMode.MARKDOWN)
  
  
  @run_async
  @spamcheck
  def info(update, context):
      args = context.args
      msg = update.effective_message  # type: Optional[Message]
      chat = update.effective_chat  # type: Optional[Chat]
      user_id = extract_user(update.effective_message, args)
  
      if user_id and user_id != "error":
          user = context.bot.get_chat(user_id)
  
      elif not msg.reply_to_message and not args:
          user = msg.from_user
  
      elif not msg.reply_to_message and (not args or (
              len(args) >= 1 and not args[0].startswith("@") and not args[0].isdigit() and not msg.parse_entities(
          [MessageEntity.TEXT_MENTION]))):
          send_message(update.effective_message, tl(update.effective_message, "Saya tidak dapat mengekstrak pengguna dari ini."))
          return
  
      else:
          return
  
      text = tl(update.effective_message, "<b>Info Pengguna</b>:") \
             + "\nID: <code>{}</code>".format(user.id) + \
             tl(update.effective_message, "\nNama depan: {}").format(html.escape(user.first_name))
  
      if user.last_name:
          text += tl(update.effective_message, "\nNama belakang: {}").format(html.escape(user.last_name))
  
      if user.username:
          text += tl(update.effective_message, "\nNama pengguna: @{}").format(html.escape(user.username))
  
      text += tl(update.effective_message, "\nTautan pengguna permanen: {}").format(mention_html(user.id, "link"))
  
      if user.id == OWNER_ID:
          text += tl(update.effective_message, "\n\nOrang ini adalah pemilik saya - saya tidak akan pernah melakukan apa pun terhadap mereka!")
      else:
          if user.id in SUDO_USERS:
              text += tl(update.effective_message, "\n\nOrang ini adalah salah satu pengguna sudo saya! " \
                      "Hampir sama kuatnya dengan pemilik saya - jadi tontonlah.")
          else:
              if user.id in SUPPORT_USERS:
                  text += tl(update.effective_message, "\n\nOrang ini adalah salah satu pengguna dukungan saya! " \
                          "Tidak sekuat pengguna sudo, tetapi masih dapat menyingkirkan Anda dari peta.")
  
              if user.id in WHITELIST_USERS:
                  text += tl(update.effective_message, "\n\nOrang ini telah dimasukkan dalam daftar putih! " \
                          "Itu berarti saya tidak diizinkan untuk melarang/menendang mereka.")
  
      fedowner = feds_sql.get_user_owner_fed_name(user.id)
      if fedowner:
          text += tl(update.effective_message, "\n\n<b>Pengguna ini adalah pemilik federasi ini:</b>\n<code>")
          text += "</code>, <code>".join(fedowner)
          text += "</code>"
      # fedadmin = feds_sql.get_user_admin_fed_name(user.id)
      # if fedadmin:
      #     text += tl(update.effective_message, "\n\nThis user is a fed admin in the current federation:\n")
      #     text += ", ".join(fedadmin)
  
      for mod in USER_INFO:
          mod_info = mod.__user_info__(user.id, chat.id).strip()
          if mod_info:
              text += "\n\n" + mod_info
  
      send_message(update.effective_message, text, parse_mode=ParseMode.HTML)
  
  
  @run_async
  @spamcheck
  def get_time(update, context):
      args = context.args
      location = " ".join(args)
      if location.lower() == context.bot.first_name.lower():
          send_message(update.effective_message, tl(update.effective_message, "Selalu ada waktu banned untukku!"))
          context.bot.send_sticker(update.effective_chat.id, BAN_STICKER)
          return
  
      res = requests.get(GMAPS_LOC, params=dict(address=location, key=MAPS_API))
      print(res.text)
  
      if res.status_code == 200:
          loc = json.loads(res.text)
          if loc.get('status') == 'OK':
              lat = loc['results'][0]['geometry']['location']['lat']
              long = loc['results'][0]['geometry']['location']['lng']
  
              country = None
              city = None
  
              address_parts = loc['results'][0]['address_components']
              for part in address_parts:
                  if 'country' in part['types']:
                      country = part.get('long_name')
                  if 'administrative_area_level_1' in part['types'] and not city:
                      city = part.get('long_name')
                  if 'locality' in part['types']:
                      city = part.get('long_name')
  
              if city and country:
                  location = "{}, {}".format(city, country)
              elif country:
                  location = country
  
              timenow = int(datetime.utcnow().timestamp())
              res = requests.get(GMAPS_TIME, params=dict(location="{},{}".format(lat, long), timestamp=timenow))
              if res.status_code == 200:
                  offset = json.loads(res.text)['dstOffset']
                  timestamp = json.loads(res.text)['rawOffset']
                  time_there = datetime.fromtimestamp(timenow + timestamp + offset).strftime("%H:%M:%S hari %A %d %B")
                  send_message(update.effective_message, "Sekarang pukul {} di {}".format(time_there, location))
  
  
  @run_async
  @spamcheck
  def get_time_alt(update, context):
      args = context.args
      if args:
          location = " ".join(args)
          if location.lower() == context.bot.first_name.lower():
              send_message(update.effective_message, "Selalu ada waktu banned untukku!")
              context.bot.send_sticker(update.effective_chat.id, BAN_STICKER)
              return
  
          res = requests.get('https://dev.virtualearth.net/REST/v1/timezone/?query={}&key={}'.format(location, MAPS_API))
  
          if res.status_code == 200:
              loc = res.json()
              if len(loc['resourceSets'][0]['resources'][0]['timeZoneAtLocation']) == 0:
                  send_message(update.effective_message, tl(update.effective_message, "Lokasi tidak di temukan!"))
                  return
              placename = loc['resourceSets'][0]['resources'][0]['timeZoneAtLocation'][0]['placeName']
              localtime = loc['resourceSets'][0]['resources'][0]['timeZoneAtLocation'][0]['timeZone'][0]['convertedTime']['localTime']
              if lang_sql.get_lang(update.effective_chat.id) == "id":
                  locale.setlocale(locale.LC_TIME, 'id_ID.UTF-8')
                  time = datetime.strptime(localtime, '%Y-%m-%dT%H:%M:%S').strftime("%H:%M:%S hari %A, %d %B")
              else:
                  time = datetime.strptime(localtime, '%Y-%m-%dT%H:%M:%S').strftime("%H:%M:%S %A, %d %B")
              send_message(update.effective_message, tl(update.effective_message, "Sekarang pukul `{}` di `{}`").format(time, placename), parse_mode="markdown")
      else:
          send_message(update.effective_message, tl(update.effective_message, "Gunakan `/time nama daerah`\nMisal: `/time jakarta`"), parse_mode="markdown")
  
  
  @run_async
  def echo(update, context):
      message = update.effective_message
      chat_id = update.effective_chat.id
      try:
          message.delete()
      except BadRequest:
          pass
      # Advanced
      text, data_type, content, buttons = get_message_type(message)
      tombol = build_keyboard_alternate(buttons)
      if str(data_type) in ('Types.BUTTON_TEXT', 'Types.TEXT'):
          try:
              if message.reply_to_message:
                  context.bot.send_message(chat_id, text, parse_mode="markdown", reply_to_message_id=message.reply_to_message.message_id, disable_web_page_preview=True, reply_markup=InlineKeyboardMarkup(tombol))
              else:
                  context.bot.send_message(chat_id, text, quote=False, disable_web_page_preview=True, parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(tombol))
          except BadRequest:
              context.bot.send_message(chat_id, tl(update.effective_message, "Teks markdown salah!\nJika anda tidak tahu apa itu markdown, silahkan ketik `/markdownhelp` pada PM."), parse_mode="markdown")
              return
  
  
  @run_async
  @spamcheck
  def markdown_help(update, context):
      send_message(update.effective_message, tl(update.effective_message, "MARKDOWN_HELP").format(dispatcher.bot.first_name), parse_mode=ParseMode.HTML)
      send_message(update.effective_message, tl(update.effective_message, "Coba teruskan pesan berikut kepada saya, dan Anda akan lihat!"))
      send_message(update.effective_message, tl(update.effective_message, "/save test Ini adalah tes markdown. _miring_, *tebal*, `kode`, "
                                          "[URL](contoh.com) [tombol](buttonurl:github.com) "
                                          "[tombol2](buttonurl:google.com:same)"))
  
  
  @run_async
  def stats(update, context):
      send_message(update.effective_message, tl(update.effective_message, "Statistik saat ini:\n") + "\n".join([mod.__stats__() for mod in STATS]))
  
  
  # /ip is for private use
  __help__ = "misc_help"
  
  __mod_name__ = "Misc"
  
  ID_HANDLER = DisableAbleCommandHandler("id", get_id, pass_args=True)
  IP_HANDLER = CommandHandler("ip", get_bot_ip, filters=Filters.chat(OWNER_ID))
  
  TIME_HANDLER = DisableAbleCommandHandler("time", get_time_alt, pass_args=True)
  
  RUNS_HANDLER = DisableAbleCommandHandler(["runs", "lari"], runs)
  SLAP_HANDLER = DisableAbleCommandHandler("slap", slap, pass_args=True)
  INFO_HANDLER = DisableAbleCommandHandler("info", info, pass_args=True)
  
  ECHO_HANDLER = CommandHandler("echo", echo, filters=Filters.user(OWNER_ID))
  MD_HELP_HANDLER = CommandHandler("markdownhelp", markdown_help, filters=Filters.private)
  
  STATS_HANDLER = CommandHandler("stats", stats, filters=CustomFilters.sudo_filter)
  
  dispatcher.add_handler(ID_HANDLER)
  dispatcher.add_handler(IP_HANDLER)
  dispatcher.add_handler(TIME_HANDLER)
  dispatcher.add_handler(RUNS_HANDLER)
  dispatcher.add_handler(SLAP_HANDLER)
  dispatcher.add_handler(INFO_HANDLER)
  dispatcher.add_handler(ECHO_HANDLER)
  dispatcher.add_handler(MD_HELP_HANDLER)
  dispatcher.add_handler(STATS_HANDLER)
  