async def Func(arg_0, arg_1):
        """Parse channel array and call the appropriate events."""
        if arg_1[0] == 'noop':
            pass  # This is just a keep-alive, ignore it.
        else:
            arg_2 = json.loads(arg_1[0]['p'])
            # Wrapper appears to be a Protocol Buffer message, but encoded via
            # field numbers as dictionary keys. Since we don't have a parser
            # for that, parse it ad-hoc here.
            if '3' in arg_2:
                # This is a new client_id.
                arg_0._client_id = arg_2['3']['2']
                logger.info('Received new client_id: %r', arg_0._client_id)
                # Once client_id is received, the channel is ready to have
                # services added.
                await arg_0._add_channel_services()
            if '2' in arg_2:
                arg_4 = json.loads(arg_2['2']['2'])
                if arg_4[0] == 'cbu':
                    # This is a (Client)BatchUpdate containing StateUpdate
                    # messages.
                    arg_5 = hangouts_pb2.BatchUpdate()
                    pblite.decode(arg_5, arg_4,
                                  ignore_first_item=True)
                    for arg_6 in arg_5.state_update:
                        logger.debug('Received StateUpdate:\n%s', arg_6)
                        arg_7 = arg_6.state_update_header
                        arg_0._active_client_state = arg_7.active_client_state
                        await arg_0.on_state_update.fire(arg_6)
                else:
                    logger.info('Ignoring message: %r', arg_4[0])


async def Func(arg_0):
        """Add services to the channel.

        The services we add to the channel determine what kind of data we will
        receive on it.

        The "babel" service includes what we need for Hangouts. If this fails
        for some reason, hangups will never receive any events. The
        "babel_presence_last_seen" service is also required to receive presence
        notifications.

        This needs to be re-called whenever we open a new channel (when there's
        a new SID and client_id.
        """
        logger.info('Adding channel services...')
        # Based on what Hangouts for Chrome does over 2 requests, this is
        # trimmed down to 1 request that includes the bare minimum to make
        # things work.
        arg_1 = ["babel", "babel_presence_last_seen"]
        arg_2 = [
            dict(p=json.dumps({"3": {"1": {"1": service}}}))
            for service in arg_1
        ]
        await arg_0._channel.send_maps(arg_2)
        logger.info('Channel services added')


async def Func(arg_0, arg_1, arg_2, arg_3):
        """Send a Protocol Buffer formatted chat API request.

        Args:
            endpoint (str): The chat API endpoint to use.
            request_pb: The request body as a Protocol Buffer message.
            response_pb: The response body as a Protocol Buffer message.

        Raises:
            NetworkError: If the request fails.
        """
        logger.debug('Sending Protocol Buffer request %s:\n%s', arg_1,
                     arg_2)
        arg_4 = await arg_0._base_request(
            'https://clients6.google.com/chat/v1/{}'.format(arg_1),
            'application/x-protobuf',  # Request body is Protocol Buffer.
            'proto',  # Response body is Protocol Buffer.
            arg_2.SerializeToString()
        )
        try:
            arg_3.ParseFromString(base64.b64decode(arg_4.body))
        except binascii.Error as e:
            raise exceptions.NetworkError(
                'Failed to decode base64 response: {}'.format(e)
            )
        except google.protobuf.message.DecodeError as e:
            raise exceptions.NetworkError(
                'Failed to decode Protocol Buffer response: {}'.format(e)
            )
        logger.debug('Received Protocol Buffer response:\n%s', arg_3)
        arg_5 = arg_3.response_header.status
        if arg_5 != hangouts_pb2.RESPONSE_STATUS_OK:
            arg_6 = arg_3.response_header.error_description
            raise exceptions.NetworkError(
                'Request failed with status {}: \'{}\''
                .format(arg_5, arg_6)
            )


async def Func(arg_0, arg_1, arg_2, arg_3, arg_4):
        """Send a generic authenticated POST request.

        Args:
            url (str): URL of request.
            content_type (str): Request content type.
            response_type (str): The desired response format. Valid options
                are: 'json' (JSON), 'protojson' (pblite), and 'proto' (binary
                Protocol Buffer). 'proto' requires manually setting an extra
                header 'X-Goog-Encode-Response-If-Executable: base64'.
            data (str): Request body data.

        Returns:
            FetchResponse: Response containing HTTP code, cookies, and body.

        Raises:
            NetworkError: If the request fails.
        """
        arg_5 = {
            'content-type': arg_2,
            # This header is required for Protocol Buffer responses. It causes
            # them to be base64 encoded:
            'X-Goog-Encode-Response-If-Executable': 'base64',
        }
        arg_6 = {
            # "alternative representation type" (desired response format).
            'alt': arg_3,
            # API key (required to avoid 403 Forbidden "Daily Limit for
            # Unauthenticated Use Exceeded. Continued use requires signup").
            'key': API_KEY,
        }
        arg_7 = await arg_0._session.fetch(
            'post', arg_1, arg_5=arg_5, arg_6=arg_6, arg_4=arg_4,
        )
        return arg_7


async def Func(arg_0, arg_1):
        """Invite users to join an existing group conversation."""
        arg_2 = hangouts_pb2.AddUserResponse()
        await arg_0._pb_request('conversations/adduser',
                               arg_1, arg_2)
        return arg_2


async def Func(arg_0, arg_1):
        """Create a new conversation."""
        arg_2 = hangouts_pb2.CreateConversationResponse()
        await arg_0._pb_request('conversations/createconversation',
                               arg_1, arg_2)
        return arg_2


async def Func(arg_0, arg_1):
        """Return conversation info and recent events."""
        arg_2 = hangouts_pb2.GetConversationResponse()
        await arg_0._pb_request('conversations/getconversation',
                               arg_1, arg_2)
        return arg_2


async def Func(arg_0, arg_1):
        """Return one or more user entities.

        Searching by phone number only finds entities when their phone number
        is in your contacts (and not always even then), and can't be used to
        find Google Voice contacts.
        """
        arg_2 = hangouts_pb2.GetEntityByIdResponse()
        await arg_0._pb_request('contacts/getentitybyid',
                               arg_1, arg_2)
        return arg_2


async def Func(arg_0, arg_1):
        """Return info about the current user."""
        arg_2 = hangouts_pb2.GetSelfInfoResponse()
        await arg_0._pb_request('contacts/getselfinfo',
                               arg_1, arg_2)
        return arg_2


async def Func(arg_0, arg_1):
        """Return presence status for a list of users."""
        arg_2 = hangouts_pb2.QueryPresenceResponse()
        await arg_0._pb_request('presence/querypresence',
                               arg_1, arg_2)
        return arg_2


async def Func(arg_0, arg_1):
        """Remove a participant from a group conversation."""
        arg_2 = hangouts_pb2.RemoveUserResponse()
        await arg_0._pb_request('conversations/removeuser',
                               arg_1, arg_2)
        return arg_2


async def Func(arg_0, arg_1):
        """Rename a conversation.

        Both group and one-to-one conversations may be renamed, but the
        official Hangouts clients have mixed support for one-to-one
        conversations with custom names.
        """
        arg_2 = hangouts_pb2.RenameConversationResponse()
        await arg_0._pb_request('conversations/renameconversation',
                               arg_1, arg_2)
        return arg_2


async def Func(arg_0, arg_1):
        """Enable or disable message history in a conversation."""
        arg_2 = hangouts_pb2.ModifyOTRStatusResponse()
        await arg_0._pb_request('conversations/modifyotrstatus',
                               arg_1, arg_2)
        return arg_2


async def Func(
            arg_0, arg_1
    ):
        """Set the notification level of a conversation."""
        arg_2 = hangouts_pb2.SetConversationNotificationLevelResponse()
        await arg_0._pb_request(
            'conversations/setconversationnotificationlevel',
            arg_1, arg_2
        )
        return arg_2


async def Func(arg_0, arg_1):
        """Set focus to a conversation."""
        arg_2 = hangouts_pb2.SetFocusResponse()
        await arg_0._pb_request('conversations/setfocus',
                               arg_1, arg_2)
        return arg_2


async def Func(
            arg_0, arg_1
    ):
        """Set whether group link sharing is enabled for a conversation."""
        arg_2 = hangouts_pb2.SetGroupLinkSharingEnabledResponse()
        await arg_0._pb_request('conversations/setgrouplinksharingenabled',
                               arg_1,
                               arg_2)
        return arg_2


async def Func(arg_0, arg_1):
        """Set the typing status of a conversation."""
        arg_2 = hangouts_pb2.SetTypingResponse()
        await arg_0._pb_request('conversations/settyping',
                               arg_1, arg_2)
        return arg_2


async def Func(
            arg_0, arg_1
    ):
        """Return info on recent conversations and their events."""
        arg_2 = hangouts_pb2.SyncRecentConversationsResponse()
        await arg_0._pb_request('conversations/syncrecentconversations',
                               arg_1,
                               arg_2)
        return arg_2


def Func(arg_0):
    """Convert a microsecond timestamp to a UTC datetime instance."""
    # Create datetime without losing precision from floating point (yes, this
    # is actually needed):
    return datetime.datetime.fromtimestamp(
        arg_0 // 1000000, datetime.timezone.utc
    ).replace(microsecond=(arg_0 % 1000000))


def Func(arg_0):
    """Convert UserID to hangouts_pb2.ParticipantId."""
    return hangouts_pb2.ParticipantId(
        chat_id=arg_0.chat_id,
        gaia_id=arg_0.gaia_id
    )


def Func(arg_0):
    """Return WatermarkNotification from hangouts_pb2.WatermarkNotification."""
    return WatermarkNotification(
        conv_id=arg_0.conversation_id.id,
        user_id=from_participantid(arg_0.sender_id),
        read_timestamp=from_timestamp(
            arg_0.latest_read_timestamp
        ),
    )


def Func(arg_0):
    """Return authorization headers for API request."""
    # It doesn't seem to matter what the url and time are as long as they are
    # consistent.
    arg_1 = int(time.time() * 1000)
    arg_2 = '{} {} {}'.format(arg_1, arg_0, ORIGIN_URL)
    arg_3 = hashlib.sha1(arg_2.encode()).hexdigest()
    arg_4 = 'SAPISIDHASH {}_{}'.format(arg_1, arg_3)
    return {
        'authorization': arg_4,
        'x-origin': ORIGIN_URL,
        'x-goog-authuser': '0',
    }


async def Func(arg_0, arg_1, arg_2, arg_3=None, arg_4=None, arg_5=None):
        """Make an HTTP request.

        Automatically uses configured HTTP proxy, and adds Google authorization
        header and cookies.

        Failures will be retried MAX_RETRIES times before raising NetworkError.

        Args:
            method (str): Request method.
            url (str): Request URL.
            params (dict): (optional) Request query string parameters.
            headers (dict): (optional) Request headers.
            data: (str): (optional) Request body data.

        Returns:
            FetchResponse: Response data.

        Raises:
            NetworkError: If the request fails.
        """
        logger.debug('Sending request %s %s:\n%r', arg_1, arg_2, arg_5)
        for arg_6 in range(MAX_RETRIES):
            try:
                async with arg_0.Func_raw(arg_1, arg_2, arg_3=arg_3,
                                          arg_4=arg_4, arg_5=arg_5) as res:
                    async with async_timeout.timeout(REQUEST_TIMEOUT):
                        body = await res.read()
                logger.debug('Received response %d %s:\n%r',
                             res.status, res.reason, body)
            except asyncio.TimeoutError:
                error_msg = 'Request timed out'
            except aiohttp.ServerDisconnectedError as err:
                error_msg = 'Server disconnected error: {}'.format(err)
            except (aiohttp.ClientError, ValueError) as err:
                error_msg = 'Request connection error: {}'.format(err)
            else:
                break
            logger.info('Request attempt %d failed: %s', arg_6, error_msg)
        else:
            logger.info('Request failed after %d attempts', MAX_RETRIES)
            raise exceptions.NetworkError(error_msg)

        if res.status != 200:
            logger.info('Request returned unexpected status: %d %s',
                        res.status, res.reason)
            raise exceptions.NetworkError(
                'Request return unexpected status: {}: {}'
                .format(res.status, res.reason)
            )

        return FetchResponse(res.status, body)


