import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def shuffle(input_string: str) -> str:
    """
    Return a new string containing same chars of the given one but in a randomized order.

    *Example:*

    >>> shuffle('hello world') # possible output: 'l wodheorll'

    :param input_string: String to shuffle
    :type input_string: str
    :return: Shuffled string
    """
    if not is_string(input_string):
        raise InvalidInputError(input_string)

    # turn the string into a list of chars
    chars = list(input_string)

    # shuffle the list
    random.shuffle(chars)

    # convert the shuffled list back to string
    return ''.join(chars)


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def strip_html(input_string: str, keep_tag_content: bool = False) -> str:
    """
    Remove html code contained into the given string.

    *Examples:*

    >>> strip_html('test: click here') # returns 'test: '
    >>> strip_html('test: click here', keep_tag_content=True) # returns 'test: click here'

    :param input_string: String to manipulate.
    :type input_string: str
    :param keep_tag_content: True to preserve tag content, False to remove tag and its content too (default).
    :type keep_tag_content: bool
    :return: String with html removed.
    """
    if not is_string(input_string):
        raise InvalidInputError(input_string)

    r = HTML_TAG_ONLY_RE if keep_tag_content else HTML_RE

    return r.sub('', input_string)


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

class __StringFormatter:

    def __init__(self, input_string):
        if not is_string(input_string):
            raise InvalidInputError(input_string)

        self.input_string = input_string

def prettify(input_string: str) -> str:
    """
    Reformat a string by applying the following basic grammar and formatting rules:

    - String cannot start or end with spaces
    - The first letter in the string and the ones after a dot, an exclamation or a question mark must be uppercase
    - String cannot have multiple sequential spaces, empty lines or punctuation (except for "?", "!" and ".")
    - Arithmetic operators (+, -, /, \\*, =) must have one, and only one space before and after themselves
    - One, and only one space should follow a dot, a comma, an exclamation or a question mark
    - Text inside double quotes cannot start or end with spaces, but one, and only one space must come first and \
    after quotes (foo" bar"baz -> foo "bar" baz)
    - Text inside round brackets cannot start or end with spaces, but one, and only one space must come first and \
    after brackets ("foo(bar )baz" -> "foo (bar) baz")
    - Percentage sign ("%") cannot be preceded by a space if there is a number before ("100 %" -> "100%")
    - Saxon genitive is correct ("Dave' s dog" -> "Dave's dog")

    *Examples:*

    >>> prettify(' unprettified string ,, like this one,will be"prettified" .it\\' s awesome! ')
    >>> # -> 'Unprettified string, like this one, will be "prettified". It\'s awesome!'

    :param input_string: String to manipulate
    :return: Prettified string.
    """
    formatted = __StringFormatter(input_string).format()
    return formatted


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def asciify(input_string: str) -> str:
    """
    Force string content to be ascii-only by translating all non-ascii chars into the closest possible representation
    (eg: ó -> o, Ë -> E, ç -> c...).

    **Bear in mind**: Some chars may be lost if impossible to translate.

    *Example:*

    >>> asciify('èéùúòóäåëýñÅÀÁÇÌÍÑÓË') # returns 'eeuuooaaeynAAACIINOE'

    :param input_string: String to convert
    :return: Ascii utf-8 string
    """
    if not is_string(input_string):
        raise InvalidInputError(input_string)

    # "NFKD" is the algorithm which is able to successfully translate the most of non-ascii chars
    normalized = unicodedata.normalize('NFKD', input_string)

    # encode string forcing ascii and ignore any errors (unrepresentable chars will be stripped out)
    ascii_bytes = normalized.encode('ascii', 'ignore')

    # turns encoded bytes into an utf-8 string
    ascii_string = ascii_bytes.decode('utf-8')

    return ascii_string


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def slugify(input_string: str, separator: str = '-') -> str:
    """
    Converts a string into a "slug" using provided separator.
    The returned string has the following properties:

    - it has no spaces
    - all letters are in lower case
    - all punctuation signs and non alphanumeric chars are removed
    - words are divided using provided separator
    - all chars are encoded as ascii (by using `asciify()`)
    - is safe for URL

    *Examples:*

    >>> slugify('Top 10 Reasons To Love Dogs!!!') # returns: 'top-10-reasons-to-love-dogs'
    >>> slugify('Mönstér Mägnët') # returns 'monster-magnet'

    :param input_string: String to convert.
    :type input_string: str
    :param separator: Sign used to join string tokens (default to "-").
    :type separator: str
    :return: Slug string
    """
    if not is_string(input_string):
        raise InvalidInputError(input_string)

    # replace any character that is NOT letter or number with spaces
    out = NO_LETTERS_OR_NUMBERS_RE.sub(' ', input_string.lower()).strip()

    # replace spaces with join sign
    out = SPACES_RE.sub(separator, out)

    # normalize joins (remove duplicates)
    out = re.sub(re.escape(separator) + r'+', separator, out)

    return asciify(out)


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def booleanize(input_string: str) -> bool:
    """
    Turns a string into a boolean based on its content (CASE INSENSITIVE).

    A positive boolean (True) is returned if the string value is one of the following:

    - "true"
    - "1"
    - "yes"
    - "y"

    Otherwise False is returned.

    *Examples:*

    >>> booleanize('true') # returns True
    >>> booleanize('YES') # returns True
    >>> booleanize('nope') # returns False

    :param input_string: String to convert
    :type input_string: str
    :return: True if the string contains a boolean-like positive value, false otherwise
    """
    if not is_string(input_string):
        raise InvalidInputError(input_string)

    return input_string.lower() in ('true', '1', 'yes', 'y')


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def strip_margin(input_string: str) -> str:
    """
    Removes tab indentation from multi line strings (inspired by analogous Scala function).

    *Example:*

    >>> strip_margin('''
    >>>                 line 1
    >>>                 line 2
    >>>                 line 3
    >>> ''')
    >>> # returns:
    >>> '''
    >>> line 1
    >>> line 2
    >>> line 3
    >>> '''

    :param input_string: String to format
    :type input_string: str
    :return: A string without left margins
    """
    if not is_string(input_string):
        raise InvalidInputError(input_string)

    line_separator = '\n'
    lines = [MARGIN_RE.sub('', line) for line in input_string.split(line_separator)]
    out = line_separator.join(lines)

    return out


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def compress(input_string: str, encoding: str = 'utf-8', compression_level: int = 9) -> str:
    """
    Compress the given string by returning a shorter one that can be safely used in any context (like URL) and
    restored back to its original state using `decompress()`.

    **Bear in mind:**
    Besides the provided `compression_level`, the compression result (how much the string is actually compressed
    by resulting into a shorter string) depends on 2 factors:

    1. The amount of data (string size): short strings might not provide a significant compression result\
    or even be longer than the given input string (this is due to the fact that some bytes have to be embedded\
    into the compressed string in order to be able to restore it later on)\

    2. The content type: random sequences of chars are very unlikely to be successfully compressed, while the best\
    compression result is obtained when the string contains several recurring char sequences (like in the example).

    Behind the scenes this method makes use of the standard Python's zlib and base64 libraries.

    *Examples:*

    >>> n = 0 # <- ignore this, it's a fix for Pycharm (not fixable using ignore comments)
    >>> # "original" will be a string with 169 chars:
    >>> original = ' '.join(['word n{}'.format(n) for n in range(20)])
    >>> # "compressed" will be a string of 88 chars
    >>> compressed = compress(original)

    :param input_string: String to compress (must be not empty or a ValueError will be raised).
    :type input_string: str
    :param encoding: String encoding (default to "utf-8").
    :type encoding: str
    :param compression_level: A value between 0 (no compression) and 9 (best compression), default to 9.
    :type compression_level: int
    :return: Compressed string.
    """
    return __StringCompressor.compress(input_string, encoding, compression_level)


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def decompress(input_string: str, encoding: str = 'utf-8') -> str:
    """
    Restore a previously compressed string (obtained using `compress()`) back to its original state.

    :param input_string: String to restore.
    :type input_string: str
    :param encoding: Original string encoding.
    :type encoding: str
    :return: Decompressed string.
    """
    return __StringCompressor.decompress(input_string, encoding)


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def roman_encode(input_number: Union[str, int]) -> str:
    """
    Convert the given number/string into a roman number.

    The passed input must represents a positive integer in the range 1-3999 (inclusive).

    Why this limit? You may be wondering:

    1. zero is forbidden since there is no related representation in roman numbers
    2. the upper bound 3999 is due to the limitation in the ascii charset\
    (the higher quantity sign displayable in ascii is "M" which is equal to 1000, therefore based on\
    roman numbers rules we can use 3 times M to reach 3000 but we can't go any further in thousands without\
    special "boxed chars").

    *Examples:*

    >>> roman_encode(37) # returns 'XXXVIII'
    >>> roman_encode('2020') # returns 'MMXX'

    :param input_number: An integer or a string to be converted.
    :type input_number: Union[str, int]
    :return: Roman number string.
    """
    return __RomanNumbers.encode(input_number)


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def roman_decode(input_string: str) -> int:
    """
    Decode a roman number string into an integer if the provided string is valid.

    *Example:*

    >>> roman_decode('VII') # returns 7

    :param input_string: (Assumed) Roman number
    :type input_string: str
    :return: Integer value
    """
    return __RomanNumbers.decode(input_string)


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

class __StringFormatter:

    def __init__(self, input_string):
        if not is_string(input_string):
            raise InvalidInputError(input_string)

        self.input_string = input_string


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

