# Path: hypebot/hypecore.py
# class RequestTracker(object):
# class OutputUtil(object):
# class UserPreferences(object):
# class Core(object):
#   _REQUEST_TIMEOUT_SEC = 60
#   _PREFS = {
#       'location': 'MTV',
#       'temperature_unit': 'F',
#       'stocks': 'GOOG,GOOGL',
#       # Comma separated list of your summoner names. First is considered main.
#       'lol_summoner': None,
#       'lol_region': 'NA',
#       '_dynamite_dm': None,
#       # Maps 'user/####' to '$ldap'.
#       '_dynamite_ldap': None,
#   }
#   _SUBKEY = 'preferences'
#   def __init__(self, reply_fn: Callable) -> None:
#   def HasPendingRequest(self, user: hype_types.User) -> bool:
#   def RequestConfirmation(self,
#                           user: hype_types.User,
#                           summary: Text,
#                           request_details: Dict,
#                           action_fn: Callable,
#                           parse_fn: Optional[Callable] = None) -> None:
#   def ResolveRequest(self, user: hype_types.User, user_msg: Text) -> None:
#   def __init__(self, output_fn: Callable) -> None:
#   def LogAndOutput(self, log_level: int, channel: channel_pb2.Channel,
#                    message: hype_types.CommandResponse) -> None:
#   def Output(self, channel: channel_pb2.Channel,
#              message: hype_types.CommandResponse) -> None:
#   def __init__(self, store: storage_lib.HypeStore):
#   def IsValid(self, pref: Text) -> bool:
#   def Get(self, user: user_pb2.User, pref: Text) -> Text:
#   def Set(self, user: user_pb2.User, pref: Text, value: Text) -> None:
#   def _Set(self, user: user_pb2.User, pref: Text, value: Text,
#            tx: storage_lib.HypeTransaction) -> None:
#   def GetAll(self, user: user_pb2.User) -> Dict[Text, Text]:
#   def __init__(
#       self,
#       params: Any,  # HypeParams
#       interface: interface_lib.BaseChatInterface) -> None:
#   def Reply(self,
#             channel: hype_types.Target,
#             msg: hype_types.CommandResponse,
#             default_channel: Optional[channel_pb2.Channel] = None,
#             limit_lines: bool = False,
#             max_public_lines: int = 6,
#             user: Optional[hype_types.User] = None,
#             log: bool = False,
#             log_level: int = logging.INFO) -> None:
#   def PublishMessage(self,
#                      topic: Text,
#                      msg: hype_types.CommandResponse,
#                      notice: bool = False) -> None:
#   def ReloadData(self) -> bool:
# 
# Path: hypebot/commands/command_factory.py

# 
# Path: hypebot/core/params_lib.py
# def _ParseChannel(channel):
# def _ParseChannels(channels):
#   def __init__(self, defaults=None):
#   def __str__(self):
#   def Override(self, params):
#   def _AssignValueConvertDict(self, key, value):
#   def _ParseDict(self, params):
#   def __setattr__(self, key, value):
#   def get(self, key, default_value=None):  # pylint: disable=invalid-name
#   def AsDict(self):
#   def Lock(self):
#   def _RaiseIfLocked(self):
# def MergeParams(defaults, *overrides):
# class HypeParams(object):
#   SPECIAL_ATTRS = ['_locked']
#   HAS_DYNAMIC_ATTRIBUTES = True
# 
# Path: hypebot/interfaces/interface_factory.py

# 
# Path: hypebot/plugins/alias_lib.py
# ALIAS_SUBKEY = 'user_aliases'
# ME_REGEX = re.compile(r'\\me\b')
# ALL_ARGS_REGEX = re.compile(r'\\@:?')
# ALL_ARGS_RANGED_REGEX = re.compile(r'\\@(-?\d+)?:(-?\d+)?')
# ARGS_REGEX = re.compile(r'\\\d+')
# def GetAliases(store, user: user_pb2.User):
# def AddOrUpdateAlias(store, user: user_pb2.User, alias_name, alias_cmd):
# def RemoveAlias(store, user: user_pb2.User, alias_name):
# def ExpandAliases(store, user: user_pb2.User, msg: Text):
# def _ExpandAllSign(alias, msg_args):


import re
from absl import app
from absl import flags
from absl import logging
from hypebot import hypecore
from hypebot.commands import command_factory
from hypebot.core import params_lib
from hypebot.interfaces import interface_factory
from hypebot.plugins import alias_lib
from hypebot.protos import channel_pb2
from hypebot.protos import user_pb2
from typing import Text
        #   * exceptions
        # TODO: Figure out how to do proper activity tracking.
        if sync_reply:
          self._core.activity_tracker.RecordActivity(channel, user,
                                                     command.__class__.__name__)
        self._core.Reply(channel, sync_reply)
      except Exception:
        self._core.Reply(
            user,
            'Exception handling: %s' % msg,
            log=True,
            log_level=logging.ERROR)

    # This must come after message processing for paychecks to work properly.
    self._core.user_tracker.RecordActivity(user, channel)

  def _ProcessAliases(self, unused_channel, user: user_pb2.User, msg: Text):
    return alias_lib.ExpandAliases(self._core.cached_store, user, msg)

  NESTED_PATTERN = re.compile(
      r'\$\(([^\(\)]+'
      # TODO: Actually tokenize input
      # instead of relying on cheap hacks
      r'(?:[^\(\)]*".*?"[^\(\)]*)*)\)')

  def _ProcessNestedCalls(self, channel, user, msg):
    """Evaluate nested commands within $(...)."""
    m = self.NESTED_PATTERN.search(msg)
    while m:
      backup_interface = self._core.interface