async def Func(arg_0, arg_1):
    """Search for entities by phone number, email, or gaia_id."""
    arg_2 = _get_lookup_spec(arg_1.entity_identifier)
    arg_3 = hangups.hangouts_pb2.GetEntityByIdRequest(
        request_header=arg_0.get_request_header(),
        batch_lookup_spec=[arg_2],
    )
    arg_4 = await arg_0.get_entity_by_id(arg_3)

    # Print the list of entities in the response.
    for arg_5 in arg_4.entity_result:
        for arg_6 in arg_5.entity:
            print(arg_6)


def Func(arg_0):
    """Return EntityLookupSpec from phone number, email address, or gaia ID."""
    if arg_0.startswith('+'):
        return hangups.hangouts_pb2.EntityLookupSpec(
            phone=arg_0, create_offnetwork_gaia=True
        )
    elif '@' in arg_0:
        return hangups.hangouts_pb2.EntityLookupSpec(
            email=arg_0, create_offnetwork_gaia=True
        )
    else:
        return hangups.hangouts_pb2.EntityLookupSpec(gaia_id=arg_0)


def Func(arg_0, arg_1=False, arg_2=False):
    """Return a readable name for a conversation.

    If the conversation has a custom name, use the custom name. Otherwise, for
    one-to-one conversations, the name is the full name of the other user. For
    group conversations, the name is a comma-separated list of first names. If
    the group conversation is empty, the name is "Empty Conversation".

    If truncate is true, only show up to two names in a group conversation.

    If show_unread is True, if there are unread chat messages, show the number
    of unread chat messages in parentheses after the conversation name.
    """
    arg_3 = len([conv_event for conv_event in arg_0.unread_events if
                      isinstance(conv_event, hangups.ChatMessageEvent) and
                      not arg_0.get_user(conv_event.user_id).is_self])
    if arg_2 and arg_3 > 0:
        arg_4 = ' ({})'.format(arg_3)
    else:
        arg_4 = ''
    if arg_0.name is not None:
        return arg_0.name + arg_4
    else:
        arg_5 = sorted(
            (user for user in arg_0.users if not user.is_self),
            key=lambda user: user.id_
        )
        arg_6 = [user.first_name for user in arg_5]
        if not arg_5:
            return "Empty Conversation" + arg_4
        if len(arg_5) == 1:
            return arg_5[0].full_name + arg_4
        elif arg_1 and len(arg_5) > 2:
            return (', '.join(arg_6[:2] + ['+{}'.format(len(arg_6) - 2)]) +
                    arg_4)
        else:
            return ', '.join(arg_6) + arg_4


def Func(arg_0, arg_1, arg_2, arg_3, arg_4):
    """Add foreground and background colours to a color scheme"""
    if arg_2 is None and arg_3 is None:
        return arg_0

    arg_5 = []
    for arg_6 in arg_0:
        if arg_6[0] == arg_1:
            if arg_2 is None:
                arg_2 = arg_6[1]
            if arg_3 is None:
                arg_3 = arg_6[2]
            if arg_4 > 16:
                arg_5.append((arg_1, '', '', '', arg_2, arg_3))
            else:
                arg_5.append((arg_1, arg_2, arg_3))
        else:
            arg_5.append(arg_6)
    return arg_5


async def Func(arg_0):
    """Sync all conversations by making paginated requests.

    Conversations are ordered by ascending sort timestamp.

    Args:
        client (Client): Connected client.

    Raises:
        NetworkError: If the requests fail.

    Returns:
        tuple of list of ``ConversationState`` messages and sync timestamp
    """
    arg_1 = []
    arg_2 = None
    arg_3 = hangouts_pb2.SyncRecentConversationsRequest(
        request_header=arg_0.get_request_header(),
        max_conversations=CONVERSATIONS_PER_REQUEST,
        max_events_per_conversation=1,
        sync_filter=[
            hangouts_pb2.SYNC_FILTER_INBOX,
            hangouts_pb2.SYNC_FILTER_ARCHIVED,
        ]
    )
    for arg_4 in range(MAX_CONVERSATION_PAGES):
        logger.info(
            'Requesting conversations page %s', arg_3.last_event_timestamp
        )
        response = await arg_0.sync_recent_conversations(arg_3)
        arg_1 = list(response.conversation_state) + arg_1
        arg_2 = parsers.from_timestamp(
            # SyncRecentConversations seems to return a sync_timestamp 4
            # minutes before the present. To prevent SyncAllNewEvents later
            # breaking requesting events older than what we already have, use
            # current_server_time instead.
            response.response_header.current_server_time
        )
        if response.continuation_end_timestamp == 0:
            logger.info('Reached final conversations page')
            break
        else:
            arg_3.last_event_timestamp = response.continuation_end_timestamp
    else:
        logger.warning('Exceeded maximum number of conversation pages')
    logger.info('Synced %s total conversations', len(arg_1))
    return arg_1, arg_2


def Func(arg_0):
        """Loaded events which are unread sorted oldest to newest.

        Some Hangouts clients don't update the read timestamp for certain event
        types, such as membership changes, so this may return more unread
        events than these clients will show. There's also a delay between
        sending a message and the user's own message being considered read.

        (list of :class:`.ConversationEvent`).
        """
        return [arg_1 for arg_1 in arg_0._events
                if arg_1.timestamp > arg_0.latest_read_timestamp]


def Func(arg_0, arg_1):
        """Handle a watermark notification."""
        # Update the conversation:
        if arg_0.get_user(arg_1.user_id).is_self:
            logger.info('latest_read_timestamp for {} updated to {}'
                        .format(arg_0.id_, arg_1.read_timestamp))
            arg_2 = (
                arg_0._conversation.self_conversation_state
            )
            arg_2.self_read_state.latest_read_timestamp = (
                parsers.to_timestamp(arg_1.read_timestamp)
            )
        # Update the participants' watermarks:
        arg_5 = arg_0._watermarks.get(
            arg_1.user_id,
            datetime.datetime.min.replace(tzinfo=datetime.timezone.utc)
        )
        if arg_1.read_timestamp > arg_5:
            logger.info(('latest_read_timestamp for conv {} participant {}' +
                         ' updated to {}').format(arg_0.id_,
                                                  arg_1.user_id.chat_id,
                                                  arg_1.read_timestamp))
            arg_0._watermarks[arg_1.user_id] = arg_1.read_timestamp


def Func(arg_0, arg_1):
        """Update the internal state of the conversation.

        This method is used by :class:`.ConversationList` to maintain this
        instance.

        Args:
            conversation: ``Conversation`` message.
        """
        # StateUpdate.conversation is actually a delta; fields that aren't
        # specified are assumed to be unchanged. Until this class is
        # refactored, hide this by saving and restoring previous values where
        # necessary.

        arg_2 = arg_1.self_conversation_state
        arg_3 = arg_0._conversation.self_conversation_state
        arg_0._conversation = arg_1

        # delivery_medium_option
        if not arg_2.delivery_medium_option:
            arg_2.delivery_medium_option.extend(
                arg_3.delivery_medium_option
            )

        # latest_read_timestamp
        arg_5 = arg_3.self_read_state.latest_read_timestamp
        arg_6 = arg_2.self_read_state.latest_read_timestamp
        if arg_6 == 0:
            arg_2.self_read_state.latest_read_timestamp = arg_5

        # user_read_state(s)
        for arg_9 in arg_1.read_state:
            arg_10 = parsers.from_timestamp(arg_9.latest_read_timestamp)
            if arg_10 == 0:
                continue
            arg_11 = parsers.from_participantid(arg_9.participant_id)
            if arg_11 not in arg_0._watermarks or arg_0._watermarks[arg_11] < arg_10:
                arg_0._watermarks[arg_11] = arg_10


def Func(arg_0):
        """Wrap hangouts_pb2.Event in ConversationEvent subclass."""
        arg_1 = conversation_event.ConversationEvent
        if arg_0.HasField('chat_message'):
            arg_1 = conversation_event.ChatMessageEvent
        elif arg_0.HasField('otr_modification'):
            arg_1 = conversation_event.OTREvent
        elif arg_0.HasField('conversation_rename'):
            arg_1 = conversation_event.RenameEvent
        elif arg_0.HasField('membership_change'):
            arg_1 = conversation_event.MembershipChangeEvent
        elif arg_0.HasField('hangout_event'):
            arg_1 = conversation_event.HangoutEvent
        elif arg_0.HasField('group_link_sharing_modification'):
            arg_1 = conversation_event.GroupLinkSharingModificationEvent
        return arg_1(arg_0)


def Func(arg_0, arg_1):
        """Add an event to the conversation.

        This method is used by :class:`.ConversationList` to maintain this
        instance.

        Args:
            event_: ``Event`` message.

        Returns:
            :class:`.ConversationEvent` representing the event.
        """
        arg_2 = arg_0._wrap_event(arg_1)
        if arg_2.id_ not in arg_0._events_dict:
            arg_0._events.append(arg_2)
            arg_0._events_dict[arg_2.id_] = arg_2
        else:
            # If this happens, there's probably a bug.
            logger.info('Conversation %s ignoring duplicate event %s',
                        arg_0.id_, arg_2.id_)
            return None
        return arg_2


async def Func(arg_0, arg_1, arg_2=None, arg_3=None,
                           arg_4=None):
        """Send a message to this conversation.

        A per-conversation lock is acquired to ensure that messages are sent in
        the correct order when this method is called multiple times
        asynchronously.

        Args:
            segments: List of :class:`.ChatMessageSegment` objects to include
                in the message.
            image_file: (optional) File-like object containing an image to be
                attached to the message.
            image_id: (optional) ID of an Picasa photo to be attached to the
                message. If you specify both ``image_file`` and ``image_id``
                together, ``image_file`` takes precedence and ``image_id`` will
                be ignored.
            image_user_id: (optional) Picasa user ID, required only if
                ``image_id`` refers to an image from a different Picasa user,
                such as Google's sticker user.

        Raises:
            .NetworkError: If the message cannot be sent.
        """
        async with arg_0._Func_lock:
            if arg_2:
                try:
                    arg_5 = await arg_0._client.upload_image(
                        arg_2, return_uploaded_image=True
                    )
                except exceptions.NetworkError as e:
                    logger.warning('Failed to upload image: {}'.format(e))
                    raise
                arg_3 = arg_5.image_id
            try:
                arg_6 = hangouts_pb2.SendChatMessageRequest(
                    request_header=arg_0._client.get_request_header(),
                    event_request_header=arg_0._get_event_request_header(),
                    message_content=hangouts_pb2.MessageContent(
                        segment=[seg.serialize() for seg in arg_1],
                    ),
                )
                if arg_3 is not None:
                    arg_6.existing_media.photo.photo_id = arg_3
                if arg_4 is not None:
                    arg_6.existing_media.photo.user_id = arg_4
                    arg_6.existing_media.photo.is_custom_user_id = True
                await arg_0._client.send_chat_message(arg_6)
            except exceptions.NetworkError as e:
                logger.warning('Failed to send message: {}'.format(e))
                raise