class __StringFormatter:

    def __init__(self, input_string):
        if not is_string(input_string):
            raise InvalidInputError(input_string)

        self.input_string = input_string

    def format(self) -> str:
        # map of temporary placeholders
        placeholders = {}
        out = self.input_string

        # looks for url or email and updates placeholders map with found values
        placeholders.update({self.__placeholder_key(): m[0] for m in URLS_RE.findall(out)})
        placeholders.update({self.__placeholder_key(): m for m in EMAILS_RE.findall(out)})

        # replace original value with the placeholder key
        for p in placeholders:
            out = out.replace(placeholders[p], p, 1)

        out = PRETTIFY_RE['UPPERCASE_FIRST_LETTER'].sub(self.__uppercase_first_char, out)
        out = PRETTIFY_RE['DUPLICATES'].sub(self.__remove_duplicates, out)
        out = PRETTIFY_RE['RIGHT_SPACE'].sub(self.__ensure_right_space_only, out)
        out = PRETTIFY_RE['LEFT_SPACE'].sub(self.__ensure_left_space_only, out)
        out = PRETTIFY_RE['SPACES_AROUND'].sub(self.__ensure_spaces_around, out)
        out = PRETTIFY_RE['SPACES_INSIDE'].sub(self.__remove_internal_spaces, out)
        out = PRETTIFY_RE['UPPERCASE_AFTER_SIGN'].sub(self.__uppercase_first_letter_after_sign, out)
        out = PRETTIFY_RE['SAXON_GENITIVE'].sub(self.__fix_saxon_genitive, out)
        out = out.strip()

        # restore placeholder keys with their associated original value
        for p in placeholders:
            out = out.replace(p, placeholders[p], 1)

        return out


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

def is_integer(input_string: str) -> bool:
    """
    Checks whether the given string represents an integer or not.

    An integer may be signed or unsigned or use a "scientific notation".

    *Examples:*

    >>> is_integer('42') # returns true
    >>> is_integer('42.0') # returns false

    :param input_string: String to check
    :type input_string: str
    :return: True if integer, false otherwise
    """
    return is_number(input_string) and '.' not in input_string


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

def is_decimal(input_string: str) -> bool:
    """
    Checks whether the given string represents a decimal or not.

    A decimal may be signed or unsigned or use a "scientific notation".

    >>> is_decimal('42.0') # returns true
    >>> is_decimal('42') # returns false

    :param input_string: String to check
    :type input_string: str
    :return: True if integer, false otherwise
    """
    return is_number(input_string) and '.' in input_string


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

def is_url(input_string: Any, allowed_schemes: Optional[List[str]] = None) -> bool:
    """
    Check if a string is a valid url.

    *Examples:*

    >>> is_url('http://www.mysite.com') # returns true
    >>> is_url('https://mysite.com') # returns true
    >>> is_url('.mysite.com') # returns false

    :param input_string: String to check.
    :type input_string: str
    :param allowed_schemes: List of valid schemes ('http', 'https', 'ftp'...). Default to None (any scheme is valid).
    :type allowed_schemes: Optional[List[str]]
    :return: True if url, false otherwise
    """
    if not is_full_string(input_string):
        return False

    valid = URL_RE.match(input_string) is not None

    if allowed_schemes:
        return valid and any([input_string.startswith(s) for s in allowed_schemes])

    return valid


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

def is_email(input_string: Any) -> bool:
    """
    Check if a string is a valid email.

    Reference: https://tools.ietf.org/html/rfc3696#section-3

    *Examples:*

    >>> is_email('my.email@the-provider.com') # returns true
    >>> is_email('@gmail.com') # returns false

    :param input_string: String to check.
    :type input_string: str
    :return: True if email, false otherwise.
    """
    # first simple "pre check": it must be a non empty string with max len 320 and cannot start with a dot
    if not is_full_string(input_string) or len(input_string) > 320 or input_string.startswith('.'):
        return False

    try:
        # we expect 2 tokens, one before "@" and one after, otherwise we have an exception and the email is not valid
        head, tail = input_string.split('@')

        # head's size must be <= 64, tail <= 255, head must not start with a dot or contain multiple consecutive dots
        if len(head) > 64 or len(tail) > 255 or head.endswith('.') or ('..' in head):
            return False

        # removes escaped spaces, so that later on the test regex will accept the string
        head = head.replace('\\ ', '')
        if head.startswith('"') and head.endswith('"'):
            head = head.replace(' ', '')[1:-1]

        return EMAIL_RE.match(head + '@' + tail) is not None

    except ValueError:
        # borderline case in which we have multiple "@" signs but the head part is correctly escaped
        if ESCAPED_AT_SIGN.search(input_string) is not None:
            # replace "@" with "a" in the head
            return is_email(ESCAPED_AT_SIGN.sub('a', input_string))

        return False


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

def is_credit_card(input_string: Any, card_type: str = None) -> bool:
    """
    Checks if a string is a valid credit card number.
    If card type is provided then it checks against that specific type only,
    otherwise any known credit card number will be accepted.

    Supported card types are the following:

    - VISA
    - MASTERCARD
    - AMERICAN_EXPRESS
    - DINERS_CLUB
    - DISCOVER
    - JCB

    :param input_string: String to check.
    :type input_string: str
    :param card_type: Card type. Default to None (any card).
    :type card_type: str

    :return: True if credit card, false otherwise.
    """
    if not is_full_string(input_string):
        return False

    if card_type:
        if card_type not in CREDIT_CARDS:
            raise KeyError(
                'Invalid card type "{}". Valid types are: {}'.format(card_type, ', '.join(CREDIT_CARDS.keys()))
            )
        return CREDIT_CARDS[card_type].match(input_string) is not None

    for c in CREDIT_CARDS:
        if CREDIT_CARDS[c].match(input_string) is not None:
            return True

    return False


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

def is_json(input_string: Any) -> bool:
    """
    Check if a string is a valid json.

    *Examples:*

    >>> is_json('{"name": "Peter"}') # returns true
    >>> is_json('[1, 2, 3]') # returns true
    >>> is_json('{nope}') # returns false

    :param input_string: String to check.
    :type input_string: str
    :return: True if json, false otherwise
    """
    if is_full_string(input_string) and JSON_WRAPPER_RE.match(input_string) is not None:
        try:
            return isinstance(json.loads(input_string), (dict, list))
        except (TypeError, ValueError, OverflowError):
            pass

    return False


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

def is_ip_v4(input_string: Any) -> bool:
    """
    Checks if a string is a valid ip v4.

    *Examples:*

    >>> is_ip_v4('255.200.100.75') # returns true
    >>> is_ip_v4('nope') # returns false (not an ip)
    >>> is_ip_v4('255.200.100.999') # returns false (999 is out of range)

    :param input_string: String to check.
    :type input_string: str
    :return: True if an ip v4, false otherwise.
    """
    if not is_full_string(input_string) or SHALLOW_IP_V4_RE.match(input_string) is None:
        return False

    # checks that each entry in the ip is in the valid range (0 to 255)
    for token in input_string.split('.'):
        if not (0 <= int(token) <= 255):
            return False

    return True


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

def is_ip(input_string: Any) -> bool:
    """
    Checks if a string is a valid ip (either v4 or v6).

    *Examples:*

    >>> is_ip('255.200.100.75') # returns true
    >>> is_ip('2001:db8:85a3:0000:0000:8a2e:370:7334') # returns true
    >>> is_ip('1.2.3') # returns false

    :param input_string: String to check.
    :type input_string: str
    :return: True if an ip, false otherwise.
    """
    return is_ip_v6(input_string) or is_ip_v4(input_string)


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

def is_palindrome(input_string: Any, ignore_spaces: bool = False, ignore_case: bool = False) -> bool:
    """
    Checks if the string is a palindrome (https://en.wikipedia.org/wiki/Palindrome).

    *Examples:*

    >>> is_palindrome('LOL') # returns true
    >>> is_palindrome('Lol') # returns false
    >>> is_palindrome('Lol', ignore_case=True) # returns true
    >>> is_palindrome('ROTFL') # returns false

    :param input_string: String to check.
    :type input_string: str
    :param ignore_spaces: False if white spaces matter (default), true otherwise.
    :type ignore_spaces: bool
    :param ignore_case: False if char case matters (default), true otherwise.
    :type ignore_case: bool
    :return: True if the string is a palindrome (like "otto", or "i topi non avevano nipoti" if strict=False),\
    False otherwise
    """
    if not is_full_string(input_string):
        return False

    if ignore_spaces:
        input_string = SPACES_RE.sub('', input_string)

    string_len = len(input_string)

    # Traverse the string one char at step, and for each step compares the
    # "head_char" (the one on the left of the string) to the "tail_char" (the one on the right).
    # In this way we avoid to manipulate the whole string in advance if not necessary and provide a faster
    # algorithm which can scale very well for long strings.
    for index in range(string_len):
        head_char = input_string[index]
        tail_char = input_string[string_len - index - 1]

        if ignore_case:
            head_char = head_char.lower()
            tail_char = tail_char.lower()

        if head_char != tail_char:
            return False

    return True


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

class __ISBNChecker:

    def __init__(self, input_string: str, normalize: bool = True):
        if not is_string(input_string):
            raise InvalidInputError(input_string)

        self.input_string = input_string.replace('-', '') if normalize else input_string