# Path: hypebot/hypecore.py
# class RequestTracker(object):
# class OutputUtil(object):
# class UserPreferences(object):
# class Core(object):
#   _REQUEST_TIMEOUT_SEC = 60
#   _PREFS = {
#       'location': 'MTV',
#       'temperature_unit': 'F',
#       'stocks': 'GOOG,GOOGL',
#       # Comma separated list of your summoner names. First is considered main.
#       'lol_summoner': None,
#       'lol_region': 'NA',
#       '_dynamite_dm': None,
#       # Maps 'user/####' to '$ldap'.
#       '_dynamite_ldap': None,
#   }
#   _SUBKEY = 'preferences'
#   def __init__(self, reply_fn: Callable) -> None:
#   def HasPendingRequest(self, user: hype_types.User) -> bool:
#   def RequestConfirmation(self,
#                           user: hype_types.User,
#                           summary: Text,
#                           request_details: Dict,
#                           action_fn: Callable,
#                           parse_fn: Optional[Callable] = None) -> None:
#   def ResolveRequest(self, user: hype_types.User, user_msg: Text) -> None:
#   def __init__(self, output_fn: Callable) -> None:
#   def LogAndOutput(self, log_level: int, channel: channel_pb2.Channel,
#                    message: hype_types.CommandResponse) -> None:
#   def Output(self, channel: channel_pb2.Channel,
#              message: hype_types.CommandResponse) -> None:
#   def __init__(self, store: storage_lib.HypeStore):
#   def IsValid(self, pref: Text) -> bool:
#   def Get(self, user: user_pb2.User, pref: Text) -> Text:
#   def Set(self, user: user_pb2.User, pref: Text, value: Text) -> None:
#   def _Set(self, user: user_pb2.User, pref: Text, value: Text,
#            tx: storage_lib.HypeTransaction) -> None:
#   def GetAll(self, user: user_pb2.User) -> Dict[Text, Text]:
#   def __init__(
#       self,
#       params: Any,  # HypeParams
#       interface: interface_lib.BaseChatInterface) -> None:
#   def Reply(self,
#             channel: hype_types.Target,
#             msg: hype_types.CommandResponse,
#             default_channel: Optional[channel_pb2.Channel] = None,
#             limit_lines: bool = False,
#             max_public_lines: int = 6,
#             user: Optional[hype_types.User] = None,
#             log: bool = False,
#             log_level: int = logging.INFO) -> None:
#   def PublishMessage(self,
#                      topic: Text,
#                      msg: hype_types.CommandResponse,
#                      notice: bool = False) -> None:
#   def ReloadData(self) -> bool:
# 
# Path: hypebot/commands/command_factory.py

# 
# Path: hypebot/core/params_lib.py
# def _ParseChannel(channel):
# def _ParseChannels(channels):
#   def __init__(self, defaults=None):
#   def __str__(self):
#   def Override(self, params):
#   def _AssignValueConvertDict(self, key, value):
#   def _ParseDict(self, params):
#   def __setattr__(self, key, value):
#   def get(self, key, default_value=None):  # pylint: disable=invalid-name
#   def AsDict(self):
#   def Lock(self):
#   def _RaiseIfLocked(self):
# def MergeParams(defaults, *overrides):
# class HypeParams(object):
#   SPECIAL_ATTRS = ['_locked']
#   HAS_DYNAMIC_ATTRIBUTES = True
# 
# Path: hypebot/interfaces/interface_factory.py

# 
# Path: hypebot/plugins/alias_lib.py
# ALIAS_SUBKEY = 'user_aliases'
# ME_REGEX = re.compile(r'\\me\b')
# ALL_ARGS_REGEX = re.compile(r'\\@:?')
# ALL_ARGS_RANGED_REGEX = re.compile(r'\\@(-?\d+)?:(-?\d+)?')
# ARGS_REGEX = re.compile(r'\\\d+')
# def GetAliases(store, user: user_pb2.User):
# def AddOrUpdateAlias(store, user: user_pb2.User, alias_name, alias_cmd):
# def RemoveAlias(store, user: user_pb2.User, alias_name):
# def ExpandAliases(store, user: user_pb2.User, msg: Text):
# def _ExpandAllSign(alias, msg_args):


# Path: hypebot/basebot.py
import re
from absl import app
from absl import flags
from absl import logging
from hypebot import hypecore
from hypebot.commands import command_factory
from hypebot.core import params_lib
from hypebot.interfaces import interface_factory
from hypebot.plugins import alias_lib
from hypebot.protos import channel_pb2
from hypebot.protos import user_pb2
from typing import Text

        #   * exceptions
        # TODO: Figure out how to do proper activity tracking.
        if sync_reply:
          self._core.activity_tracker.RecordActivity(channel, user,
                                                     command.__class__.__name__)
        self._core.Reply(channel, sync_reply)
      except Exception:
        self._core.Reply(
            user,
            'Exception handling: %s' % msg,
            log=True,
            log_level=logging.ERROR)

    # This must come after message processing for paychecks to work properly.
    self._core.user_tracker.RecordActivity(user, channel)

  def _ProcessAliases(self, unused_channel, user: user_pb2.User, msg: Text):
    return alias_lib.ExpandAliases(self._core.cached_store, user, msg)

  NESTED_PATTERN = re.compile(
      r'\$\(([^\(\)]+'
      # TODO: Actually tokenize input
      # instead of relying on cheap hacks
      r'(?:[^\(\)]*".*?"[^\(\)]*)*)\)')

  def _ProcessNestedCalls(self, channel, user, msg):
    """Evaluate nested commands within $(...)."""
    m = self.NESTED_PATTERN.search(msg)
    while m:
      backup_interface = self._core.interface

      self._core.interface = interface_factory.Create('CaptureInterface', {})