async def Func(arg_0):
        """Leave this conversation.

        Raises:
            .NetworkError: If conversation cannot be left.
        """
        arg_1 = (arg_0._conversation.type ==
                                 hangouts_pb2.CONVERSATION_TYPE_GROUP)
        try:
            if arg_1:
                await arg_0._client.remove_user(
                    hangouts_pb2.RemoveUserRequest(
                        request_header=arg_0._client.get_request_header(),
                        event_request_header=arg_0._get_event_request_header(),
                    )
                )
            else:
                await arg_0._client.delete_conversation(
                    hangouts_pb2.DeleteConversationRequest(
                        request_header=arg_0._client.get_request_header(),
                        conversation_id=hangouts_pb2.ConversationId(
                            id=arg_0.id_
                        ),
                        delete_upper_bound_timestamp=parsers.to_timestamp(
                            datetime.datetime.now(tz=datetime.timezone.utc)
                        )
                    )
                )
        except exceptions.NetworkError as e:
            logger.warning('Failed to Func conversation: {}'.format(e))
            raise


async def Func(arg_0, arg_1):
        """Set the notification level of this conversation.

        Args:
            level: ``NOTIFICATION_LEVEL_QUIET`` to disable notifications, or
                ``NOTIFICATION_LEVEL_RING`` to enable them.

        Raises:
            .NetworkError: If the request fails.
        """
        await arg_0._client.set_conversation_notification_level(
            hangouts_pb2.SetConversationNotificationLevelRequest(
                request_header=arg_0._client.get_request_header(),
                conversation_id=hangouts_pb2.ConversationId(id=arg_0.id_),
                arg_1=arg_1,
            )
        )


async def Func(arg_0, arg_1=None):
        """Update the timestamp of the latest event which has been read.

        This method will avoid making an API request if it will have no effect.

        Args:
            read_timestamp (datetime.datetime): (optional) Timestamp to set.
                Defaults to the timestamp of the newest event.

        Raises:
            .NetworkError: If the timestamp cannot be updated.
        """
        if arg_1 is None:
            arg_1 = (arg_0.events[-1].timestamp if arg_0.events else
                              datetime.datetime.now(datetime.timezone.utc))
        if arg_1 > arg_0.latest_read_timestamp:
            logger.info(
                'Setting {} latest_read_timestamp from {} to {}'
                .format(arg_0.id_, arg_0.latest_read_timestamp, arg_1)
            )
            # Prevent duplicate requests by updating the conversation now.
            arg_2 = arg_0._conversation.self_conversation_state
            arg_2.self_read_state.latest_read_timestamp = (
                parsers.to_timestamp(arg_1)
            )
            try:
                await arg_0._client.update_watermark(
                    hangouts_pb2.UpdateWatermarkRequest(
                        request_header=arg_0._client.get_request_header(),
                        conversation_id=hangouts_pb2.ConversationId(
                            id=arg_0.id_
                        ),
                        last_read_timestamp=parsers.to_timestamp(
                            arg_1
                        ),
                    )
                )
            except exceptions.NetworkError as e:
                logger.warning('Failed to update read timestamp: {}'.format(e))
                raise


def Func(arg_0, arg_1=False):
        """Get all the conversations.

        Args:
            include_archived (bool): (optional) Whether to include archived
                conversations. Defaults to ``False``.

        Returns:
            List of all :class:`.Conversation` objects.
        """
        return [arg_2 for arg_2 in arg_0._conv_dict.values()
                if not arg_2.is_archived or arg_1]


async def Func(arg_0, arg_1):
        """Leave a conversation.

        Args:
            conv_id (str): ID of conversation to leave.
        """
        logger.info('Leaving conversation: {}'.format(arg_1))
        await arg_0._conv_dict[arg_1].leave()
        del arg_0._conv_dict[arg_1]


def Func(arg_0, arg_1, arg_2=[],
                          arg_3=None):
        """Add new conversation from hangouts_pb2.Conversation"""
        # pylint: disable=dangerous-default-value
        arg_4 = arg_1.conversation_id.id
        logger.debug('Adding new conversation: {}'.format(arg_4))
        arg_5 = Conversation(arg_0._client, arg_0._user_list, arg_1,
                            arg_2, arg_3)
        arg_0._conv_dict[arg_4] = arg_5
        return arg_5


async def Func(arg_0, arg_1):
        """Get a cached conversation or fetch a missing conversation.

        Args:
            conv_id: string, conversation identifier

        Raises:
            NetworkError: If the request to fetch the conversation fails.

        Returns:
            :class:`.Conversation` with matching ID.
        """
        arg_2 = arg_0._conv_dict.get(arg_1, None)
        if arg_2 is None:
            logger.info('Fetching unknown conversation %s', arg_1)
            arg_3 = await arg_0._client.get_conversation(
                hangouts_pb2.GetConversationRequest(
                    request_header=arg_0._client.get_request_header(),
                    conversation_spec=hangouts_pb2.ConversationSpec(
                        conversation_id=hangouts_pb2.ConversationId(
                            id=arg_1
                        )
                    ), include_event=False
                )
            )
            arg_4 = arg_3.conversation_state
            arg_5 = None
            if arg_4.HasField('event_continuation_token'):
                arg_5 = arg_4.event_continuation_token
            return arg_0._add_conversation(arg_4.conversation,
                                          arg_5=arg_5)
        else:
            return arg_2


async def Func(arg_0, arg_1):
        """Receive a hangouts_pb2.Event and fan out to Conversations.

        Args:
            event_: hangouts_pb2.Event instance
        """
        arg_2 = arg_1.conversation_id.id
        try:
            arg_3 = await arg_0._get_or_fetch_conversation(arg_2)
        except exceptions.NetworkError:
            logger.warning(
                'Failed to fetch conversation for event notification: %s',
                arg_2
            )
        else:
            arg_0._sync_timestamp = parsers.from_timestamp(arg_1.timestamp)
            arg_5 = arg_3.add_event(arg_1)
            # conv_event may be None if the event was a duplicate.
            if arg_5 is not None:
                await arg_0.on_event.fire(arg_5)
                await arg_3.on_event.fire(arg_5)


async def Func(arg_0, arg_1):
        """Receive Conversation delta and create or update the conversation.

        Args:
            conversation: hangouts_pb2.Conversation instance

        Raises:
            NetworkError: A request to fetch the complete conversation failed.
        """
        arg_2 = arg_1.conversation_id.id
        arg_3 = arg_0._conv_dict.get(arg_2, None)
        if arg_3 is None:
            # Ignore the delta and fetch the complete conversation.
            await arg_0._get_or_fetch_conversation(arg_2)
        else:
            # Update conversation using the delta.
            arg_3.update_conversation(arg_1)


async def Func(arg_0, arg_1):
        """Receive SetTypingNotification and update the conversation.

        Args:
            set_typing_notification: hangouts_pb2.SetTypingNotification
                instance
        """
        arg_2 = arg_1.conversation_id.id
        arg_3 = parsers.parse_typing_status_message(arg_1)
        await arg_0.on_typing.fire(arg_3)
        try:
            arg_4 = await arg_0._get_or_fetch_conversation(arg_2)
        except exceptions.NetworkError:
            logger.warning(
                'Failed to fetch conversation for typing notification: %s',
                arg_2
            )
        else:
            await arg_4.on_typing.fire(arg_3)


async def Func(arg_0, arg_1):
        """Receive WatermarkNotification and update the conversation.

        Args:
            watermark_notification: hangouts_pb2.WatermarkNotification instance
        """
        arg_2 = arg_1.conversation_id.id
        arg_3 = parsers.parse_watermark_notification(arg_1)
        await arg_0.on_watermark_notification.fire(arg_3)
        try:
            arg_4 = await arg_0._get_or_fetch_conversation(arg_2)
        except exceptions.NetworkError:
            logger.warning(
                'Failed to fetch conversation for watermark notification: %s',
                arg_2
            )
        else:
            await arg_4.on_watermark_notification.fire(arg_3)


async def Func(arg_0):
        """Sync conversation state and events that could have been missed."""
        logger.info('Syncing events since {}'.format(arg_0.Func_timestamp))
        try:
            arg_1 = await arg_0._client.sync_all_new_events(
                hangouts_pb2.SyncAllNewEventsRequest(
                    request_header=arg_0._client.get_request_header(),
                    lastFunc_timestamp=parsers.to_timestamp(
                        arg_0.Func_timestamp
                    ),
                    max_response_size_bytes=1048576,  # 1 MB
                )
            )
        except exceptions.NetworkError as e:
            logger.warning('Failed to sync events, some events may be lost: {}'
                           .format(e))
        else:
            for arg_2 in arg_1.conversation_state:
                arg_3 = arg_2.conversation_id.id
                arg_4 = arg_0._conv_dict.get(arg_3, None)
                if arg_4 is not None:
                    arg_4.update_conversation(arg_2.conversation)
                    for arg_5 in arg_2.event:
                        arg_6 = parsers.from_timestamp(arg_5.timestamp)
                        if arg_6 > arg_0.Func_timestamp:
                            # This updates the sync_timestamp for us, as well
                            # as triggering events.
                            await arg_0._on_event(arg_5)
                else:
                    arg_0._add_conversation(
                        arg_2.conversation,
                        arg_2.event,
                        arg_2.event_continuation_token
                    )


def Func(arg_0, arg_1):
        """Construct user from ``Entity`` message.

        Args:
            entity: ``Entity`` message.
            self_user_id (~hangups.user.UserID or None): The ID of the current
                user. If ``None``, assume ``entity`` is the current user.

        Returns:
            :class:`~hangups.user.User` object.
        """
        arg_2 = UserID(chat_id=arg_0.id.chat_id,
                         gaia_id=arg_0.id.gaia_id)
        return User(arg_2, arg_0.properties.display_name,
                    arg_0.properties.first_name,
                    arg_0.properties.photo_url,
                    arg_0.properties.email,
                    (arg_1 == arg_2) or (arg_1 is None))


def Func(arg_0, arg_1):
        """Get a user by its ID.

        Args:
            user_id (~hangups.user.UserID): The ID of the user.

        Raises:
            KeyError: If no such user is known.

        Returns:
            :class:`~hangups.user.User` with the given ID.
        """
        try:
            return arg_0._user_dict[arg_1]
        except KeyError:
            logger.warning('UserList returning unknown User for UserID %s',
                           arg_1)
            return User(arg_1, None, None, None, [], False)


def Func(arg_0, arg_1):
        """Add or upgrade User from ConversationParticipantData."""
        arg_2 = User.from_conv_part_data(arg_1, arg_0._self_user.id_)

        arg_3 = arg_0._user_dict.get(arg_2.id_)
        if arg_3 is None:
            logger.warning('Adding fallback User with %s name "%s"',
                           arg_2.name_type.name.lower(), arg_2.full_name)
            arg_0._user_dict[arg_2.id_] = arg_2
            return arg_2
        else:
            arg_3.upgrade_name(arg_2)
            return arg_3


def Func(arg_0, arg_1):
        """Add an observer to this event.

        Args:
            callback: A function or coroutine callback to call when the event
                is fired.

        Raises:
            ValueError: If the callback has already been added.
        """
        if arg_1 in arg_0._observers:
            raise ValueError('{} is already an observer of {}'
                             .format(arg_1, arg_0))
        arg_0._observers.append(arg_1)


def Func(arg_0, arg_1):
        """Remove an observer from this event.

        Args:
            callback: A function or coroutine callback to remove from this
                event.

        Raises:
            ValueError: If the callback is not an observer of this event.
        """
        if arg_1 not in arg_0._observers:
            raise ValueError('{} is not an observer of {}'
                             .format(arg_1, arg_0))
        arg_0._observers.remove(arg_1)