def is_isbn(input_string: str, normalize: bool = True) -> bool:
    """
    Checks if the given string represents a valid ISBN (International Standard Book Number).
    By default hyphens in the string are ignored, so digits can be separated in different ways, by calling this
    function with `normalize=False` only digit-only strings will pass the validation.

    *Examples:*

    >>> is_isbn('9780312498580') # returns true
    >>> is_isbn('1506715214') # returns true

    :param input_string: String to check.
    :param normalize: True to ignore hyphens ("-") in the string (default), false otherwise.
    :return: True if valid ISBN (10 or 13), false otherwise.
    """
    checker = __ISBNChecker(input_string, normalize)
    return checker.is_isbn_13() or checker.is_isbn_10()


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

class __ISBNChecker:

    def __init__(self, input_string: str, normalize: bool = True):
        if not is_string(input_string):
            raise InvalidInputError(input_string)

        self.input_string = input_string.replace('-', '') if normalize else input_string

    def is_isbn_13(self) -> bool:
        if len(self.input_string) == 13:
            product = 0

            try:
                for index, digit in enumerate(self.input_string):
                    weight = 1 if (index % 2 == 0) else 3
                    product += int(digit) * weight

                return product % 10 == 0

            except ValueError:
                pass

        return False


import json
import string
from typing import Any, Optional, List
from ._regex import *
from .errors import InvalidInputError

__all__ = [
    'is_string',
    'is_full_string',
    'is_number',
    'is_integer',
    'is_decimal',
    'is_url',
    'is_email',
    'is_credit_card',
    'is_camel_case',
    'is_snake_case',
    'is_json',
    'is_uuid',
    'is_ip_v4',
    'is_ip_v6',
    'is_ip',
    'is_isbn_10',
    'is_isbn_13',
    'is_isbn',
    'is_palindrome',
    'is_pangram',
    'is_isogram',
    'is_slug',
    'contains_html',
    'words_count',
]

class __ISBNChecker:

    def __init__(self, input_string: str, normalize: bool = True):
        if not is_string(input_string):
            raise InvalidInputError(input_string)

        self.input_string = input_string.replace('-', '') if normalize else input_string

    def is_isbn_10(self) -> bool:
        if len(self.input_string) == 10:
            product = 0

            try:
                for index, digit in enumerate(self.input_string):
                    product += int(digit) * (index + 1)

                return product % 11 == 0

            except ValueError:
                pass

        return False


from .primitive import Register

def mute(*objects: Register) -> None:
    """
    Use this function to mute multiple register-objects at once.

    :param objects: Pass multiple register-objects to the function.
    """
    err = ValueError(
        "The mute() method can only be used with objects that inherit "
        "from the 'Register class'."
    )
    for obj in objects:
        if not isinstance(obj, Register):
            raise err
        obj.mute()


from .primitive import Register

def unmute(*objects: Register) -> None:
    """
    Use this function to unmute multiple register-objects at once.

    :param objects: Pass multiple register-objects to the function.
    """
    err = ValueError(
        "The unmute() method can only be used with objects that inherit "
        "from the 'Register class'."
    )
    for obj in objects:
        if not isinstance(obj, Register):
            raise err
        obj.unmute()


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Style(str):

    rules: Iterable[StylingRule]

    def __new__(cls, *rules: StylingRule, value: str = "") -> "Style":
        new_cls = str.__new__(cls, value)  # type: ignore
        setattr(new_cls, "rules", rules)
        return new_cls


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Register:

    def __init__(self):
        self.renderfuncs: Renderfuncs = {}
        self.is_muted = False
        self.eightbit_call = lambda x: x
        self.rgb_call = lambda r, g, b: (r, g, b)


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Register:

    def __init__(self):
        self.renderfuncs: Renderfuncs = {}
        self.is_muted = False
        self.eightbit_call = lambda x: x
        self.rgb_call = lambda r, g, b: (r, g, b)

    def __setattr__(self, name: str, value: Style):

        if isinstance(value, Style):

            if self.is_muted:
                rendered_style = Style(*value.rules, value="")
            else:
                rendered, rules = _render_rules(self.renderfuncs, value.rules)
                rendered_style = Style(*rules, value=rendered)

            return super().__setattr__(name, rendered_style)
        else:
            # TODO: Why do we need this??? What should be set here?
            return super().__setattr__(name, value)


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Register:

    def __init__(self):
        self.renderfuncs: Renderfuncs = {}
        self.is_muted = False
        self.eightbit_call = lambda x: x
        self.rgb_call = lambda r, g, b: (r, g, b)

    def __call__(self, *args: Union[int, str], **kwargs) -> str:
        """
        This function is to handle calls such as `fg(42)`, `bg(102, 49, 42)`, `fg('red')`.
        """

        # Return empty str if object is muted.
        if self.is_muted:
            return ""

        len_args = len(args)

        if len_args == 1:

            # If input is an 8bit color code, run 8bit render function.
            if isinstance(args[0], int):
                return self.eightbit_call(*args, **kwargs)

            # If input is a string, return attribute with the name that matches
            # input.
            else:
                return getattr(self, args[0])

        # If input is an 24bit color code, run 24bit render function.
        elif len_args == 3:
            return self.rgb_call(*args, **kwargs)

        else:
            return ""


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Register:

    def __init__(self):
        self.renderfuncs: Renderfuncs = {}
        self.is_muted = False
        self.eightbit_call = lambda x: x
        self.rgb_call = lambda r, g, b: (r, g, b)

    def set_eightbit_call(self, rendertype: Type[RenderType]) -> None:
        """
        You can call a register-object directly. A call like this ``fg(144)``
        is a Eightbit-call. With this method you can define the render-type for such calls.

        :param rendertype: The new rendertype that is used for Eightbit-calls.
        """
        func: Callable = self.renderfuncs[rendertype]
        self.eightbit_call = func


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Register:

    def __init__(self):
        self.renderfuncs: Renderfuncs = {}
        self.is_muted = False
        self.eightbit_call = lambda x: x
        self.rgb_call = lambda r, g, b: (r, g, b)

    def set_rgb_call(self, rendertype: Type[RenderType]) -> None:
        """
        You can call a register-object directly. A call like this ``fg(10, 42, 255)``
        is a RGB-call. With this method you can define the render-type for such calls.

        :param rendertype: The new rendertype that is used for RGB-calls.
        """
        func: Callable = self.renderfuncs[rendertype]
        self.rgb_call = func


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Register:

    def __init__(self):
        self.renderfuncs: Renderfuncs = {}
        self.is_muted = False
        self.eightbit_call = lambda x: x
        self.rgb_call = lambda r, g, b: (r, g, b)

    def set_renderfunc(self, rendertype: Type[RenderType], func: Callable) -> None:
        """
        With this method you can add or replace render-functions for a given register-object:

        :param rendertype: The render type for which the new renderfunc is used.
        :param func: The new render function.
        """
        # Save new render-func in register
        self.renderfuncs.update({rendertype: func})

        # Update style atributes and styles with the new renderfunc.
        for attr_name in dir(self):
            val = getattr(self, attr_name)
            if isinstance(val, Style):
                setattr(self, attr_name, val)


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Register:

    def __init__(self):
        self.renderfuncs: Renderfuncs = {}
        self.is_muted = False
        self.eightbit_call = lambda x: x
        self.rgb_call = lambda r, g, b: (r, g, b)

    def mute(self) -> None:
        """
        Sometimes it is useful to disable the formatting for a register-object. You can
        do so by invoking this method.
        """
        self.is_muted = True

        for attr_name in dir(self):
            val = getattr(self, attr_name)
            if isinstance(val, Style):
                setattr(self, attr_name, val)


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Register:

    def __init__(self):
        self.renderfuncs: Renderfuncs = {}
        self.is_muted = False
        self.eightbit_call = lambda x: x
        self.rgb_call = lambda r, g, b: (r, g, b)

    def unmute(self) -> None:
        """
        Use this method to unmute a previously muted register object.
        """
        self.is_muted = False

        for attr_name in dir(self):
            val = getattr(self, attr_name)
            if isinstance(val, Style):
                setattr(self, attr_name, val)


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Register:

    def __init__(self):
        self.renderfuncs: Renderfuncs = {}
        self.is_muted = False
        self.eightbit_call = lambda x: x
        self.rgb_call = lambda r, g, b: (r, g, b)

    def as_dict(self) -> Dict[str, str]:
        """
        Export color register as dict.
        """
        items: Dict[str, str] = {}

        for name in dir(self):

            if not name.startswith("_") and isinstance(getattr(self, name), str):

                items.update({name: str(getattr(self, name))})

        return items


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Register:

    def __init__(self):
        self.renderfuncs: Renderfuncs = {}
        self.is_muted = False
        self.eightbit_call = lambda x: x
        self.rgb_call = lambda r, g, b: (r, g, b)

    def as_namedtuple(self):
        """
        Export color register as namedtuple.
        """
        d = self.as_dict()
        return namedtuple("StyleRegister", d.keys())(*d.values())


from collections import namedtuple
from copy import deepcopy
from typing import Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from .rendertype import RenderType

Renderfuncs = Dict[Type[RenderType], Callable]
StylingRule = Union["Style", RenderType]

class Register:

    def __init__(self):
        self.renderfuncs: Renderfuncs = {}
        self.is_muted = False
        self.eightbit_call = lambda x: x
        self.rgb_call = lambda r, g, b: (r, g, b)

    def copy(self) -> "Register":
        """
        Make a deepcopy of a register-object.
        """
        return deepcopy(self)


import sys
from argparse import ArgumentParser, SUPPRESS
from .const import ARGUMENT_PLACEHOLDER
from .utils import get_alias

class Parser(object):

    def __init__(self):
        self._parser = ArgumentParser(prog='thefuck', add_help=False)
        self._add_arguments()


