# Path: snowballing/collection_helpers.py
# def callable_get(collection, key, default=None, args=[]):
#     """Get item from collection. Return collection applied to args, if it is callable"""
#     result = collection.get(key, default)
#     if callable(result):
#         return result(*args)
#     return result
# 
# def setitem(info, key, value):
#     """Set item in dict info if value is not None 
# 
#     Doctest:
# 
#     .. doctest::
# 
#         >>> info = {}
#         >>> setitem(info, 'def', 2)
#         >>> info
#         {'def': 2}
#         >>> setitem(info, 'abc', None)
#         >>> info
#         {'def': 2}
#     """
#     if value is not None:
#         info[key] = value
# 
# def consume(info, key):
#     """Consumes key from dict
# 
#     Arguments:
# 
#     * `info` -- dict
#     * `key` -- key
# 
#     Doctest:
# 
#     .. doctest::
# 
#         >>> info = {'abc': 1, 'def': 2}
#         >>> consume(info, 'abc')
#         1
#         >>> info
#         {'def': 2}
#         >>> consume(info, 'abc') is None
#         True
#     """
#     if key not in info:
#         return None
#     result = info[key]
#     del info[key]
#     return result
# 
# Path: snowballing/utils.py
# def match_any(string, regexes):
#     """Check if string matches any regex in list
# 
#     Doctest:
# 
#     .. doctest::
# 
#         >>> match_any("a", ["b", "c"])
#         False
#         >>> match_any("a", ["b", "c", "a"])
#         True
#         >>> match_any("_a", ["b", "c", "a"])
#         False
#         >>> match_any("_a", ["b", "c", "a", "_.*"])
#         True
#     """
#     if len(regexes) >= 100:
#         return any(re.match(regex + "$", string) for regex in regexes)
#     else:
#         combined = "({})".format(")|(".join(regex + "$" for regex in regexes))
#         return bool(re.match(combined, string))


import warnings
from copy import copy, deepcopy
from itertools import zip_longest
from .collection_helpers import callable_get, setitem, consume
from .utils import match_any
    from . import config
            return command(original, new, current)

    def apply(self, new, original, current, commands, key=None):
        for command in commands:
            if isinstance(command, (tuple, list)):
                # Command is a tuple with (key, value)
                # Previous values do not matter
                new_key = self.process_element(command[0], new, original, current)
                new_value = self.process_element(command[1], new, original, current)
                if new_key is not None and new_value is not None:
                    new[new_key] = new_value
            elif self.has(original, key):
                # Command is a new key.
                # It uses the previous key to get the value
                new_key = self.process_element(command, new, original, current)
                if new_key is not None:
                    new[new_key] = self.get(original, key)

    def run(self, original, article=None, new=None, skip_result=False):
        cp = self.new_current(original)
        new = new or {}
        if "<before>" in self.rules:
            self.apply(new, original, cp, self.rules["<before>"])
        for key in self.attrs(original):
            if key in self.rules:
                self.apply(new, original, cp, self.rules[key], key=key)
                self.indicate_usage(cp, key)
        if "<middle>" in self.rules:
            self.apply(new, original, cp, self.rules["<middle>"])
        for key, value in self.iterate_remaining(original, cp):

# Path: snowballing/collection_helpers.py
# def callable_get(collection, key, default=None, args=[]):
#     """Get item from collection. Return collection applied to args, if it is callable"""
#     result = collection.get(key, default)
#     if callable(result):
#         return result(*args)
#     return result
# 
# def setitem(info, key, value):
#     """Set item in dict info if value is not None 
# 
#     Doctest:
# 
#     .. doctest::
# 
#         >>> info = {}
#         >>> setitem(info, 'def', 2)
#         >>> info
#         {'def': 2}
#         >>> setitem(info, 'abc', None)
#         >>> info
#         {'def': 2}
#     """
#     if value is not None:
#         info[key] = value
# 
# def consume(info, key):
#     """Consumes key from dict
# 
#     Arguments:
# 
#     * `info` -- dict
#     * `key` -- key
# 
#     Doctest:
# 
#     .. doctest::
# 
#         >>> info = {'abc': 1, 'def': 2}
#         >>> consume(info, 'abc')
#         1
#         >>> info
#         {'def': 2}
#         >>> consume(info, 'abc') is None
#         True
#     """
#     if key not in info:
#         return None
#     result = info[key]
#     del info[key]
#     return result
# 
# Path: snowballing/utils.py
# def match_any(string, regexes):
#     """Check if string matches any regex in list
# 
#     Doctest:
# 
#     .. doctest::
# 
#         >>> match_any("a", ["b", "c"])
#         False
#         >>> match_any("a", ["b", "c", "a"])
#         True
#         >>> match_any("_a", ["b", "c", "a"])
#         False
#         >>> match_any("_a", ["b", "c", "a", "_.*"])
#         True
#     """
#     if len(regexes) >= 100:
#         return any(re.match(regex + "$", string) for regex in regexes)
#     else:
#         combined = "({})".format(")|(".join(regex + "$" for regex in regexes))
#         return bool(re.match(combined, string))


# Path: snowballing/rules.py
import warnings
from copy import copy, deepcopy
from itertools import zip_longest
from .collection_helpers import callable_get, setitem, consume
from .utils import match_any
    from . import config

            return command(original, new, current)

    def apply(self, new, original, current, commands, key=None):
        for command in commands:
            if isinstance(command, (tuple, list)):
                # Command is a tuple with (key, value)
                # Previous values do not matter
                new_key = self.process_element(command[0], new, original, current)
                new_value = self.process_element(command[1], new, original, current)
                if new_key is not None and new_value is not None:
                    new[new_key] = new_value
            elif self.has(original, key):
                # Command is a new key.
                # It uses the previous key to get the value
                new_key = self.process_element(command, new, original, current)
                if new_key is not None:
                    new[new_key] = self.get(original, key)

    def run(self, original, article=None, new=None, skip_result=False):
        cp = self.new_current(original)
        new = new or {}
        if "<before>" in self.rules:
            self.apply(new, original, cp, self.rules["<before>"])
        for key in self.attrs(original):
            if key in self.rules:
                self.apply(new, original, cp, self.rules[key], key=key)
                self.indicate_usage(cp, key)
        if "<middle>" in self.rules:
            self.apply(new, original, cp, self.rules["<middle>"])
        for key, value in self.iterate_remaining(original, cp):

            setitem(new, key, value)