async def Func(arg_0, *arg_1, **arg_2):
        """Fire this event, calling all observers with the same arguments."""
        logger.debug('Fired {}'.format(arg_0))
        for arg_3 in arg_0._observers:
            arg_4 = arg_3(*arg_1, **arg_2)
            if asyncio.iscoroutinefunction(arg_3):
                await arg_4


def Func(arg_0, *arg_1):
    """Run a hangups example coroutine.

    Args:
        example_coroutine (coroutine): Coroutine to run with a connected
            hangups client and arguments namespace as arguments.
        extra_args (str): Any extra command line arguments required by the
            example.
    """
    arg_2 = _get_parser(arg_1).parse_args()
    logging.basicConfig(level=logging.DEBUG if arg_2.debug else logging.WARNING)
    # Obtain hangups authentication cookies, prompting for credentials from
    # standard input if necessary.
    arg_3 = hangups.auth.get_auth_stdin(arg_2.token_path)
    arg_4 = hangups.Client(arg_3)
    arg_5 = asyncio.get_event_loop()
    arg_6 = asyncio.ensure_future(_async_main(arg_0, arg_4, arg_2),
                                 arg_5=arg_5)

    try:
        arg_5.run_until_complete(arg_6)
    except KeyboardInterrupt:
        arg_6.cancel()
        arg_5.run_until_complete(arg_6)
    finally:
        arg_5.close()


def Func(arg_0):
    """Return ArgumentParser with any extra arguments."""
    arg_1 = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    arg_2 = appdirs.AppDirs('hangups', 'hangups')
    arg_3 = os.path.join(arg_2.user_cache_dir, 'refresh_token.txt')
    arg_1.add_argument(
        '--token-path', default=arg_3,
        help='path used to store OAuth refresh token'
    )
    arg_1.add_argument(
        '-d', '--debug', action='store_true',
        help='log detailed debugging messages'
    )
    for arg_4 in arg_0:
        arg_1.add_argument(arg_4, required=True)
    return arg_1


def Func(arg_0, arg_1):
    """Print column headers and rows as a reStructuredText table.

    Args:
        col_tuple: Tuple of column name strings.
        row_tuples: List of tuples containing row data.
    """
    arg_2 = [max(len(str(row[col])) for row in [arg_0] + arg_1)
                  for col in range(len(arg_0))]
    arg_3 = ' '.join('{{:<{}}}'.format(col_width)
                          for col_width in arg_2)
    arg_4 = ' '.join('=' * col_width for col_width in arg_2)
    print(arg_4)
    print(arg_3.format(*arg_0))
    print(arg_4)
    for arg_5 in arg_1:
        print(arg_3.format(*arg_5))
    print(arg_4)
    print()


def Func(arg_0, arg_1, arg_2, arg_3=''):
    """Generate doc for an enum.

    Args:
        enum_descriptor: descriptor_pb2.EnumDescriptorProto instance for enum
            to generate docs for.
        locations: Dictionary of location paths tuples to
            descriptor_pb2.SourceCodeInfo.Location instances.
        path: Path tuple to the enum definition.
        name_prefix: Optional prefix for this enum's name.
    """
    print(make_subsection(arg_3 + arg_0.name))
    arg_4 = arg_1[arg_2]
    if arg_4.HasField('leading_comments'):
        print(textwrap.dedent(arg_4.leading_comments))

    arg_5 = []
    for arg_6, arg_7 in enumerate(arg_0.value):
        arg_8 = arg_1[arg_2 + (2, arg_6)]
        arg_5.append((
            make_code(arg_7.name),
            arg_7.number,
            textwrap.fill(get_comment_from_location(arg_8), INFINITY),
        ))
    print_table(('Name', 'Number', 'Description'), arg_5)


def Func(arg_0):
    """Create a directory if it does not exist."""
    arg_1 = os.path.dirname(arg_0)
    if arg_1 != '' and not os.path.isdir(arg_1):
        try:
            os.makedirs(arg_1)
        except OSError as e:
            sys.exit('Failed to create directory: {}'.format(e))


def Func(arg_0):
        """Show the overlay menu."""
        # If the current widget in the TabbedWindowWidget has a menu,
        # overlay it on the TabbedWindowWidget.
        arg_1 = arg_0._tabbed_window.get_current_widget()
        if hasattr(arg_1, 'get_menu_widget'):
            arg_2 = arg_1.get_menu_widget(arg_0._hide_menu)
            arg_3 = urwid.Overlay(arg_2, arg_0._tabbed_window,
                                    align='center', width=('relative', 80),
                                    valign='middle', height=('relative', 80))
            arg_0._urwid_loop.widget = arg_3


async def Func(arg_0):
        """Handle connecting for the first time."""
        arg_0._user_list, arg_0._conv_list = (
            await hangups.build_user_conversation_list(arg_0._client)
        )
        arg_0._conv_list.on_event.add_observer(arg_0._on_event)

        # show the conversation menu
        arg_3 = ConversationPickerWidget(arg_0._conv_list,
                                               arg_0.on_select_conversation,
                                               arg_0._keys)
        arg_0._tabbed_window = TabbedWindowWidget(arg_0._keys)
        arg_0._tabbed_window.set_tab(arg_3, switch=True,
                                    title='Conversations')
        arg_0._urwid_loop.widget = arg_0._tabbed_window


def Func(arg_0, arg_1):
        """Open conversation tab for new messages & pass events to notifier."""
        arg_2 = arg_0._conv_list.get(arg_1.conversation_id)
        arg_3 = arg_2.get_user(arg_1.user_id)
        arg_4 = all((
            isinstance(arg_1, hangups.ChatMessageEvent),
            not arg_3.is_self,
            not arg_2.is_quiet,
        ))
        if arg_4:
            arg_0.add_conversation_tab(arg_1.conversation_id)
            if arg_0._discreet_notifications:
                arg_5 = DISCREET_NOTIFICATION
            else:
                arg_5 = notifier.Notification(
                    arg_3.full_name, get_conv_name(arg_2), arg_1.text
                )
            arg_0._notifier.send(arg_5)


def Func(arg_0, arg_1):
        """Put a coroutine in the queue to be executed."""
        # Avoid logging when a coroutine is queued or executed to avoid log
        # spam from coroutines that are started on every keypress.
        assert asyncio.iscoroutine(arg_1)
        arg_0._queue.Func_nowait(arg_1)


async def Func(arg_0):
        """Consume coroutines from the queue by executing them."""
        while True:
            arg_1 = await arg_0._queue.get()
            assert asyncio.iscoroutine(arg_1)
            await arg_1


def Func(arg_0, arg_1, arg_2):
        """Rename conversation and call callback."""
        arg_0._coroutine_queue.put(arg_0._conversation.rename(arg_1))
        arg_2()


def Func(arg_0, arg_1):
        """Re-order the conversations when an event occurs."""
        # TODO: handle adding new conversations
        arg_0.sort(key=lambda conv_button: conv_button.last_modified,
                  reverse=True)


def Func(arg_0, arg_1):
        """Make users stop typing when they send a message."""
        if isinstance(arg_1, hangups.ChatMessageEvent):
            arg_0._typing_statuses[arg_1.user_id] = (
                hangups.TYPING_TYPE_STOPPED
            )
            arg_0._update()


def Func(arg_0):
        """Update status text."""
        arg_1 = [arg_0._conversation.get_user(user_id)
                        for user_id, status in arg_0._typing_statuses.items()
                        if status == hangups.TYPING_TYPE_STARTED]
        arg_2 = [user.first_name for user in arg_1
                           if not user.is_self]
        if arg_2:
            arg_3 = '{} {} typing...'.format(
                ', '.join(sorted(arg_2)),
                'is' if len(arg_2) == 1 else 'are'
            )
        else:
            arg_3 = ''

        if not arg_0._is_connected:
            arg_0._widget.set_text("RECONNECTING...")
        elif arg_0._message is not None:
            arg_0._widget.set_text(arg_0._message)
        else:
            arg_0._widget.set_text(arg_3)


def Func(arg_0, arg_1, arg_2,
                                arg_3, arg_4=None):
        """Return MessageWidget representing a ConversationEvent.

        Returns None if the ConversationEvent does not have a widget
        representation.
        """
        arg_5 = arg_0.get_user(arg_1.user_id)
        # Check whether the previous event occurred on the same day as this
        # event.
        if arg_2 is not None:
            arg_6 = (arg_1.timestamp.astimezone(tz=None).date() !=
                          arg_2.timestamp.astimezone(tz=None).date())
        else:
            arg_6 = False
        if isinstance(arg_1, hangups.ChatMessageEvent):
            return MessageWidget(arg_1.timestamp, arg_1.text,
                                 arg_3, arg_5, show_date=arg_6,
                                 arg_4=arg_4)
        elif isinstance(arg_1, hangups.RenameEvent):
            if arg_1.new_name == '':
                arg_7 = ('{} cleared the conversation name'
                        .format(arg_5.first_name))
            else:
                arg_7 = ('{} renamed the conversation to {}'
                        .format(arg_5.first_name, arg_1.new_name))
            return MessageWidget(arg_1.timestamp, arg_7, arg_3,
                                 show_date=arg_6,
                                 arg_4=arg_4)
        elif isinstance(arg_1, hangups.MembershipChangeEvent):
            arg_8 = [arg_0.get_user(user_id) for user_id
                           in arg_1.participant_ids]
            arg_9 = ', '.join([arg_5.full_name for arg_5 in arg_8])
            if arg_1.type_ == hangups.MEMBERSHIP_CHANGE_TYPE_JOIN:
                arg_7 = ('{} added {} to the conversation'
                        .format(arg_5.first_name, arg_9))
            else:  # LEAVE
                arg_7 = ('{} left the conversation'.format(arg_9))
            return MessageWidget(arg_1.timestamp, arg_7, arg_3,
                                 show_date=arg_6,
                                 arg_4=arg_4)
        elif isinstance(arg_1, hangups.HangoutEvent):
            arg_7 = {
                hangups.HANGOUT_EVENT_TYPE_START: (
                    'A Hangout call is starting.'
                ),
                hangups.HANGOUT_EVENT_TYPE_END: (
                    'A Hangout call ended.'
                ),
                hangups.HANGOUT_EVENT_TYPE_ONGOING: (
                    'A Hangout call is ongoing.'
                ),
            }.get(arg_1.event_type, 'Unknown Hangout call event.')
            return MessageWidget(arg_1.timestamp, arg_7, arg_3,
                                 show_date=arg_6,
                                 arg_4=arg_4)
        elif isinstance(arg_1, hangups.GroupLinkSharingModificationEvent):
            arg_10 = hangups.GROUP_LINK_SHARING_STATUS_ON
            arg_11 = ('on' if arg_1.new_status == arg_10
                           else 'off')
            arg_7 = '{} turned {} joining by link.'.format(arg_5.first_name,
                                                          arg_11)
            return MessageWidget(arg_1.timestamp, arg_7, arg_3,
                                 show_date=arg_6,
                                 arg_4=arg_4)
        else:
            # conv_event is a generic hangups.ConversationEvent.
            arg_7 = 'Unknown conversation event'
            return MessageWidget(arg_1.timestamp, arg_7, arg_3,
                                 show_date=arg_6,
                                 arg_4=arg_4)


def Func(arg_0, arg_1):
        """Handle updating and scrolling when a new event is added.

        Automatically scroll down to show the new text if the bottom is
        showing. This allows the user to scroll up to read previous messages
        while new messages are arriving.
        """
        if not arg_0._is_scrolling:
            arg_0.set_focus(arg_1.id_)
        else:
            arg_0._modified()