import sys
from argparse import ArgumentParser, SUPPRESS
from .const import ARGUMENT_PLACEHOLDER
from .utils import get_alias

class Parser(object):

    def __init__(self):
        self._parser = ArgumentParser(prog='thefuck', add_help=False)
        self._add_arguments()

    def parse(self, argv):
        arguments = self._prepare_arguments(argv[1:])
        return self._parser.parse_args(arguments)


import sys
from argparse import ArgumentParser, SUPPRESS
from .const import ARGUMENT_PLACEHOLDER
from .utils import get_alias

class Parser(object):

    def __init__(self):
        self._parser = ArgumentParser(prog='thefuck', add_help=False)
        self._add_arguments()

    def print_usage(self):
        self._parser.print_usage(sys.stderr)


import sys
from argparse import ArgumentParser, SUPPRESS
from .const import ARGUMENT_PLACEHOLDER
from .utils import get_alias

class Parser(object):

    def __init__(self):
        self._parser = ArgumentParser(prog='thefuck', add_help=False)
        self._add_arguments()

    def print_help(self):
        self._parser.print_help(sys.stderr)


from imp import load_source
import os
import sys
from warnings import warn
from six import text_type
from . import const
from .system import Path

settings = Settings(const.DEFAULT_SETTINGS)

class Settings(dict):

    def init(self, args=None):
        """Fills `settings` with values from `settings.py` and env."""
        from .logs import exception

        self._setup_user_dir()
        self._init_settings_file()

        try:
            self.update(self._settings_from_file())
        except Exception:
            exception("Can't load settings from file", sys.exc_info())

        try:
            self.update(self._settings_from_env())
        except Exception:
            exception("Can't load settings from env", sys.exc_info())

        self.update(self._settings_from_args(args))


import sys
from .conf import settings
from .types import Rule
from .system import Path
from . import logs

def get_loaded_rules(rules_paths):
    """Yields all available rules.

    :type rules_paths: [Path]
    :rtype: Iterable[Rule]

    """
    for path in rules_paths:
        if path.name != '__init__.py':
            rule = Rule.from_path(path)
            if rule and rule.is_enabled:
                yield rule


import sys
from .conf import settings
from .types import Rule
from .system import Path
from . import logs

def get_rules_import_paths():
    """Yields all rules import paths.

    :rtype: Iterable[Path]

    """
    # Bundled rules:
    yield Path(__file__).parent.joinpath('rules')
    # Rules defined by user:
    yield settings.user_dir.joinpath('rules')
    # Packages with third-party rules:
    for path in sys.path:
        for contrib_module in Path(path).glob('thefuck_contrib_*'):
            contrib_rules = contrib_module.joinpath('rules')
            if contrib_rules.is_dir():
                yield contrib_rules


import sys
from .conf import settings
from .types import Rule
from .system import Path
from . import logs

def get_rules():
    """Returns all enabled rules.

    :rtype: [Rule]

    """
    paths = [rule_path for path in get_rules_import_paths()
             for rule_path in sorted(path.glob('*.py'))]
    return sorted(get_loaded_rules(paths),
                  key=lambda rule: rule.priority)


import sys
from .conf import settings
from .types import Rule
from .system import Path
from . import logs

def organize_commands(corrected_commands):
    """Yields sorted commands without duplicates.

    :type corrected_commands: Iterable[thefuck.types.CorrectedCommand]
    :rtype: Iterable[thefuck.types.CorrectedCommand]

    """
    try:
        first_command = next(corrected_commands)
        yield first_command
    except StopIteration:
        return

    without_duplicates = {
        command for command in sorted(
            corrected_commands, key=lambda command: command.priority)
        if command != first_command}

    sorted_commands = sorted(
        without_duplicates,
        key=lambda corrected_command: corrected_command.priority)

    logs.debug(u'Corrected commands: {}'.format(
        ', '.join(u'{}'.format(cmd) for cmd in [first_command] + sorted_commands)))

    for command in sorted_commands:
        yield command


import sys
from .conf import settings
from .types import Rule
from .system import Path
from . import logs

def get_corrected_commands(command):
    """Returns generator with sorted and unique corrected commands.

    :type command: thefuck.types.Command
    :rtype: Iterable[thefuck.types.CorrectedCommand]

    """
    corrected_commands = (
        corrected for rule in get_rules()
        if rule.is_match(command)
        for corrected in rule.get_corrected_commands(command))
    return organize_commands(corrected_commands)


from pprint import pformat
import os
import sys
from difflib import SequenceMatcher
from .. import logs, types, const
from ..conf import settings
from ..corrector import get_corrected_commands
from ..exceptions import EmptyCommand
from ..ui import select_command
from ..utils import get_alias, get_all_executables

def fix_command(known_args):
    """Fixes previous command. Used when `thefuck` called without arguments."""
    settings.init(known_args)
    with logs.debug_time('Total'):
        logs.debug(u'Run with settings: {}'.format(pformat(settings)))
        raw_command = _get_raw_command(known_args)

        try:
            command = types.Command.from_raw_script(raw_command)
        except EmptyCommand:
            logs.debug('Empty command, nothing to do')
            return

        corrected_commands = get_corrected_commands(command)
        selected_command = select_command(corrected_commands)

        if selected_command:
            selected_command.run(command)
        else:
            sys.exit(1)


from ..system import init_output
import os
import sys
from .. import logs
from ..argument_parser import Parser
from ..utils import get_installation_info
from ..shells import shell
from .alias import print_alias
from .fix_command import fix_command

def main():
    parser = Parser()
    known_args = parser.parse(sys.argv)

    if known_args.help:
        parser.print_help()
    elif known_args.version:
        logs.version(get_installation_info().version,
                     sys.version.split()[0], shell.info())
    # It's important to check if an alias is being requested before checking if
    # `TF_HISTORY` is in `os.environ`, otherwise it might mess with subshells.
    # Check https://github.com/nvbn/thefuck/issues/921 for reference
    elif known_args.alias:
        print_alias(known_args)
    elif known_args.command or 'TF_HISTORY' in os.environ:
        fix_command(known_args)
    elif known_args.shell_logger:
        try:
            from .shell_logger import shell_logger  # noqa: E402
        except ImportError:
            logs.warn('Shell logger supports only Linux and macOS')
        else:
            shell_logger(known_args.shell_logger)
    else:
        parser.print_usage()


import array
import fcntl
from functools import partial
import mmap
import os
import pty
import signal
import sys
import termios
import tty
from .. import logs, const

def shell_logger(output):
    """Logs shell output to the `output`.

    Works like unix script command with `-f` flag.

    """
    if not os.environ.get('SHELL'):
        logs.warn("Shell logger doesn't support your platform.")
        sys.exit(1)

    fd = os.open(output, os.O_CREAT | os.O_TRUNC | os.O_RDWR)
    os.write(fd, b'\x00' * const.LOG_SIZE_IN_BYTES)
    buffer = mmap.mmap(fd, const.LOG_SIZE_IN_BYTES, mmap.MAP_SHARED, mmap.PROT_WRITE)
    return_code = _spawn(os.environ['SHELL'], partial(_read, buffer))

    sys.exit(return_code)


from contextlib import contextmanager
from datetime import datetime
import sys
from traceback import format_exception
import colorama
from .conf import settings
from . import const

def color(color_):
    """Utility for ability to disabling colored output."""
    if settings.no_colors:
        return ''
    else:
        return color_


from contextlib import contextmanager
from datetime import datetime
import sys
from traceback import format_exception
import colorama
from .conf import settings
from . import const

def show_corrected_command(corrected_command):
    sys.stderr.write(u'{prefix}{bold}{script}{reset}{side_effect}\n'.format(
        prefix=const.USER_COMMAND_MARK,
        script=corrected_command.script,
        side_effect=u' (+side effect)' if corrected_command.side_effect else u'',
        bold=color(colorama.Style.BRIGHT),
        reset=color(colorama.Style.RESET_ALL)))


from contextlib import contextmanager
from datetime import datetime
import sys
from traceback import format_exception
import colorama
from .conf import settings
from . import const

def confirm_text(corrected_command):
    sys.stderr.write(
        (u'{prefix}{clear}{bold}{script}{reset}{side_effect} '
         u'[{green}enter{reset}/{blue}↑{reset}/{blue}↓{reset}'
         u'/{red}ctrl+c{reset}]').format(
            prefix=const.USER_COMMAND_MARK,
            script=corrected_command.script,
            side_effect=' (+side effect)' if corrected_command.side_effect else '',
            clear='\033[1K\r',
            bold=color(colorama.Style.BRIGHT),
            green=color(colorama.Fore.GREEN),
            red=color(colorama.Fore.RED),
            reset=color(colorama.Style.RESET_ALL),
            blue=color(colorama.Fore.BLUE)))


from contextlib import contextmanager
from datetime import datetime
import sys
from traceback import format_exception
import colorama
from .conf import settings
from . import const

def debug(msg):
    if settings.debug:
        sys.stderr.write(u'{blue}{bold}DEBUG:{reset} {msg}\n'.format(
            msg=msg,
            reset=color(colorama.Style.RESET_ALL),
            blue=color(colorama.Fore.BLUE),
            bold=color(colorama.Style.BRIGHT)))


from contextlib import contextmanager
from datetime import datetime
import sys
from traceback import format_exception
import colorama
from .conf import settings
from . import const

