def METHOD_NAME(self,
                  username,
                  password,
                  menu_port=None,
                  pri_prompt_terminator=r".*# ",
                  alt_prompt_terminator=r".*\$ ",
                  username_pattern=r"(?:user:|username|login|user name)",
                  pwd_pattern=r"assword",
                  delay_factor=1,
                  max_loops=20
                  ):
    """
    Perform a stage_2 login
    """
    delay_factor = self.select_delay_factor(delay_factor)
    time.sleep(1 * delay_factor)
    output = ""
    return_msg = ""
    i = 1
    menu_port_sent = False
    user_sent = False
    password_sent = False
    # The following prompt is only for SONiC
    # Need to add more login failure prompt for other system
    login_failure_prompt = r".*incorrect"
    while i <= max_loops:
        try:
            if menu_port and not menu_port_sent:
                self.write_and_poll("menu ports", "Selection:")
                self.write_channel(str(self.menu_port) + self.RETURN)
                menu_port_sent = True
            output = self.read_channel()
            return_msg += output
            # Search for username pattern / send username
            if not user_sent and re.search(username_pattern, output, flags=re.I):
                self.write_channel(username + self.RETURN)
                time.sleep(1 * delay_factor)
                output = self.read_channel()
                return_msg += output
                user_sent = True
            # Search for password pattern / send password
            if user_sent and not password_sent and re.search(pwd_pattern, output, flags=re.I):
                self.write_channel(password + self.RETURN)
                time.sleep(0.5 * delay_factor)
                output = self.read_channel()
                return_msg += output
                password_sent = True
                if re.search(
                        pri_prompt_terminator, output, flags=re.M
                ) or re.search(alt_prompt_terminator, output, flags=re.M):
                    return return_msg
            # Check if proper data received
            if re.search(pri_prompt_terminator, output, flags=re.M) or re.search(
                    alt_prompt_terminator, output, flags=re.M
            ):
                return return_msg
            # Check if login failed
            if re.search(login_failure_prompt, output, flags=re.M):
                # Wait a short time or the next login will be refused
                time.sleep(1 * delay_factor)
                msg = "Login failed: {}".format(self.host)
                raise NetMikoAuthenticationException(msg)
            self.write_channel(self.RETURN)
            time.sleep(0.5 * delay_factor)
            i += 1
        except EOFError:
            self.remote_conn.close()
            msg = "Login failed: {}".format(self.host)
            raise NetMikoAuthenticationException(msg)
    # Last try to see if we already logged in
    self.write_channel(self.RETURN)
    time.sleep(0.5 * delay_factor)
    output = self.read_channel()
    return_msg += output
    if re.search(pri_prompt_terminator, output, flags=re.M) or re.search(
            alt_prompt_terminator, output, flags=re.M
    ):
        return return_msg
    self.remote_conn.close()
    msg = "Login failed: {}".format(self.host)
    raise NetMikoAuthenticationException(msg)