async def Func(arg_0):
        """Load more events for this conversation."""
        try:
            arg_1 = await arg_0._conversation.get_events(
                arg_0._conversation.events[0].id_
            )
        except (IndexError, hangups.NetworkError):
            arg_1 = []
        if not arg_1:
            arg_0._firstFunced = True
        if arg_0._focus_position == arg_0.POSITION_LOADING and arg_1:
            # If the loading indicator is still focused, and we loaded more
            # events, set focus on the first new event so the loaded
            # indicator is replaced.
            arg_0.set_focus(arg_1[-1].id_)
        else:
            # Otherwise, still need to invalidate in case the loading
            # indicator is showing but not focused.
            arg_0._modified()
        # Loading events can also update the watermarks.
        arg_0._refresh_watermarked_events()
        arg_0._isFuncing = False


def Func(arg_0, arg_1):
        """Return the menu widget associated with this widget."""
        return ConversationMenu(
            arg_0._coroutine_queue, arg_0._conversation, arg_1,
            arg_0._keys
        )


def Func(arg_0):
        """Update this conversation's tab title."""
        arg_0.title = get_conv_name(arg_0._conversation, show_unread=True,
                                   truncate=True)
        arg_0.Func_cb(arg_0, arg_0.title)


def Func(arg_0):
        """Update tab display."""
        arg_1 = []
        for arg_2, arg_3 in enumerate(arg_0._widgets):
            arg_4 = ('active_tab' if arg_2 == arg_0._tab_index
                       else 'inactive_tab')
            arg_1 += [
                (arg_4, ' {} '.format(arg_0._widget_title[arg_3])),
                ('tab_background', ' '),
            ]
        arg_0._tabs.set_text(arg_1)
        arg_0._frame.contents['body'] = (arg_0._widgets[arg_0._tab_index], None)


def Func(arg_0, arg_1, arg_2=False, arg_3=None):
        """Add or modify a tab.

        If widget is not a tab, it will be added. If switch is True, switch to
        this tab. If title is given, set the tab's title.
        """
        if arg_1 not in arg_0._widgets:
            arg_0._widgets.append(arg_1)
            arg_0._widget_title[arg_1] = ''
        if arg_2:
            arg_0._tab_index = arg_0._widgets.index(arg_1)
        if arg_3:
            arg_0._widget_title[arg_1] = arg_3
        arg_0._update_tabs()


def Func(arg_0, arg_1):
    """Use the access token to get session cookies.

    Raises GoogleAuthError if session cookies could not be loaded.

    Returns dict of cookies.
    """
    arg_2 = {'Authorization': 'Bearer {}'.format(arg_1)}

    try:
        arg_3 = arg_0.get(('https://accounts.google.com/accounts/OAuthLogin'
                         '?source=hangups&issueuberauth=1'), arg_2=arg_2)
        arg_3.raise_for_status()
    except requests.RequestException as e:
        raise GoogleAuthError('OAuthLogin request failed: {}'.format(e))
    arg_4 = arg_3.text

    try:
        arg_3 = arg_0.get(('https://accounts.google.com/MergeSession?'
                         'service=mail&'
                         'continue=http://www.google.com&uberauth={}')
                        .format(arg_4), arg_2=arg_2)
        arg_3.raise_for_status()
    except requests.RequestException as e:
        raise GoogleAuthError('MergeSession request failed: {}'.format(e))

    arg_5 = arg_0.cookies.get_dict(domain='.google.com')
    if arg_5 == {}:
        raise GoogleAuthError('Failed to find session cookies')
    return arg_5


def Func(arg_0, arg_1, arg_2):
        """Populate and submit a form on the current page.

        Raises GoogleAuthError if form can not be submitted.
        """
        logger.info(
            'Submitting form on page %r', arg_0._page.url.split('?')[0]
        )
        logger.info(
            'Page contains forms: %s',
            [arg_3.get('id') for arg_3 in arg_0._page.soup.select('form')]
        )
        try:
            arg_4 = arg_0._page.soup.select(arg_1)[0]
        except IndexError:
            raise GoogleAuthError(
                'Failed to find form {!r} in page'.format(arg_1)
            )
        logger.info(
            'Page contains inputs: %s',
            [arg_3.get('id') for arg_3 in arg_4.select('input')]
        )
        for arg_5, arg_6 in arg_2.items():
            try:
                arg_4.select(arg_5)[0]['value'] = arg_6
            except IndexError:
                raise GoogleAuthError(
                    'Failed to find input {!r} in form'.format(arg_5)
                )
        try:
            arg_0._page = arg_0._browser.submit(arg_4, arg_0._page.url)
            arg_0._page.raise_for_status()
        except requests.RequestException as e:
            raise GoogleAuthError('Failed to submit form: {}'.format(e))


def Func(arg_0):
    """Parse response format for request for new channel SID.

    Example format (after parsing JS):
    [   [0,["c","SID_HERE","",8]],
        [1,[{"gsid":"GSESSIONID_HERE"}]]]

    Returns (SID, gsessionid) tuple.
    """
    arg_0 = json.loads(list(ChunkParser().get_chunks(arg_0))[0])
    arg_1 = arg_0[0][1][1]
    arg_2 = arg_0[1][1][0]['gsid']
    return (arg_1, arg_2)


async def Func(arg_0):
        """Listen for messages on the backwards channel.

        This method only returns when the connection has been closed due to an
        error.
        """
        arg_1 = 0  # Number of retries attempted so far
        arg_2 = True  # whether a new SID is needed

        while arg_1 <= arg_0._max_retries:
            # After the first failed retry, back off exponentially longer after
            # each attempt.
            if arg_1 > 0:
                arg_3 = arg_0._retry_backoff_base ** arg_1
                logger.info('Backing off for %s seconds', arg_3)
                await asyncio.sleep(arg_3)

            # Request a new SID if we don't have one yet, or the previous one
            # became invalid.
            if arg_2:
                await arg_0._fetch_channel_sid()
                arg_2 = False
            # Clear any previous push data, since if there was an error it
            # could contain garbage.
            arg_0._chunk_parser = ChunkParser()
            try:
                await arg_0._longpoll_request()
            except ChannelSessionError as err:
                logger.warning('Long-polling interrupted: %s', err)
                arg_2 = True
            except exceptions.NetworkError as err:
                logger.warning('Long-polling request failed: %s', err)
            else:
                # The connection closed successfully, so reset the number of
                # retries.
                arg_1 = 0
                continue

            arg_1 += 1
            logger.info('retry attempt count is now %s', arg_1)
            if arg_0._is_connected:
                arg_0._is_connected = False
                await arg_0.on_disconnect.fire()

            # If the request ended with an error, the client must account for
            # messages being dropped during this time.

        logger.error('Ran out of retries for long-polling request')


async def Func(arg_0):
        """Open a long-polling request and receive arrays.

        This method uses keep-alive to make re-opening the request faster, but
        the remote server will set the "Connection: close" header once an hour.

        Raises hangups.NetworkError or ChannelSessionError.
        """
        arg_1 = {
            'VER': 8,  # channel protocol version
            'gsessionid': arg_0._gsessionid_param,
            'RID': 'rpc',  # request identifier
            't': 1,  # trial
            'SID': arg_0._sid_param,  # session ID
            'CI': 0,  # 0 if streaming/chunked requests should be used
            'ctype': 'hangouts',  # client type
            'TYPE': 'xmlhttp',  # type of request
        }
        logger.info('Opening new long-polling request')
        try:
            async with arg_0._session.fetch_raw('GET', CHANNEL_URL,
                                               arg_1=arg_1) as res:

                if res.status != 200:
                    if res.status == 400 and res.reason == 'Unknown SID':
                        raise ChannelSessionError('SID became invalid')
                    raise exceptions.NetworkError(
                        'Request return unexpected status: {}: {}'.format(
                            res.status, res.reason))

                while True:
                    async with async_timeout.timeout(PUSH_TIMEOUT):
                        arg_2 = await res.content.read(MAX_READ_BYTES)
                    if not arg_2:
                        break

                    await arg_0._on_push_data(arg_2)

        except asyncio.TimeoutError:
            raise exceptions.NetworkError('Request timed out')
        except aiohttp.ServerDisconnectedError as err:
            raise exceptions.NetworkError(
                'Server disconnected error: %s' % err)
        except aiohttp.ClientPayloadError:
            raise ChannelSessionError('SID is about to expire')
        except aiohttp.ClientError as err:
            raise exceptions.NetworkError('Request connection error: %s' % err)


async def Func(arg_0, arg_1):
        """Parse push data and trigger events."""
        logger.debug('Received chunk:\n{}'.format(arg_1))
        for arg_2 in arg_0._chunk_parser.get_chunks(arg_1):

            # Consider the channel connected once the first chunk is received.
            if not arg_0._is_connected:
                if arg_0._on_connect_called:
                    arg_0._is_connected = True
                    await arg_0.on_reconnect.fire()
                else:
                    arg_0._on_connect_called = True
                    arg_0._is_connected = True
                    await arg_0.on_connect.fire()

            # chunk contains a container array
            arg_5 = json.loads(arg_2)
            # container array is an array of inner arrays
            for arg_6 in arg_5:
                # inner_array always contains 2 elements, the array_id and the
                # data_array.
                arg_7, arg_8 = arg_6
                logger.debug('Chunk contains data array with id %r:\n%r',
                             arg_7, arg_8)
                await arg_0.on_receive_array.fire(arg_8)


def Func(arg_0, arg_1, arg_2):
    """Decode optional or required field."""
    if arg_1.type == FieldDescriptor.TYPE_MESSAGE:
        decode(getattr(arg_0, arg_1.name), arg_2)
    else:
        try:
            if arg_1.type == FieldDescriptor.TYPE_BYTES:
                arg_2 = base64.b64decode(arg_2)
            setattr(arg_0, arg_1.name, arg_2)
        except (ValueError, TypeError) as e:
            # ValueError: invalid enum value, negative unsigned int value, or
            # invalid base64
            # TypeError: mismatched type
            logger.warning('Message %r ignoring field %s: %s',
                           arg_0.__class__.__name__, arg_1.name, e)


def Func(arg_0, arg_1, arg_2):
    """Decode repeated field."""
    if arg_1.type == FieldDescriptor.TYPE_MESSAGE:
        for arg_3 in arg_2:
            decode(getattr(arg_0, arg_1.name).add(), arg_3)
    else:
        try:
            for arg_3 in arg_2:
                if arg_1.type == FieldDescriptor.TYPE_BYTES:
                    arg_3 = base64.b64decode(arg_3)
                getattr(arg_0, arg_1.name).append(arg_3)
        except (ValueError, TypeError) as e:
            # ValueError: invalid enum value, negative unsigned int value, or
            # invalid base64
            # TypeError: mismatched type
            logger.warning('Message %r ignoring repeated field %s: %s',
                           arg_0.__class__.__name__, arg_1.name, e)
            # Ignore any values already decoded by clearing list
            arg_0.ClearField(arg_1.name)