def how_to_configure_alias(configuration_details):
    print(u"Seems like {bold}fuck{reset} alias isn't configured!".format(
        bold=color(colorama.Style.BRIGHT),
        reset=color(colorama.Style.RESET_ALL)))

    if configuration_details:
        print(
            u"Please put {bold}{content}{reset} in your "
            u"{bold}{path}{reset} and apply "
            u"changes with {bold}{reload}{reset} or restart your shell.".format(
                bold=color(colorama.Style.BRIGHT),
                reset=color(colorama.Style.RESET_ALL),
                **configuration_details._asdict()))

        if configuration_details.can_configure_automatically:
            print(
                u"Or run {bold}fuck{reset} a second time to configure"
                u" it automatically.".format(
                    bold=color(colorama.Style.BRIGHT),
                    reset=color(colorama.Style.RESET_ALL)))

    print(u'More details - https://github.com/nvbn/thefuck#manual-installation')


import re
from thefuck.utils import for_app, replace_argument

INVALID_CHOICE = "(?<=Invalid choice: ')(.*)(?=', maybe you meant:)"
OPTIONS = "^\\s*\\*\\s(.*)"

def get_new_command(command):
    mistake = re.search(INVALID_CHOICE, command.output).group(0)
    options = re.findall(OPTIONS, command.output, flags=re.MULTILINE)
    return [replace_argument(command.script, mistake, o) for o in options]


import os
import re
from thefuck.utils import get_closest, replace_argument
from thefuck.specific.brew import get_brew_path_prefix, brew_available

enabled_by_default = brew_available

def match(command):
    is_proper_command = ('brew install' in command.script and
                         'No available formula' in command.output)

    if is_proper_command:
        formula = re.findall(r'Error: No available formula for ([a-z]+)',
                             command.output)[0]
        return bool(_get_similar_formula(formula))
    return False


import os
import re
from thefuck.utils import get_closest, replace_argument
from thefuck.specific.brew import get_brew_path_prefix, brew_available

enabled_by_default = brew_available

def get_new_command(command):
    not_exist_formula = re.findall(r'Error: No available formula for ([a-z]+)',
                                   command.output)[0]
    exist_formula = _get_similar_formula(not_exist_formula)

    return replace_argument(command.script, not_exist_formula, exist_formula)


from thefuck.utils import for_app, which

enabled_by_default = bool(which("choco")) or bool(which("cinst"))

def get_new_command(command):
    # Find the argument that is the package name
    for script_part in command.script_parts:
        if (
            script_part not in ["choco", "cinst", "install"]
            # Need exact match (bc chocolatey is a package)
            and not script_part.startswith('-')
            # Leading hyphens are parameters; some packages contain them though
            and '=' not in script_part and '/' not in script_part
            # These are certainly parameters
        ):
            return command.script.replace(script_part, script_part + ".install")
    return []


import os
import zipfile
from thefuck.utils import for_app
from thefuck.shells import shell

requires_output = False

def side_effect(old_cmd, command):
    with zipfile.ZipFile(_zip_file(old_cmd), 'r') as archive:
        for file in archive.namelist():
            if not os.path.abspath(file).startswith(os.getcwd()):
                # it's unsafe to overwrite files outside of the current directory
                continue

            try:
                os.remove(file)
            except OSError:
                # does not try to remove directories as we cannot know if they
                # already existed before
                pass


def match(command):
    return 'manage.py' in command.script and \
           'migrate' in command.script \
           and '--merge: will just attempt the migration' in command.output


import re
from thefuck.shells import shell

patterns = (
    r"mv: cannot move '[^']*' to '([^']*)': No such file or directory",
    r"mv: cannot move '[^']*' to '([^']*)': Not a directory",
    r"cp: cannot create regular file '([^']*)': No such file or directory",
    r"cp: cannot create regular file '([^']*)': Not a directory",
)

def match(command):
    for pattern in patterns:
        if re.search(pattern, command.output):
            return True

    return False


import re
from thefuck.shells import shell

patterns = (
    r"mv: cannot move '[^']*' to '([^']*)': No such file or directory",
    r"mv: cannot move '[^']*' to '([^']*)': Not a directory",
    r"cp: cannot create regular file '([^']*)': No such file or directory",
    r"cp: cannot create regular file '([^']*)': Not a directory",
)

def get_new_command(command):
    for pattern in patterns:
        file = re.findall(pattern, command.output)

        if file:
            file = file[0]
            dir = file[0:file.rfind('/')]

            formatme = shell.and_('mkdir -p {}', '{}')
            return formatme.format(dir, command.script)


from thefuck.specific.archlinux import archlinux_env
from thefuck.specific.sudo import sudo_support
from thefuck.utils import for_app
import re

enabled_by_default = archlinux_env()

def get_new_command(command):
    option = re.findall(r" -[dfqrstuv]", command.script)[0]
    return re.sub(option, option.upper(), command.script)


import re
from thefuck.utils import for_app, which, replace_argument

def get_new_command(command):
    command_name = _get_command_name(command)
    return replace_argument(command.script, command_name,
                            u'env "PATH=$PATH" {}'.format(command_name))


import re
from thefuck.utils import get_all_matched_commands, replace_command, for_app

def get_new_command(command):
    broken_cmd = re.findall(r'tsuru: "([^"]*)" is not a tsuru command',
                            command.output)[0]
    return replace_command(command, broken_cmd,
                           get_all_matched_commands(command.output))


from thefuck.shells import shell
from thefuck.utils import for_app

def get_new_command(command):
    cmds = command.script_parts
    machine = None
    if len(cmds) >= 3:
        machine = cmds[2]

    start_all_instances = shell.and_(u"vagrant up", command.script)
    if machine is None:
        return start_all_instances
    else:
        return [shell.and_(u"vagrant up {}".format(machine), command.script),
                start_all_instances]


import os
import sys
import tty
import termios
import colorama
from distutils.spawn import find_executable
from .. import const

init_output = colorama.init

def getch():
    fd = sys.stdin.fileno()
    old = termios.tcgetattr(fd)
    try:
        tty.setraw(fd)
        return sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old)


import os
import sys
import tty
import termios
import colorama
from distutils.spawn import find_executable
from .. import const

init_output = colorama.init

def get_key():
    ch = getch()

    if ch in const.KEY_MAPPING:
        return const.KEY_MAPPING[ch]
    elif ch == '\x1b':
        next_ch = getch()
        if next_ch == '[':
            last_ch = getch()

            if last_ch == 'A':
                return const.KEY_UP
            elif last_ch == 'B':
                return const.KEY_DOWN

    return ch


import os
import sys
import tty
import termios
import colorama
from distutils.spawn import find_executable
from .. import const

init_output = colorama.init

def open_command(arg):
    if find_executable('xdg-open'):
        return 'xdg-open ' + arg
    return 'open ' + arg


from imp import load_source
import os
import sys
from . import logs
from .shells import shell
from .conf import settings
from .const import DEFAULT_PRIORITY, ALL_ENABLED
from .exceptions import EmptyCommand
from .utils import get_alias, format_raw_script
from .output_readers import get_output

class Command(object):

    def __init__(self, script, output):
        """Initializes command with given values.

        :type script: basestring
        :type output: basestring

        """
        self.script = script
        self.output = output

    def __eq__(self, other):
        if isinstance(other, Command):
            return (self.script, self.output) == (other.script, other.output)
        else:
            return False


from imp import load_source
import os
import sys
from . import logs
from .shells import shell
from .conf import settings
from .const import DEFAULT_PRIORITY, ALL_ENABLED
from .exceptions import EmptyCommand
from .utils import get_alias, format_raw_script
from .output_readers import get_output

class Rule(object):

    def __init__(self, name, match, get_new_command,
                 enabled_by_default, side_effect,
                 priority, requires_output):
        """Initializes rule with given fields.

        :type name: basestring
        :type match: (Command) -> bool
        :type get_new_command: (Command) -> (basestring | [basestring])
        :type enabled_by_default: boolean
        :type side_effect: (Command, basestring) -> None
        :type priority: int
        :type requires_output: bool

        """
        self.name = name
        self.match = match
        self.get_new_command = get_new_command
        self.enabled_by_default = enabled_by_default
        self.side_effect = side_effect
        self.priority = priority
        self.requires_output = requires_output

    def __eq__(self, other):
        if isinstance(other, Rule):
            return ((self.name, self.match, self.get_new_command,
                     self.enabled_by_default, self.side_effect,
                     self.priority, self.requires_output)
                    == (other.name, other.match, other.get_new_command,
                        other.enabled_by_default, other.side_effect,
                        other.priority, other.requires_output))
        else:
            return False


from imp import load_source
import os
import sys
from . import logs
from .shells import shell
from .conf import settings
from .const import DEFAULT_PRIORITY, ALL_ENABLED
from .exceptions import EmptyCommand
from .utils import get_alias, format_raw_script
from .output_readers import get_output

class Command(object):

    def __init__(self, script, output):
        """Initializes command with given values.

        :type script: basestring
        :type output: basestring

        """
        self.script = script
        self.output = output

class Rule(object):

    def __init__(self, name, match, get_new_command,
                 enabled_by_default, side_effect,
                 priority, requires_output):
        """Initializes rule with given fields.

        :type name: basestring
        :type match: (Command) -> bool
        :type get_new_command: (Command) -> (basestring | [basestring])
        :type enabled_by_default: boolean
        :type side_effect: (Command, basestring) -> None
        :type priority: int
        :type requires_output: bool

        """
        self.name = name
        self.match = match
        self.get_new_command = get_new_command
        self.enabled_by_default = enabled_by_default
        self.side_effect = side_effect
        self.priority = priority
        self.requires_output = requires_output

    def is_match(self, command):
        """Returns `True` if rule matches the command.

        :type command: Command
        :rtype: bool

        """
        if command.output is None and self.requires_output:
            return False

        try:
            with logs.debug_time(u'Trying rule: {};'.format(self.name)):
                if self.match(command):
                    return True
        except Exception:
            logs.rule_failed(self, sys.exc_info())