def Func(arg_0, arg_1, arg_2=False):
    """Decode pblite to Protocol Buffer message.

    This method is permissive of decoding errors and will log them as warnings
    and continue decoding where possible.

    The first element of the outer pblite list must often be ignored using the
    ignore_first_item parameter because it contains an abbreviation of the name
    of the protobuf message (eg.  cscmrp for ClientSendChatMessageResponseP)
    that's not part of the protobuf.

    Args:
        message: protocol buffer message instance to Func into.
        pblite: list representing a pblite-serialized message.
        ignore_first_item: If True, ignore the item at index 0 in the pblite
            list, making the item at index 1 correspond to field 1 in the
            message.
    """
    if not isinstance(arg_1, list):
        logger.warning('Ignoring invalid message: expected list, got %r',
                       type(arg_1))
        return
    if arg_2:
        arg_1 = arg_1[1:]
    # If the last item of the list is a dict, use it as additional field/value
    # mappings. This seems to be an optimization added for dealing with really
    # high field numbers.
    if arg_1 and isinstance(arg_1[-1], dict):
        arg_3 = {int(arg_5): arg_6 for arg_5, arg_6
                        in arg_1[-1].items()}
        arg_1 = arg_1[:-1]
    else:
        arg_3 = {}
    arg_4 = itertools.chain(enumerate(arg_1, start=1),
                                    arg_3.items())
    for arg_5, arg_6 in arg_4:
        if arg_6 is None:
            continue
        try:
            arg_7 = arg_0.DESCRIPTOR.fields_by_number[arg_5]
        except KeyError:
            # If the tag number is unknown and the value is non-trivial, log a
            # message to aid reverse-engineering the missing field in the
            # message.
            if arg_6 not in [[], '', 0]:
                logger.debug('Message %r contains unknown field %s with value '
                             '%r', arg_0.__class__.__name__, arg_5,
                             arg_6)
            continue
        if arg_7.label == FieldDescriptor.LABEL_REPEATED:
            _Func_repeated_field(arg_0, arg_7, arg_6)
        else:
            _Func_field(arg_0, arg_7, arg_6)


def Func(arg_0, arg_1=False, arg_2=None):
    """
    Sets the Elasticsearch hosts to use

    Args:
        hosts (str): A single hostname or URL, or list of hostnames or URLs
        use_ssl (bool): Use a HTTPS connection to the server
        ssl_cert_path (str): Path to the certificate chain
    """
    if type(arg_0) != list:
        arg_0 = [arg_0]
    arg_3 = {
        "hosts": arg_0,
        "timeout": 20
    }
    if arg_1:
        arg_3['use_ssl'] = True
        if arg_2:
            arg_3['verify_certs'] = True
            arg_3['ca_certs'] = arg_2
        else:
            arg_3['verify_certs'] = False
    connections.create_connection(**arg_3)


def Func(arg_0=None, arg_1=None):
    """
    Updates index mappings

    Args:
        aggregate_indexes (list): A list of aggregate index names
        forensic_indexes (list): A list of forensic index names
    """
    arg_2 = 2
    if arg_0 is None:
        arg_0 = []
    if arg_1 is None:
        arg_1 = []
    for arg_3 in arg_0:
        if not Index(arg_3).exists():
            continue
        arg_4 = Index(arg_3)
        arg_5 = "doc"
        arg_6 = "published_policy.fo"
        arg_7 = "fo"
        arg_8 = arg_4.get_field_mapping(fields=[arg_6])
        arg_8 = arg_8[list(arg_8.keys())[0]]["mappings"]
        if arg_5 not in arg_8:
            continue

        arg_8 = arg_8[arg_5][arg_6]["mapping"][arg_7]
        arg_9 = arg_8["type"]
        if arg_9 == "long":
            arg_10 = "{0}-v{1}".format(arg_3, arg_2)
            arg_11 = {"properties": {"published_policy.fo": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                }
            }
            }
            }
            Index(arg_10).create()
            Index(arg_10).put_mapping(doc_type=arg_5, arg_11=arg_11)
            reindex(connections.get_connection(), arg_3,
                    arg_10)
            Index(arg_3).delete()

    for arg_12 in arg_1:
        pass


def Func(arg_0, arg_1,
                                        arg_2):
        """
        Saves aggregate DMARC reports to Kafka

        Args:
            aggregate_reports (list):  A list of aggregate report dictionaries
            to save to Kafka
            aggregate_topic (str): The name of the Kafka topic

        """
        if (type(arg_1) == dict or
           type(arg_1) == OrderedDict):
            arg_1 = [arg_1]

        if len(arg_1) < 1:
            return

        for arg_3 in arg_1:
            arg_3['date_range'] = arg_0.generate_daterange(arg_3)
            arg_3 = arg_0.strip_metadata(arg_3)

            for arg_4 in arg_3['records']:
                arg_4['date_range'] = arg_3['date_range']
                arg_4['org_name'] = arg_3['org_name']
                arg_4['org_email'] = arg_3['org_email']
                arg_4['policy_published'] = arg_3['policy_published']
                arg_4['report_id'] = arg_3['report_id']
                logger.debug("Sending slice.")
                try:
                    logger.debug("Saving aggregate report to Kafka")
                    arg_0.producer.send(arg_2, arg_4)
                except UnknownTopicOrPartitionError:
                    raise KafkaError(
                        "Kafka error: Unknown topic or partition on broker")
                except Exception as e:
                    raise KafkaError(
                        "Kafka error: {0}".format(e.__str__()))
                try:
                    arg_0.producer.flush()
                except Exception as e:
                    raise KafkaError(
                        "Kafka error: {0}".format(e.__str__()))


def Func(arg_0):
    """
    Extracts xml from a zip or gzip file at the given path, file-like object,
    or bytes.

    Args:
        input_: A path to a file, a file like object, or bytes

    Returns:
        str: The extracted XML

    """
    if type(arg_0) == str:
        arg_1 = open(arg_0, "rb")
    elif type(arg_0) == bytes:
        arg_1 = BytesIO(arg_0)
    else:
        arg_1 = arg_0
    try:
        arg_2 = arg_1.read(6)
        arg_1.seek(0)
        if arg_2.startswith(MAGIC_ZIP):
            arg_3 = zipfile.ZipFile(arg_1)
            arg_4 = arg_3.open(arg_3.namelist()[0]).read().decode()
        elif arg_2.startswith(MAGIC_GZIP):
            arg_4 = GzipFile(fileobj=arg_1).read().decode()
        elif arg_2.startswith(MAGIC_XML):
            arg_4 = arg_1.read().decode()
        else:
            arg_1.close()
            raise InvalidAggregateReport("Not a valid zip, gzip, or xml file")

        arg_1.close()

    except UnicodeDecodeError:
        raise InvalidAggregateReport("File objects must be opened in binary "
                                     "(rb) mode")
    except Exception as error:
        raise InvalidAggregateReport(
            "Invalid archive file: {0}".format(error.__str__()))

    return arg_4


def Func(arg_0, arg_1=None, arg_2=2.0,
                                arg_3=False):
    """Parses a file at the given path, a file-like object. or bytes as a
    aggregate DMARC report

    Args:
        _input: A path to a file, a file like object, or bytes
        nameservers (list): A list of one or more nameservers to use
        (Cloudflare's public DNS resolvers by default)
        dns_timeout (float): Sets the DNS timeout in seconds
        parallel (bool): Parallel processing

    Returns:
        OrderedDict: The parsed DMARC aggregate report
    """
    arg_4 = extract_xml(arg_0)

    return parse_aggregate_report_xml(arg_4,
                                      arg_1=arg_1,
                                      timeout=arg_2,
                                      arg_3=arg_3)


def Func(arg_0):
    """
    Converts one or more parsed forensic reports to flat CSV format, including
    headers

    Args:
        reports: A parsed forensic report or list of parsed forensic reports

    Returns:
        str: Parsed forensic report data in flat CSV format, including headers
        """
    arg_1 = ["feedback_type", "user_agent", "version", "original_envelope_id",
              "original_mail_from", "original_rcpt_to", "arrival_date",
              "arrival_date_utc", "subject", "message_id",
              "authentication_results", "dkim_domain", "source_ip_address",
              "source_country", "source_reverse_dns", "source_base_domain",
              "delivery_result", "auth_failure", "reported_domain",
              "authentication_mechanisms", "sample_headers_only"]

    if type(arg_0) == OrderedDict:
        arg_0 = [arg_0]
    arg_2 = StringIO()
    arg_3 = DictWriter(arg_2, fieldnames=arg_1)
    arg_3.writeheader()
    for arg_4 in arg_0:
        arg_5 = arg_4.copy()
        arg_5["source_ip_address"] = arg_4["source"]["ip_address"]
        arg_5["source_reverse_dns"] = arg_4["source"]["reverse_dns"]
        arg_5["source_base_domain"] = arg_4["source"]["base_domain"]
        arg_5["source_country"] = arg_4["source"]["country"]
        del arg_5["source"]
        arg_5["subject"] = arg_4["parsed_sample"]["subject"]
        arg_5["auth_failure"] = ",".join(arg_4["auth_failure"])
        arg_6 = arg_4["authentication_mechanisms"]
        arg_5["authentication_mechanisms"] = ",".join(
            arg_6)
        del arg_5["sample"]
        del arg_5["parsed_sample"]
        arg_3.writerow(arg_5)

    return arg_2.getvalue()


def Func(arg_0, arg_1=None, arg_2=2.0,
                      arg_3=False, arg_4=False):
    """Parses a DMARC aggregate or forensic file at the given path, a
    file-like object. or bytes

    Args:
        input_: A path to a file, a file like object, or bytes
        nameservers (list): A list of one or more nameservers to use
        (Cloudflare's public DNS resolvers by default)
        dns_timeout (float): Sets the DNS timeout in seconds
        strip_attachment_payloads (bool): Remove attachment payloads from
        forensic report results
        parallel (bool): Parallel processing

    Returns:
        OrderedDict: The parsed DMARC report
    """
    if type(arg_0) == str:
        arg_5 = open(arg_0, "rb")
    elif type(arg_0) == bytes:
        arg_5 = BytesIO(arg_0)
    else:
        arg_5 = arg_0

    arg_6 = arg_5.read()
    try:
        arg_7 = parse_aggregate_report_file(arg_6, arg_1=arg_1,
                                             arg_2=arg_2,
                                             arg_4=arg_4)
        arg_8 = OrderedDict([("report_type", "aggregate"),
                               ("report", arg_7)])
    except InvalidAggregateReport:
        try:
            arg_9 = arg_3
            arg_8 = parse_report_email(arg_6,
                                         arg_1=arg_1,
                                         arg_2=arg_2,
                                         arg_3=arg_9,
                                         arg_4=arg_4)
        except InvalidDMARCReport:
            raise InvalidDMARCReport("Not a valid aggregate or forensic "
                                     "report")
    return arg_8


def Func(arg_0):
    """
    Returns a list of an IMAP server's capabilities

    Args:
        server (imapclient.IMAPClient): An instance of imapclient.IMAPClient

    Returns (list): A list of capabilities
    """

    arg_1 = list(map(str, list(arg_0.capabilities())))
    for arg_2 in range(len(arg_1)):
        arg_1[arg_2] = str(arg_1[arg_2]).replace("b'",
                                                       "").replace("'",
                                                                   "")
    logger.debug("IMAP server supports: {0}".format(arg_1))

    return arg_1


def Func(arg_0, arg_1, arg_2, arg_3, arg_4=0,
                  arg_5=False, arg_6=None, arg_7=None, arg_8=None,
                  arg_9=None, arg_10=None, arg_11=None):
    """
    Emails parsing results as a zip file

    Args:
        results (OrderedDict): Parsing results
        host: Mail server hostname or IP address
        mail_from: The value of the message from header
        mail_to : A list of addresses to mail to
        port (int): Port to use
        ssl (bool): Require a SSL connection from the start
        user: An optional username
        password: An optional password
        subject: Overrides the default message subject
        attachment_filename: Override the default attachment filename
        message: Override the default plain text body
        ssl_context: SSL context options
    """
    logging.debug("Emailing report to: {0}".format(",".join(arg_3)))
    arg_12 = datetime.now().strftime("%Y-%m-%d")
    if arg_9:
        if not arg_9.lower().endswith(".zip"):
            arg_9 += ".zip"
        arg_13 = arg_9
    else:
        arg_13 = "DMARC-{0}.zip".format(arg_12)

    assert isinstance(arg_3, list)

    arg_14 = MIMEMultipart()
    arg_14['From'] = arg_2
    arg_14['To'] = ", ".join(arg_3)
    arg_14['Date'] = email.utils.formatdate(localtime=True)
    arg_14['Subject'] = arg_8 or "DMARC results for {0}".format(arg_12)
    arg_15 = arg_10 or "Please see the attached zip file\n"

    arg_14.attach(MIMEText(arg_15))

    arg_16 = get_report_zip(arg_0)
    arg_17 = MIMEApplication(arg_16, Name=arg_13)

    arg_17['Content-Disposition'] = 'attachment; filename="{0}"'.format(arg_13)
    arg_14.attach(arg_17)

    try:
        if arg_11 is None:
            arg_11 = create_default_context()
        if arg_5:
            arg_18 = smtplib.SMTP_SSL(arg_1, arg_4=arg_4, context=arg_11)
            arg_18.connect(arg_1, arg_4)
            arg_18.ehlo_or_helo_if_needed()
        else:
            arg_18 = smtplib.SMTP(arg_1, arg_4=arg_4)
            arg_18.connect(arg_1, arg_4)
            arg_18.ehlo_or_helo_if_needed()
            if arg_18.has_extn("starttls"):
                arg_18.starttls(context=arg_11)
                arg_18.ehlo()
            else:
                logger.warning("SMTP server does not support STARTTLS. "
                               "Proceeding in plain text!")
        if arg_6 and arg_7:
            arg_18.login(arg_6, arg_7)
        arg_18.sendmail(arg_2, arg_3, arg_14.as_string())
    except smtplib.SMTPException as arg_19:
        arg_19 = arg_19.__str__().lstrip("b'").rstrip("'").rstrip(".")
        raise SMTPError(arg_19)
    except socket.gaierror:
        raise SMTPError("DNS resolution failed")
    except ConnectionRefusedError:
        raise SMTPError("Connection refused")
    except ConnectionResetError:
        raise SMTPError("Connection reset")
    except ConnectionAbortedError:
        raise SMTPError("Connection aborted")
    except TimeoutError:
        raise SMTPError("Connection timed out")
    except SSLError as arg_19:
        raise SMTPError("SSL error: {0}".format(arg_19.__str__()))
    except CertificateError as arg_19:
        raise SMTPError("Certificate error: {0}".format(arg_19.__str__()))


def Func(arg_0, arg_1):
        """
        Saves aggregate DMARC reports to Splunk

        Args:
            aggregate_reports: A list of aggregate report dictionaries
            to save in Splunk

        """
        logger.debug("Saving aggregate reports to Splunk")
        if type(arg_1) == dict:
            arg_1 = [arg_1]

        if len(arg_1) < 1:
            return

        arg_2 = arg_0._common_data.copy()
        arg_3 = ""
        for arg_4 in arg_1:
            for arg_5 in arg_4["records"]:
                arg_6 = dict()
                for arg_7 in arg_4["report_metadata"]:
                    arg_6[arg_7] = arg_4["report_metadata"][arg_7]
                arg_6["published_policy"] = arg_4["policy_published"]
                arg_6["source_ip_address"] = arg_5["source"][
                    "ip_address"]
                arg_6["source_country"] = arg_5["source"]["country"]
                arg_6["source_reverse_dns"] = arg_5["source"][
                    "reverse_dns"]
                arg_6["source_base_domain"] = arg_5["source"][
                    "base_domain"]
                arg_6["message_count"] = arg_5["count"]
                arg_6["disposition"] = arg_5["policy_evaluated"][
                    "disposition"
                ]
                arg_6["spf_aligned"] = arg_5["alignment"]["spf"]
                arg_6["dkim_aligned"] = arg_5["alignment"]["dkim"]
                arg_6["passed_dmarc"] = arg_5["alignment"]["dmarc"]
                arg_6["header_from"] = arg_5["identifiers"][
                    "header_from"]
                arg_6["envelope_from"] = arg_5["identifiers"][
                    "envelope_from"]
                if "dkim" in arg_5["auth_results"]:
                    arg_6["dkim_results"] = arg_5["auth_results"][
                        "dkim"]
                if "spf" in arg_5["auth_results"]:
                    arg_6["spf_results"] = arg_5["auth_results"][
                        "spf"]

                arg_2["sourcetype"] = "dmarc:aggregate"
                arg_8 = human_timestamp_to_timestamp(
                    arg_6["begin_date"])
                arg_2["time"] = arg_8
                arg_2["event"] = arg_6.copy()
                arg_3 += "{0}\n".format(json.dumps(arg_2))

        if not arg_0.session.verify:
            logger.debug("Skipping certificate verification for Splunk HEC")
        try:
            arg_9 = arg_0.session.post(arg_0.url, arg_2=arg_3,
                                         timeout=arg_0.timeout)
            arg_9 = arg_9.json()
        except Exception as e:
            raise SplunkError(e.__str__())
        if arg_9["code"] != 0:
            raise SplunkError(arg_9["text"])


def Func(arg_0):
    """
    Decodes a base64 string, with padding being optional

    Args:
        data: A base64 encoded string

    Returns:
        bytes: The decoded bytes

    """
    arg_0 = bytes(arg_0, encoding="ascii")
    arg_1 = len(arg_0) % 4
    if arg_1 != 0:
        arg_0 += b'=' * (4 - arg_1)
    return base64.b64decode(arg_0)


def Func(arg_0, arg_1=False):
    """
    Gets the base domain name for the given domain

    .. note::
        Results are based on a list of public domain suffixes at
        https://publicsuffix.org/list/public_suffix_list.dat.

    Args:
        domain (str): A domain or subdomain
        use_fresh_psl (bool): Download a fresh Public Suffix List

    Returns:
        str: The base domain of the given domain

    """
    arg_2 = os.path.join(tempdir, "public_suffix_list.dat")

    def download_psl():
        arg_3 = "https://publicsuffix.org/list/public_suffix_list.dat"
        # Use a browser-like user agent string to bypass some proxy blocks
        arg_4 = {"User-Agent": USER_AGENT}
        arg_5 = requests.get(arg_3, arg_4=arg_4).text
        with open(arg_2, "w", encoding="utf-8") as fresh_psl_file:
            fresh_psl_file.write(arg_5)

    if arg_1:
        if not os.path.exists(arg_2):
            download_psl()
        else:
            arg_6 = datetime.now() - datetime.fromtimestamp(
                os.stat(arg_2).st_mtime)
            if arg_6 > timedelta(hours=24):
                try:
                    download_psl()
                except Exception as error:
                    logger.warning(
                        "Failed to download an updated PSL {0}".format(error))
        with open(arg_2, encoding="utf-8") as psl_file:
            arg_7 = publicsuffix2.PublicSuffixList(psl_file)

        return arg_7.get_public_suffix(arg_0)
    else:
        return publicsuffix2.get_public_suffix(arg_0)


def Func(arg_0, arg_1=None, arg_2=None, arg_3=2.0):
    """
    Resolves an IP address to a hostname using a reverse DNS query

    Args:
        ip_address (str): The IP address to resolve
        cache (ExpiringDict): Cache storage
        nameservers (list): A list of one or more nameservers to use
        (Cloudflare's public DNS resolvers by default)
        timeout (float): Sets the DNS query timeout in seconds

    Returns:
        str: The reverse DNS hostname (if any)
    """
    arg_4 = None
    try:
        arg_5 = dns.reversename.from_address(arg_0)
        arg_4 = query_dns(arg_5, "PTR", arg_1=arg_1,
                             arg_2=arg_2,
                             arg_3=arg_3)[0]

    except dns.exception.DNSException:
        pass

    return arg_4


def Func(arg_0, arg_1=False):
    """
    Converts a human-readable timestamp into a Python ``DateTime`` object

    Args:
        human_timestamp (str): A timestamp string
        to_utc (bool): Convert the timestamp to UTC

    Returns:
        DateTime: The converted timestamp
    """

    arg_2 = {}

    if arg_1:
        arg_2 = {"TO_TIMEZONE": "UTC"}

    return dateparser.parse(arg_0, arg_2=arg_2)


def Func(arg_0, arg_1=None, arg_2=None,
                        arg_3=2.0, arg_4=False):
    """
    Returns reverse DNS and country information for the given IP address

    Args:
        ip_address (str): The IP address to check
        cache (ExpiringDict): Cache storage
        nameservers (list): A list of one or more nameservers to use
        (Cloudflare's public DNS resolvers by default)
        timeout (float): Sets the DNS timeout in seconds
        parallel (bool): parallel processing

    Returns:
        OrderedDict: ``ip_address``, ``reverse_dns``

    """
    arg_0 = arg_0.lower()
    if arg_1:
        arg_5 = arg_1.get(arg_0, None)
        if arg_5:
            return arg_5
    arg_5 = OrderedDict()
    arg_5["ip_address"] = arg_0
    arg_6 = get_reverse_dns(arg_0,
                                  arg_2=arg_2,
                                  arg_3=arg_3)
    arg_7 = get_ip_address_country(arg_0, arg_4=arg_4)
    arg_5["country"] = arg_7
    arg_5["reverse_dns"] = arg_6
    arg_5["base_domain"] = None
    if arg_6 is not None:
        arg_8 = get_base_domain(arg_6)
        arg_5["base_domain"] = arg_8

    return arg_5


def Func(arg_0):
    """
    Uses the ``msgconvert`` Perl utility to convert an Outlook MS file to
    standard RFC 822 format

    Args:
        msg_bytes (bytes): the content of the .msg file

    Returns:
        A RFC 822 string
    """
    if not is_outlook_msg(arg_0):
        raise ValueError("The supplied bytes are not an Outlook MSG file")
    arg_1 = os.getcwd()
    arg_2 = tempfile.mkdtemp()
    os.chdir(arg_2)
    with open("sample.msg", "wb") as msg_file:
        msg_file.write(arg_0)
    try:
        subprocess.check_call(["msgconvert", "sample.msg"],
                              stdout=null_file, stderr=null_file)
        arg_3 = "sample.eml"
        with open(arg_3, "rb") as eml_file:
            arg_4 = eml_file.read()
    except FileNotFoundError:
        raise EmailParserError(
            "Failed to convert Outlook MSG: msgconvert utility not found")
    finally:
        os.chdir(arg_1)
        shutil.rmtree(arg_2)

    return arg_4


def Func(arg_0, arg_1, arg_2, arg_3, arg_4=False):
    """Separated this function for multiprocessing"""
    try:
        arg_5 = parse_report_file(arg_0,
                                         arg_2=arg_2,
                                         arg_3=arg_3,
                                         strip_attachment_payloads=arg_1,
                                         arg_4=arg_4)
    except ParserError as error:
        return error, arg_0
    finally:
        global counter
        with counter.get_lock():
            counter.value += 1
    return arg_5, arg_0


def Func(arg_0, arg_1, arg_2):
        """
        Sends a PUB command to the server on the specified subject.

          ->> PUB hello 5
          ->> MSG_PAYLOAD: world
          <<- MSG hello 2 5

        """
        if arg_0.is_closed:
            raise ErrConnectionClosed
        if arg_0.is_draining_pubs:
            raise ErrConnectionDraining

        arg_3 = len(arg_2)
        if arg_3 > arg_0._max_payload:
            raise ErrMaxPayload
        yield from arg_0._Func(arg_1, _EMPTY_, arg_2, arg_3)