from imp import load_source
import os
import sys
from . import logs
from .shells import shell
from .conf import settings
from .const import DEFAULT_PRIORITY, ALL_ENABLED
from .exceptions import EmptyCommand
from .utils import get_alias, format_raw_script
from .output_readers import get_output

class Command(object):

    def __init__(self, script, output):
        """Initializes command with given values.

        :type script: basestring
        :type output: basestring

        """
        self.script = script
        self.output = output

class CorrectedCommand(object):

    def __init__(self, script, side_effect, priority):
        """Initializes instance with given fields.

        :type script: basestring
        :type side_effect: (Command, basestring) -> None
        :type priority: int

        """
        self.script = script
        self.side_effect = side_effect
        self.priority = priority

class Rule(object):

    def __init__(self, name, match, get_new_command,
                 enabled_by_default, side_effect,
                 priority, requires_output):
        """Initializes rule with given fields.

        :type name: basestring
        :type match: (Command) -> bool
        :type get_new_command: (Command) -> (basestring | [basestring])
        :type enabled_by_default: boolean
        :type side_effect: (Command, basestring) -> None
        :type priority: int
        :type requires_output: bool

        """
        self.name = name
        self.match = match
        self.get_new_command = get_new_command
        self.enabled_by_default = enabled_by_default
        self.side_effect = side_effect
        self.priority = priority
        self.requires_output = requires_output

    def get_corrected_commands(self, command):
        """Returns generator with corrected commands.

        :type command: Command
        :rtype: Iterable[CorrectedCommand]

        """
        new_commands = self.get_new_command(command)
        if not isinstance(new_commands, list):
            new_commands = (new_commands,)
        for n, new_command in enumerate(new_commands):
            yield CorrectedCommand(script=new_command,
                                   side_effect=self.side_effect,
                                   priority=(n + 1) * self.priority)


from imp import load_source
import os
import sys
from . import logs
from .shells import shell
from .conf import settings
from .const import DEFAULT_PRIORITY, ALL_ENABLED
from .exceptions import EmptyCommand
from .utils import get_alias, format_raw_script
from .output_readers import get_output

class Command(object):

    def __init__(self, script, output):
        """Initializes command with given values.

        :type script: basestring
        :type output: basestring

        """
        self.script = script
        self.output = output

class CorrectedCommand(object):

    def __init__(self, script, side_effect, priority):
        """Initializes instance with given fields.

        :type script: basestring
        :type side_effect: (Command, basestring) -> None
        :type priority: int

        """
        self.script = script
        self.side_effect = side_effect
        self.priority = priority

    def __eq__(self, other):
        """Ignores `priority` field."""
        if isinstance(other, CorrectedCommand):
            return (other.script, other.side_effect) == \
                   (self.script, self.side_effect)
        else:
            return False


from imp import load_source
import os
import sys
from . import logs
from .shells import shell
from .conf import settings
from .const import DEFAULT_PRIORITY, ALL_ENABLED
from .exceptions import EmptyCommand
from .utils import get_alias, format_raw_script
from .output_readers import get_output

class Command(object):

    def __init__(self, script, output):
        """Initializes command with given values.

        :type script: basestring
        :type output: basestring

        """
        self.script = script
        self.output = output

class CorrectedCommand(object):

    def __init__(self, script, side_effect, priority):
        """Initializes instance with given fields.

        :type script: basestring
        :type side_effect: (Command, basestring) -> None
        :type priority: int

        """
        self.script = script
        self.side_effect = side_effect
        self.priority = priority

    def run(self, old_cmd):
        """Runs command from rule for passed command.

        :type old_cmd: Command

        """
        if self.side_effect:
            self.side_effect(old_cmd, self.script)
        if settings.alter_history:
            shell.put_to_history(self.script)
        # This depends on correct setting of PYTHONIOENCODING by the alias:
        logs.debug(u'PYTHONIOENCODING: {}'.format(
            os.environ.get('PYTHONIOENCODING', '!!not-set!!')))

        sys.stdout.write(self._get_script())


import logging
from typing import List, Dict

logger = logging.getLogger(__name__)

def get_script_completions(source: str, row: int, column: int, filename: str, sys_path=None):
    import jedi

    if _using_older_jedi(jedi):
        try:
            script = jedi.Script(source, row, column, filename, sys_path=sys_path)
        except Exception as e:
            logger.info("Could not get completions with given sys_path", exc_info=e)
            script = jedi.Script(source, row, column, filename)

        completions = script.completions()
    else:
        script = jedi.Script(code=source, path=filename, project=_get_new_jedi_project(sys_path))
        completions = script.complete(line=row, column=column)

    return _tweak_completions(completions)


import logging
from typing import List, Dict

logger = logging.getLogger(__name__)

def get_interpreter_completions(source: str, namespaces: List[Dict], sys_path=None):
    import jedi

    if _using_older_jedi(jedi):
        try:
            interpreter = jedi.Interpreter(source, namespaces, sys_path=sys_path)
        except Exception as e:
            logger.info("Could not get completions with given sys_path", exc_info=e)
            interpreter = jedi.Interpreter(source, namespaces)
    else:
        # NB! Can't send project for Interpreter in 0.18
        # https://github.com/davidhalter/jedi/pull/1734
        interpreter = jedi.Interpreter(source, namespaces)
    if hasattr(interpreter, "completions"):
        # up to jedi 0.17
        return _tweak_completions(interpreter.completions())
    else:
        return _tweak_completions(interpreter.complete())


import logging
from typing import List, Dict

logger = logging.getLogger(__name__)

def get_definitions(source: str, row: int, column: int, filename: str):
    import jedi

    if _using_older_jedi(jedi):
        script = jedi.Script(source, row, column, filename)
        return script.goto_definitions()
    else:
        script = jedi.Script(code=source, path=filename)
        return script.infer(line=row, column=column)


import os
from thonny import get_workbench
from thonny.languages import tr

_OPTION_NAME = "run.pgzero_mode"

def toggle_variable():
    var = get_workbench().get_variable(_OPTION_NAME)
    var.set(not var.get())
    update_environment()


import os
from thonny import get_workbench
from thonny.languages import tr

_OPTION_NAME = "run.pgzero_mode"

def update_environment():
    if get_workbench().in_simple_mode():
        os.environ["PGZERO_MODE"] = "auto"
    else:
        os.environ["PGZERO_MODE"] = str(get_workbench().get_option(_OPTION_NAME))


import os
from thonny import get_workbench
from thonny.languages import tr

_OPTION_NAME = "run.pgzero_mode"

def load_plugin():
    get_workbench().set_default(_OPTION_NAME, False)
    get_workbench().add_command(
        "toggle_pgzero_mode",
        "run",
        tr("Pygame Zero mode"),
        toggle_variable,
        flag_name=_OPTION_NAME,
        group=40,
    )
    update_environment()


import re
import string
from collections.abc import Mapping
from keyword import iskeyword
from typing import Dict

NUM_CONTEXT_LINES = (50, 500, 5000000)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
_synchre = re.compile(
    r"""
    ^
    [ \t]*
    (?: while
    |   else
    |   def
    |   return
    |   assert
    |   break
    |   class
    |   continue
    |   elif
    |   try
    |   except
    |   raise
    |   import
    |   yield
    )
    \b
""",
    re.VERBOSE | re.MULTILINE,
).search
_junkre = re.compile(
    r"""
    [ \t]*
    (?: \# \S .* )?
    \n
""",
    re.VERBOSE,
).match
_match_stringre = re.compile(
    r"""
    \""" [^"\\]* (?:
                     (?: \\. | "(?!"") )
                     [^"\\]*
                 )*
    (?: \""" )?

|   " [^"\\\n]* (?: \\. [^"\\\n]* )* "?

|   ''' [^'\\]* (?:
                   (?: \\. | '(?!'') )
                   [^'\\]*
                )*
    (?: ''' )?

|   ' [^'\\\n]* (?: \\. [^'\\\n]* )* '?
""",
    re.VERBOSE | re.DOTALL,
).match
_itemre = re.compile(
    r"""
    [ \t]*
    [^\s#\\]    # if we match, m.end()-1 is the interesting char
""",
    re.VERBOSE,
).match
_closere = re.compile(
    r"""
    \s*
    (?: return
    |   break
    |   continue
    |   raise
    |   pass
    )
    \b
""",
    re.VERBOSE,
).match
_chew_ordinaryre = re.compile(
    r"""
    [^[\](){}#'"\\]+
""",
    re.VERBOSE,
).match
_ASCII_ID_CHARS = frozenset(string.ascii_letters + string.digits + "_")
_ASCII_ID_FIRST_CHARS = frozenset(string.ascii_letters + "_")
_IS_ASCII_ID_CHAR = [(chr(x) in _ASCII_ID_CHARS) for x in range(128)]
_IS_ASCII_ID_FIRST_CHAR = [(chr(x) in _ASCII_ID_FIRST_CHARS) for x in range(128)]

class StringTranslatePseudoMapping(Mapping):

    def __init__(self, non_defaults, default_value):
        self._non_defaults = non_defaults
        self._default_value = default_value

        def _get(key, _get=non_defaults.get, _default=default_value):
            return _get(key, _default)

        self._get = _get

    def __getitem__(self, item):
        return self._get(item)


import re
import string
from collections.abc import Mapping
from keyword import iskeyword
from typing import Dict

NUM_CONTEXT_LINES = (50, 500, 5000000)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
_synchre = re.compile(
    r"""
    ^
    [ \t]*
    (?: while
    |   else
    |   def
    |   return
    |   assert
    |   break
    |   class
    |   continue
    |   elif
    |   try
    |   except
    |   raise
    |   import
    |   yield
    )
    \b
""",
    re.VERBOSE | re.MULTILINE,
).search
_junkre = re.compile(
    r"""
    [ \t]*
    (?: \# \S .* )?
    \n
""",
    re.VERBOSE,
).match
_match_stringre = re.compile(
    r"""
    \""" [^"\\]* (?:
                     (?: \\. | "(?!"") )
                     [^"\\]*
                 )*
    (?: \""" )?

|   " [^"\\\n]* (?: \\. [^"\\\n]* )* "?

|   ''' [^'\\]* (?:
                   (?: \\. | '(?!'') )
                   [^'\\]*
                )*
    (?: ''' )?

|   ' [^'\\\n]* (?: \\. [^'\\\n]* )* '?
""",
    re.VERBOSE | re.DOTALL,
).match
_itemre = re.compile(
    r"""
    [ \t]*
    [^\s#\\]    # if we match, m.end()-1 is the interesting char
""",
    re.VERBOSE,
).match
_closere = re.compile(
    r"""
    \s*
    (?: return
    |   break
    |   continue
    |   raise
    |   pass
    )
    \b
""",
    re.VERBOSE,
).match
_chew_ordinaryre = re.compile(
    r"""
    [^[\](){}#'"\\]+
""",
    re.VERBOSE,
).match
_ASCII_ID_CHARS = frozenset(string.ascii_letters + string.digits + "_")
_ASCII_ID_FIRST_CHARS = frozenset(string.ascii_letters + "_")
_IS_ASCII_ID_CHAR = [(chr(x) in _ASCII_ID_CHARS) for x in range(128)]
_IS_ASCII_ID_FIRST_CHAR = [(chr(x) in _ASCII_ID_FIRST_CHARS) for x in range(128)]

class StringTranslatePseudoMapping(Mapping):

    def __init__(self, non_defaults, default_value):
        self._non_defaults = non_defaults
        self._default_value = default_value

        def _get(key, _get=non_defaults.get, _default=default_value):
            return _get(key, _default)

        self._get = _get

    def __len__(self):
        return len(self._non_defaults)


import re
import string
from collections.abc import Mapping
from keyword import iskeyword
from typing import Dict

NUM_CONTEXT_LINES = (50, 500, 5000000)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
_synchre = re.compile(
    r"""
    ^
    [ \t]*
    (?: while
    |   else
    |   def
    |   return
    |   assert
    |   break
    |   class
    |   continue
    |   elif
    |   try
    |   except
    |   raise
    |   import
    |   yield
    )
    \b
""",
    re.VERBOSE | re.MULTILINE,
).search
_junkre = re.compile(
    r"""
    [ \t]*
    (?: \# \S .* )?
    \n
""",
    re.VERBOSE,
).match
_match_stringre = re.compile(
    r"""
    \""" [^"\\]* (?:
                     (?: \\. | "(?!"") )
                     [^"\\]*
                 )*
    (?: \""" )?

|   " [^"\\\n]* (?: \\. [^"\\\n]* )* "?

|   ''' [^'\\]* (?:
                   (?: \\. | '(?!'') )
                   [^'\\]*
                )*
    (?: ''' )?

|   ' [^'\\\n]* (?: \\. [^'\\\n]* )* '?
""",
    re.VERBOSE | re.DOTALL,
).match
_itemre = re.compile(
    r"""
    [ \t]*
    [^\s#\\]    # if we match, m.end()-1 is the interesting char
""",
    re.VERBOSE,
).match
_closere = re.compile(
    r"""
    \s*
    (?: return
    |   break
    |   continue
    |   raise
    |   pass
    )
    \b
""",
    re.VERBOSE,
).match
_chew_ordinaryre = re.compile(
    r"""
    [^[\](){}#'"\\]+
""",
    re.VERBOSE,
).match
_ASCII_ID_CHARS = frozenset(string.ascii_letters + string.digits + "_")
_ASCII_ID_FIRST_CHARS = frozenset(string.ascii_letters + "_")
_IS_ASCII_ID_CHAR = [(chr(x) in _ASCII_ID_CHARS) for x in range(128)]
_IS_ASCII_ID_FIRST_CHAR = [(chr(x) in _ASCII_ID_FIRST_CHARS) for x in range(128)]

class StringTranslatePseudoMapping(Mapping):

    def __init__(self, non_defaults, default_value):
        self._non_defaults = non_defaults
        self._default_value = default_value

        def _get(key, _get=non_defaults.get, _default=default_value):
            return _get(key, _default)

        self._get = _get

    def __iter__(self):
        return iter(self._non_defaults)


import re
import string
from collections.abc import Mapping
from keyword import iskeyword
from typing import Dict

NUM_CONTEXT_LINES = (50, 500, 5000000)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
_synchre = re.compile(
    r"""
    ^
    [ \t]*
    (?: while
    |   else
    |   def
    |   return
    |   assert
    |   break
    |   class
    |   continue
    |   elif
    |   try
    |   except
    |   raise
    |   import
    |   yield
    )
    \b
""",
    re.VERBOSE | re.MULTILINE,
).search
_junkre = re.compile(
    r"""
    [ \t]*
    (?: \# \S .* )?
    \n
""",
    re.VERBOSE,
).match
_match_stringre = re.compile(
    r"""
    \""" [^"\\]* (?:
                     (?: \\. | "(?!"") )
                     [^"\\]*
                 )*
    (?: \""" )?

|   " [^"\\\n]* (?: \\. [^"\\\n]* )* "?

|   ''' [^'\\]* (?:
                   (?: \\. | '(?!'') )
                   [^'\\]*
                )*
    (?: ''' )?

|   ' [^'\\\n]* (?: \\. [^'\\\n]* )* '?
""",
    re.VERBOSE | re.DOTALL,
).match
_itemre = re.compile(
    r"""
    [ \t]*
    [^\s#\\]    # if we match, m.end()-1 is the interesting char
""",
    re.VERBOSE,
).match
_closere = re.compile(
    r"""
    \s*
    (?: return
    |   break
    |   continue
    |   raise
    |   pass
    )
    \b
""",
    re.VERBOSE,
).match
_chew_ordinaryre = re.compile(
    r"""
    [^[\](){}#'"\\]+
""",
    re.VERBOSE,
).match
_ASCII_ID_CHARS = frozenset(string.ascii_letters + string.digits + "_")
_ASCII_ID_FIRST_CHARS = frozenset(string.ascii_letters + "_")
_IS_ASCII_ID_CHAR = [(chr(x) in _ASCII_ID_CHARS) for x in range(128)]
_IS_ASCII_ID_FIRST_CHAR = [(chr(x) in _ASCII_ID_FIRST_CHARS) for x in range(128)]

class StringTranslatePseudoMapping(Mapping):

    def __init__(self, non_defaults, default_value):
        self._non_defaults = non_defaults
        self._default_value = default_value

        def _get(key, _get=non_defaults.get, _default=default_value):
            return _get(key, _default)

        self._get = _get

    def get(self, key, default=None):
        return self._get(key)


import re
import string
from collections.abc import Mapping
from keyword import iskeyword
from typing import Dict

NUM_CONTEXT_LINES = (50, 500, 5000000)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
_synchre = re.compile(
    r"""
    ^
    [ \t]*
    (?: while
    |   else
    |   def
    |   return
    |   assert
    |   break
    |   class
    |   continue
    |   elif
    |   try
    |   except
    |   raise
    |   import
    |   yield
    )
    \b
""",
    re.VERBOSE | re.MULTILINE,
).search
_junkre = re.compile(
    r"""
    [ \t]*
    (?: \# \S .* )?
    \n
""",
    re.VERBOSE,
).match
_match_stringre = re.compile(
    r"""
    \""" [^"\\]* (?:
                     (?: \\. | "(?!"") )
                     [^"\\]*
                 )*
    (?: \""" )?

|   " [^"\\\n]* (?: \\. [^"\\\n]* )* "?

|   ''' [^'\\]* (?:
                   (?: \\. | '(?!'') )
                   [^'\\]*
                )*
    (?: ''' )?

|   ' [^'\\\n]* (?: \\. [^'\\\n]* )* '?
""",
    re.VERBOSE | re.DOTALL,
).match
_itemre = re.compile(
    r"""
    [ \t]*
    [^\s#\\]    # if we match, m.end()-1 is the interesting char
""",
    re.VERBOSE,
).match
_closere = re.compile(
    r"""
    \s*
    (?: return
    |   break
    |   continue
    |   raise
    |   pass
    )
    \b
""",
    re.VERBOSE,
).match
_chew_ordinaryre = re.compile(
    r"""
    [^[\](){}#'"\\]+
""",
    re.VERBOSE,
).match
_ASCII_ID_CHARS = frozenset(string.ascii_letters + string.digits + "_")
_ASCII_ID_FIRST_CHARS = frozenset(string.ascii_letters + "_")
_IS_ASCII_ID_CHAR = [(chr(x) in _ASCII_ID_CHARS) for x in range(128)]
_IS_ASCII_ID_FIRST_CHAR = [(chr(x) in _ASCII_ID_FIRST_CHARS) for x in range(128)]