def Func(arg_0, arg_1, arg_2, arg_3):
        """
        Publishes a message tagging it with a reply subscription
        which can be used by those receiving the message to respond.

           ->> PUB hello   _INBOX.2007314fe0fcb2cdc2a2914c1 5
           ->> MSG_PAYLOAD: world
           <<- MSG hello 2 _INBOX.2007314fe0fcb2cdc2a2914c1 5

        """
        if arg_0.is_closed:
            raise ErrConnectionClosed
        if arg_0.is_draining_pubs:
            raise ErrConnectionDraining

        arg_4 = len(arg_3)
        if arg_4 > arg_0._max_payload:
            raise ErrMaxPayload
        yield from arg_0._publish(arg_1, arg_2.encode(), arg_3, arg_4)


def Func(arg_0, arg_1, **arg_2):
        """
        Sets the subcription to use a task per message to be processed.

        ..deprecated:: 7.0
          Will be removed 9.0.
        """
        arg_2["is_async"] = True
        arg_3 = yield from arg_0.subscribe(arg_1, **arg_2)
        return arg_3


def Func(arg_0, arg_1=60):
        """
        Sends a ping to the server expecting a pong back ensuring
        what we have written so far has made it to the server and
        also enabling measuring of roundtrip time.
        In case a pong is not returned within the allowed timeout,
        then it will raise ErrTimeout.
        """
        if arg_1 <= 0:
            raise ErrBadTimeout

        if arg_0.is_closed:
            raise ErrConnectionClosed

        arg_2 = asyncio.Future(loop=arg_0._loop)
        try:
            yield from arg_0._send_ping(arg_2)
            yield from asyncio.wait_for(arg_2, arg_1, loop=arg_0._loop)
        except asyncio.TimeoutError:
            arg_2.cancel()
            raise ErrTimeout


def Func(arg_0):
        """
        Looks up in the server pool for an available server
        and attempts to connect.
        """

        while True:
            if len(arg_0._server_pool) == 0:
                arg_0._current_server = None
                raise ErrNoServers

            arg_2 = time.monotonic()
            arg_3 = arg_0._server_pool.pop(0)
            if arg_0.options["max_reconnect_attempts"] > 0:
                if arg_3.reconnects > arg_0.options["max_reconnect_attempts"]:
                    # Discard server since already tried to reconnect too many times
                    continue

            # Not yet exceeded max_reconnect_attempts so can still use
            # this server in the future.
            arg_0._server_pool.append(arg_3)
            if arg_3.last_attempt is not None and arg_2 < arg_3.last_attempt + arg_0.options["reconnect_time_wait"]:
                # Backoff connecting to server if we attempted recently.
                yield from asyncio.sleep(arg_0.options["reconnect_time_wait"], loop=arg_0._loop)
            try:
                arg_3.last_attempt = time.monotonic()
                arg_5, arg_6 = yield from asyncio.open_connection(
                    arg_3.uri.hostname,
                    arg_3.uri.port,
                    loop=arg_0._loop,
                    limit=DEFAULT_BUFFER_SIZE)
                arg_0._current_server = arg_3

                # We keep a reference to the initial transport we used when
                # establishing the connection in case we later upgrade to TLS
                # after getting the first INFO message. This is in order to
                # prevent the GC closing the socket after we send CONNECT
                # and replace the transport.
                #
                # See https://github.com/nats-io/asyncio-nats/issues/43
                arg_0._bare_io_reader = arg_0._io_reader = arg_5
                arg_0._bare_io_writer = arg_0._io_writer = arg_6
                break
            except Exception as e:
                arg_3.last_attempt = time.monotonic()
                arg_3.reconnects += 1

                arg_0._err = e
                if arg_0._error_cb is not None:
                    yield from arg_0._error_cb(e)
                continue


def Func(arg_0, arg_1):
        """
        Process errors which occured while reading or parsing
        the protocol. If allow_reconnect is enabled it will
        try to switch the server to which it is currently connected
        otherwise it will disconnect.
        """
        if arg_0.is_connecting or arg_0.is_closed or arg_0.is_reconnecting:
            return

        if arg_0.options["allow_reconnect"] and arg_0.is_connected:
            arg_0._status = Client.RECONNECTING
            arg_0._ps.reset()

            if arg_0._reconnection_task is not None and not arg_0._reconnection_task.cancelled():
                # Cancel the previous task in case it may still be running.
                arg_0._reconnection_task.cancel()

            arg_0._reconnection_task = arg_0._loop.create_task(arg_0._attempt_reconnect())
        else:
            arg_0._process_disconnect()
            arg_0._err = arg_1
            yield from arg_0._close(Client.CLOSED, True)


def Func(arg_0):
        """
        Process PONG sent by server.
        """
        if len(arg_0._pongs) > 0:
            arg_1 = arg_0._pongs.pop(0)
            arg_1.set_result(True)
            arg_0._pongs_received += 1
            arg_0._pings_outstanding -= 1


def Func(arg_0):
        """
        Coroutine which continuously tries to consume pending commands
        and then flushes them to the socket.
        """
        while True:
            if not arg_0.is_connected or arg_0.is_connecting:
                break

            try:
                yield from arg_0._flush_queue.get()

                if arg_0._pending_data_size > 0:
                    arg_0._io_writer.writelines(arg_0._pending[:])
                    arg_0._pending = []
                    arg_0._pending_data_size = 0
                    yield from arg_0._io_writer.drain()
            except OSError as e:
                if arg_0._error_cb is not None:
                    yield from arg_0._error_cb(e)
                yield from arg_0._process_op_err(e)
                break
            except asyncio.CancelledError:
                break


def Func(arg_0):
        """
        Coroutine which gathers bytes sent by the server
        and feeds them to the protocol parser.
        In case of error while reading, it will stop running
        and its task has to be rescheduled.
        """
        while True:
            try:
                arg_1 = arg_0.is_closed or arg_0.is_reconnecting
                if arg_1 or arg_0._io_reader is None:
                    break
                if arg_0.is_connected and arg_0._io_reader.at_eof():
                    if arg_0._error_cb is not None:
                        yield from arg_0._error_cb(ErrStaleConnection)
                    yield from arg_0._process_op_err(ErrStaleConnection)
                    break

                arg_2 = yield from arg_0._io_reader.read(DEFAULT_BUFFER_SIZE)
                yield from arg_0._ps.parse(arg_2)
            except ErrProtocol:
                yield from arg_0._process_op_err(ErrProtocol)
                break
            except OSError as e:
                yield from arg_0._process_op_err(e)
                break
            except asyncio.CancelledError:
                break


def Func(arg_0):
    """
    Generates a timezone aware datetime if the 'USE_TZ' setting is enabled

    :param value: The datetime value
    :return: A locale aware datetime
    """
    return timezone.make_aware(arg_0, timezone.get_current_timezone()) if getattr(settings, 'USE_TZ', False) else arg_0


def Func(arg_0, arg_1):
        """ Load feature data from a 2D ndarray on disk. """
        arg_0.feature_images = np.load(arg_1)
        arg_0.feature_names = range(arg_0.feature_images.shape[1])


def Func(arg_0, arg_1, arg_2=None):
        """ Load feature image data from image files.

        Args:
          images: A list of image filenames.
          names: An optional list of strings to use as the feature names. Must
            be in the same order as the images.
        """
        if arg_2 is not None and len(arg_2) != len(arg_1):
            raise Exception(
                "Lists of feature names and images must be of same length!")
        arg_0.feature_names = arg_2 if arg_2 is not None else arg_1
        arg_0.feature_images = imageutils.load_imgs(arg_1, arg_0.masker)


def Func(arg_0, arg_1):
        """ Decode images using Pearson's r.

        Computes the correlation between each input image and each feature
        image across voxels.

        Args:
            imgs_to_decode: An ndarray of images to decode, with voxels in rows
                and images in columns.

        Returns:
            An n_features x n_images 2D array, with each cell representing the
            pearson correlation between the i'th feature and the j'th image
            across all voxels.
        """
        arg_2, arg_3 = arg_1.astype(float), arg_0.feature_images.astype(float)
        return arg_0._xy_corr(arg_2, arg_3)


def Func(arg_0, arg_1):
        """ Decoding using the dot product.
        """
        return np.dot(arg_1.T, arg_0.feature_images).T


def Func(arg_0, arg_1, arg_2=0.08, arg_3=True,
                           arg_4=None, arg_5=None,
                           arg_6="scale"):
    """ Set up data for a classification task given a set of masks

        Given a set of masks, this function retrieves studies associated with
        each mask at the specified threshold, optionally removes overlap and
        filters by studies and features, and returns studies by feature matrix
        (X) and class labels (y)

        Args:
            dataset: a Neurosynth dataset
            maks: a list of paths to Nifti masks
            threshold: percentage of voxels active within the mask for study
                to be included
            remove_overlap: A boolean indicating if studies studies that
                appear in more than one mask should be excluded
            studies: An optional list of study names used to constrain the set
                used in classification. If None, will use all features in the
                dataset.
            features: An optional list of feature names used to constrain the
                set used in classification. If None, will use all features in
                the dataset.
            regularize: Optional boolean indicating if X should be regularized

        Returns:
            A tuple (X, y) of np arrays.
            X is a feature by studies matrix and y is a vector of class labels
    """

    import nibabel as nib
    import os

    # Load masks using NiBabel

    try:
        arg_7 = [nib.load(os.path.relpath(m)) for m in arg_1]
    except OSError:
        print('Error loading masks. Check the path')

    # Get a list of studies that activate for each mask file--i.e.,  a list of
    # lists

    arg_8 = [arg_0.get_studies(mask=m, activation_threshold=arg_2)
                   for m in arg_7]

    # Flattened ids

    arg_9 = reduce(lambda a, b: a + b, arg_8)

    # Remove duplicates

    if arg_3:
        import collections
        arg_9 = [id for (id, count) in
                    collections.Counter(arg_9).items() if count == 1]
        arg_8 = [[x for x in m if x in arg_9] for m in
                       arg_8]  # Remove

    # Create class label(y)
    arg_10 = [[idx] * len(ids) for (idx, ids) in enumerate(arg_8)]
    arg_10 = reduce(lambda a, b: a + b, arg_10)  # Flatten
    arg_10 = np.array(arg_10)

    # Extract feature set for each class separately
    arg_11 = [arg_0.get_feature_data(ids=group_ids, arg_5=arg_5)
         for group_ids in arg_8]

    arg_11 = np.vstack(tuple(arg_11))

    if arg_6:
        arg_11 = regularize(arg_11, method=arg_6)

    return (arg_11, arg_10)


def Func(arg_0, arg_1):
    """ Returns a list with the order that features requested appear in
    dataset """
    arg_2 = arg_0.get_feature_names()

    arg_3 = [arg_2.index(f) for f in arg_1]

    return arg_3


def Func(arg_0, arg_1='auto', arg_2=None):
        """ Sets the class_weight of the classifier to match y """

        if arg_1 is None:
            arg_3 = None

            try:
                arg_0.clf.set_params(arg_1=arg_3)
            except ValueError:
                pass

        elif arg_1 == 'auto':
            arg_4 = np.bincount(arg_2)
            arg_5 = np.nonzero(arg_4)[0]
            arg_4 = arg_4 / float(arg_4.sum())
            arg_3 = dict(zip(arg_5[::-1], arg_4[arg_5]))

            try:
                arg_0.clf.set_params(arg_1=arg_3)
            except ValueError:
                import warnings
                warnings.warn(
                    "Tried to set class_weight, but failed. The classifier "
                    "probably doesn't support it")