class RoughParser:

    _tran1 = {}

    _tran = StringTranslatePseudoMapping(_tran1, default_value=ord("x"))

    lastopenbracketpos = None

    stmt_bracketing = None

    def __init__(self, indent_width, tabwidth):
        self.indent_width = indent_width
        self.tabwidth = tabwidth

    def set_str(self, s):
        assert len(s) == 0 or s[-1] == "\n"
        self.str = s
        self.study_level = 0


import re
import string
from collections.abc import Mapping
from keyword import iskeyword
from typing import Dict

NUM_CONTEXT_LINES = (50, 500, 5000000)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
_synchre = re.compile(
    r"""
    ^
    [ \t]*
    (?: while
    |   else
    |   def
    |   return
    |   assert
    |   break
    |   class
    |   continue
    |   elif
    |   try
    |   except
    |   raise
    |   import
    |   yield
    )
    \b
""",
    re.VERBOSE | re.MULTILINE,
).search
_junkre = re.compile(
    r"""
    [ \t]*
    (?: \# \S .* )?
    \n
""",
    re.VERBOSE,
).match
_match_stringre = re.compile(
    r"""
    \""" [^"\\]* (?:
                     (?: \\. | "(?!"") )
                     [^"\\]*
                 )*
    (?: \""" )?

|   " [^"\\\n]* (?: \\. [^"\\\n]* )* "?

|   ''' [^'\\]* (?:
                   (?: \\. | '(?!'') )
                   [^'\\]*
                )*
    (?: ''' )?

|   ' [^'\\\n]* (?: \\. [^'\\\n]* )* '?
""",
    re.VERBOSE | re.DOTALL,
).match
_itemre = re.compile(
    r"""
    [ \t]*
    [^\s#\\]    # if we match, m.end()-1 is the interesting char
""",
    re.VERBOSE,
).match
_closere = re.compile(
    r"""
    \s*
    (?: return
    |   break
    |   continue
    |   raise
    |   pass
    )
    \b
""",
    re.VERBOSE,
).match
_chew_ordinaryre = re.compile(
    r"""
    [^[\](){}#'"\\]+
""",
    re.VERBOSE,
).match
_ASCII_ID_CHARS = frozenset(string.ascii_letters + string.digits + "_")
_ASCII_ID_FIRST_CHARS = frozenset(string.ascii_letters + "_")
_IS_ASCII_ID_CHAR = [(chr(x) in _ASCII_ID_CHARS) for x in range(128)]
_IS_ASCII_ID_FIRST_CHAR = [(chr(x) in _ASCII_ID_FIRST_CHARS) for x in range(128)]

class RoughParser:

    _tran1 = {}

    _tran = StringTranslatePseudoMapping(_tran1, default_value=ord("x"))

    lastopenbracketpos = None

    stmt_bracketing = None

    def __init__(self, indent_width, tabwidth):
        self.indent_width = indent_width
        self.tabwidth = tabwidth

    def find_good_parse_start(self, is_char_in_string=None, _synchre=_synchre):
        # pylint: disable=redefined-builtin

        str, pos = self.str, None  # @ReservedAssignment

        if not is_char_in_string:
            # no clue -- make the caller pass everything
            return None

        # Peek back from the end for a good place to start,
        # but don't try too often; pos will be left None, or
        # bumped to a legitimate synch point.
        limit = len(str)
        for _ in range(5):
            i = str.rfind(":\n", 0, limit)
            if i < 0:
                break
            i = str.rfind("\n", 0, i) + 1  # start of colon line
            m = _synchre(str, i, limit)
            if m and not is_char_in_string(m.start()):
                pos = m.start()
                break
            limit = i
        if pos is None:
            # Nothing looks like a block-opener, or stuff does
            # but is_char_in_string keeps returning true; most likely
            # we're in or near a giant string, the colorizer hasn't
            # caught up enough to be helpful, or there simply *aren't*
            # any interesting stmts.  In any of these cases we're
            # going to have to parse the whole thing to be sure, so
            # give it one last try from the start, but stop wasting
            # time here regardless of the outcome.
            m = _synchre(str)
            if m and not is_char_in_string(m.start()):
                pos = m.start()
            return pos

        # Peeking back worked; look forward until _synchre no longer
        # matches.
        i = pos + 1
        while 1:
            m = _synchre(str, i)
            if m:
                s, i = m.span()
                if not is_char_in_string(s):
                    pos = s
            else:
                break
        return pos


import re
import string
from collections.abc import Mapping
from keyword import iskeyword
from typing import Dict

NUM_CONTEXT_LINES = (50, 500, 5000000)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
_synchre = re.compile(
    r"""
    ^
    [ \t]*
    (?: while
    |   else
    |   def
    |   return
    |   assert
    |   break
    |   class
    |   continue
    |   elif
    |   try
    |   except
    |   raise
    |   import
    |   yield
    )
    \b
""",
    re.VERBOSE | re.MULTILINE,
).search
_junkre = re.compile(
    r"""
    [ \t]*
    (?: \# \S .* )?
    \n
""",
    re.VERBOSE,
).match
_match_stringre = re.compile(
    r"""
    \""" [^"\\]* (?:
                     (?: \\. | "(?!"") )
                     [^"\\]*
                 )*
    (?: \""" )?

|   " [^"\\\n]* (?: \\. [^"\\\n]* )* "?

|   ''' [^'\\]* (?:
                   (?: \\. | '(?!'') )
                   [^'\\]*
                )*
    (?: ''' )?

|   ' [^'\\\n]* (?: \\. [^'\\\n]* )* '?
""",
    re.VERBOSE | re.DOTALL,
).match
_itemre = re.compile(
    r"""
    [ \t]*
    [^\s#\\]    # if we match, m.end()-1 is the interesting char
""",
    re.VERBOSE,
).match
_closere = re.compile(
    r"""
    \s*
    (?: return
    |   break
    |   continue
    |   raise
    |   pass
    )
    \b
""",
    re.VERBOSE,
).match
_chew_ordinaryre = re.compile(
    r"""
    [^[\](){}#'"\\]+
""",
    re.VERBOSE,
).match
_ASCII_ID_CHARS = frozenset(string.ascii_letters + string.digits + "_")
_ASCII_ID_FIRST_CHARS = frozenset(string.ascii_letters + "_")
_IS_ASCII_ID_CHAR = [(chr(x) in _ASCII_ID_CHARS) for x in range(128)]
_IS_ASCII_ID_FIRST_CHAR = [(chr(x) in _ASCII_ID_FIRST_CHARS) for x in range(128)]

class RoughParser:

    _tran1 = {}

    _tran = StringTranslatePseudoMapping(_tran1, default_value=ord("x"))

    lastopenbracketpos = None

    stmt_bracketing = None

    def __init__(self, indent_width, tabwidth):
        self.indent_width = indent_width
        self.tabwidth = tabwidth

    def set_lo(self, lo):
        assert lo == 0 or self.str[lo - 1] == "\n"
        if lo > 0:
            self.str = self.str[lo:]


import re
import string
from collections.abc import Mapping
from keyword import iskeyword
from typing import Dict

NUM_CONTEXT_LINES = (50, 500, 5000000)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE, C_STRING_NEXT_LINES, C_BRACKET) = range(5)
_synchre = re.compile(
    r"""
    ^
    [ \t]*
    (?: while
    |   else
    |   def
    |   return
    |   assert
    |   break
    |   class
    |   continue
    |   elif
    |   try
    |   except
    |   raise
    |   import
    |   yield
    )
    \b
""",
    re.VERBOSE | re.MULTILINE,
).search
_junkre = re.compile(
    r"""
    [ \t]*
    (?: \# \S .* )?
    \n
""",
    re.VERBOSE,
).match
_match_stringre = re.compile(
    r"""
    \""" [^"\\]* (?:
                     (?: \\. | "(?!"") )
                     [^"\\]*
                 )*
    (?: \""" )?

|   " [^"\\\n]* (?: \\. [^"\\\n]* )* "?

|   ''' [^'\\]* (?:
                   (?: \\. | '(?!'') )
                   [^'\\]*
                )*
    (?: ''' )?

|   ' [^'\\\n]* (?: \\. [^'\\\n]* )* '?
""",
    re.VERBOSE | re.DOTALL,
).match
_itemre = re.compile(
    r"""
    [ \t]*
    [^\s#\\]    # if we match, m.end()-1 is the interesting char
""",
    re.VERBOSE,
).match
_closere = re.compile(
    r"""
    \s*
    (?: return
    |   break
    |   continue
    |   raise
    |   pass
    )
    \b
""",
    re.VERBOSE,
).match
_chew_ordinaryre = re.compile(
    r"""
    [^[\](){}#'"\\]+
""",
    re.VERBOSE,
).match
_ASCII_ID_CHARS = frozenset(string.ascii_letters + string.digits + "_")
_ASCII_ID_FIRST_CHARS = frozenset(string.ascii_letters + "_")
_IS_ASCII_ID_CHAR = [(chr(x) in _ASCII_ID_CHARS) for x in range(128)]
_IS_ASCII_ID_FIRST_CHAR = [(chr(x) in _ASCII_ID_FIRST_CHARS) for x in range(128)]

class RoughParser:

    _tran1 = {}

    _tran = StringTranslatePseudoMapping(_tran1, default_value=ord("x"))

    lastopenbracketpos = None

    stmt_bracketing = None

    def __init__(self, indent_width, tabwidth):
        self.indent_width = indent_width
        self.tabwidth = tabwidth

    def get_continuation_type(self):
        self._study1()
        return self.continuation