# Path: kibitzr/stash.py
# class LazyStash(Stash):
#     def __init__(self):
#         self._stashobj = None
# 
#     @property
#     def _stash(self):
#         if self._stashobj is None:
#             self._stashobj = self.read()
#         return self._stashobj
# 
#     def __getitem__(self, key):
#         return self._stash[key]
# 
#     def get(self, key, default=None):
#         try:
#             return self._stash[key]
#         except KeyError:
#             return default
# 
# Path: kibitzr/transformer/html.py
# @contextlib.contextmanager
# def deep_recursion():
#     old_limit = sys.getrecursionlimit()
#     try:
#         sys.setrecursionlimit(100000)
#         yield
#     finally:
#         sys.setrecursionlimit(old_limit)
# 
# class SoupOps(object):
#     def __init__(self, selector=None, select_all=False):
#         self.selector = selector
#         self.select_all = select_all
# 
#     def tag_selector(self, html):
#         with soup(html) as doc:
#             element = doc.find(self.selector)
#             if element:
#                 return True, six.text_type(element)
#             else:
#                 logger.warning('Tag not found: %r', self.selector)
#                 return False, html
# 
#     def css_selector(self, html):
#         with soup(html) as doc:
#             try:
#                 elements = doc.select(self.selector)
#                 if self.select_all:
#                     result = u"".join(six.text_type(x)
#                                       for x in elements)
#                 else:
#                     result = six.text_type(elements[0])
#                 return True, result
#             except IndexError:
#                 logger.warning('CSS selector not found: %r', self.selector)
#                 return False, html
# 
#     @staticmethod
#     def extract_text(html):
#         with soup(html) as doc:
#             strings = doc.stripped_strings
#             return True, u'\n'.join([
#                 line
#                 for line in strings
#                 if line
#             ])
# 
#     @classmethod
#     def factory(cls, key, value, conf):
#         def transform(content):
#             instance = cls(selector=value, select_all=select_all)
#             method = handler.__get__(instance, cls)
#             return method(content)
#         action, _, all_flag = key.partition('-')
#         select_all = (all_flag == 'all')
#         handler = cls.SHORTCUTS[action]
#         return transform
# 
#     SHORTCUTS = {
#         'tag': tag_selector,
#         'css': css_selector,
#         'text': extract_text,
#     }
# 
# Path: kibitzr/transformer/xpath.py
# def parse_html(html):
#     """
#     Returns `html` parsed with lxml.
# 
#     :param html: Unicode content
#     """
#     from defusedxml import lxml as dlxml
#     from lxml import etree
# 
#     # lxml requires argument to be bytes
#     # see https://github.com/kibitzr/kibitzr/issues/47
#     encoded = html.encode('utf-8')
#     return dlxml.fromstring(encoded, parser=etree.HTMLParser())
# 
# def serialize_xpath_results(xpath_results, select_all):
#     """
#     Serializes results of xpath evaluation.
# 
#     :param xpath_results: Results of xpath evaluation.
#     See: https://lxml.de/xpathxslt.html#xpath-return-values
# 
#     :param select_all: True to get all matches
#     """
#     from defusedxml import lxml as dlxml
#     import re
# 
#     if isinstance(xpath_results, list):
#         if select_all is False:
#             xpath_results = xpath_results[0:1]
#     else:
#         xpath_results = [xpath_results]
# 
#     results = []
#     for r in xpath_results:
#         # namespace declarations
#         if isinstance(r, tuple):
#             results.append("%s=\"%s\"" % (r[0], r[1]))
#         # an element
#         elif hasattr(r, 'tag'):
#             results.append(
#                 re.sub(r'\s+', ' ',
#                        dlxml.tostring(r, method='html', encoding='unicode'))
#             )
#         else:
#             results.append(r)
# 
#     return u"\n".join(six.text_type(x).strip() for x in results)


import re
import os
import logging
import json
import functools
import six
from kibitzr.stash import LazyStash
from .html import deep_recursion, SoupOps
from .xpath import parse_html, serialize_xpath_results
        from jinja2 import Environment
        from jinja2 import TemplateError
        from bs4 import BeautifulSoup
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except (TypeError, ValueError):
            logger.warning("Invalid value passed in Jinja transform",
                           exc_info=True)
            return None
    return wrapper


@ignore_cast_error
def dollars_filter(number):
    sign = '-' if number < 0 else ''
    return '{0}${1:,}'.format(sign, abs(number))


@ignore_cast_error
def int_filter(text):
    return int(text)


@ignore_cast_error
def float_filter(text):
    return float(RE_NOT_FLOAT.sub('', text))


def text_filter(html):
    if isinstance(html, list):
        html = "".join(html)

# Path: kibitzr/stash.py
# class LazyStash(Stash):
#     def __init__(self):
#         self._stashobj = None
# 
#     @property
#     def _stash(self):
#         if self._stashobj is None:
#             self._stashobj = self.read()
#         return self._stashobj
# 
#     def __getitem__(self, key):
#         return self._stash[key]
# 
#     def get(self, key, default=None):
#         try:
#             return self._stash[key]
#         except KeyError:
#             return default
# 
# Path: kibitzr/transformer/html.py
# @contextlib.contextmanager
# def deep_recursion():
#     old_limit = sys.getrecursionlimit()
#     try:
#         sys.setrecursionlimit(100000)
#         yield
#     finally:
#         sys.setrecursionlimit(old_limit)
# 
# class SoupOps(object):
#     def __init__(self, selector=None, select_all=False):
#         self.selector = selector
#         self.select_all = select_all
# 
#     def tag_selector(self, html):
#         with soup(html) as doc:
#             element = doc.find(self.selector)
#             if element:
#                 return True, six.text_type(element)
#             else:
#                 logger.warning('Tag not found: %r', self.selector)
#                 return False, html
# 
#     def css_selector(self, html):
#         with soup(html) as doc:
#             try:
#                 elements = doc.select(self.selector)
#                 if self.select_all:
#                     result = u"".join(six.text_type(x)
#                                       for x in elements)
#                 else:
#                     result = six.text_type(elements[0])
#                 return True, result
#             except IndexError:
#                 logger.warning('CSS selector not found: %r', self.selector)
#                 return False, html
# 
#     @staticmethod
#     def extract_text(html):
#         with soup(html) as doc:
#             strings = doc.stripped_strings
#             return True, u'\n'.join([
#                 line
#                 for line in strings
#                 if line
#             ])
# 
#     @classmethod
#     def factory(cls, key, value, conf):
#         def transform(content):
#             instance = cls(selector=value, select_all=select_all)
#             method = handler.__get__(instance, cls)
#             return method(content)
#         action, _, all_flag = key.partition('-')
#         select_all = (all_flag == 'all')
#         handler = cls.SHORTCUTS[action]
#         return transform
# 
#     SHORTCUTS = {
#         'tag': tag_selector,
#         'css': css_selector,
#         'text': extract_text,
#     }
# 
# Path: kibitzr/transformer/xpath.py
# def parse_html(html):
#     """
#     Returns `html` parsed with lxml.
# 
#     :param html: Unicode content
#     """
#     from defusedxml import lxml as dlxml
#     from lxml import etree
# 
#     # lxml requires argument to be bytes
#     # see https://github.com/kibitzr/kibitzr/issues/47
#     encoded = html.encode('utf-8')
#     return dlxml.fromstring(encoded, parser=etree.HTMLParser())
# 
# def serialize_xpath_results(xpath_results, select_all):
#     """
#     Serializes results of xpath evaluation.
# 
#     :param xpath_results: Results of xpath evaluation.
#     See: https://lxml.de/xpathxslt.html#xpath-return-values
# 
#     :param select_all: True to get all matches
#     """
#     from defusedxml import lxml as dlxml
#     import re
# 
#     if isinstance(xpath_results, list):
#         if select_all is False:
#             xpath_results = xpath_results[0:1]
#     else:
#         xpath_results = [xpath_results]
# 
#     results = []
#     for r in xpath_results:
#         # namespace declarations
#         if isinstance(r, tuple):
#             results.append("%s=\"%s\"" % (r[0], r[1]))
#         # an element
#         elif hasattr(r, 'tag'):
#             results.append(
#                 re.sub(r'\s+', ' ',
#                        dlxml.tostring(r, method='html', encoding='unicode'))
#             )
#         else:
#             results.append(r)
# 
#     return u"\n".join(six.text_type(x).strip() for x in results)


# Path: kibitzr/transformer/jinja_transform.py
import re
import os
import logging
import json
import functools
import six
from kibitzr.stash import LazyStash
from .html import deep_recursion, SoupOps
from .xpath import parse_html, serialize_xpath_results
        from jinja2 import Environment
        from jinja2 import TemplateError
        from bs4 import BeautifulSoup

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except (TypeError, ValueError):
            logger.warning("Invalid value passed in Jinja transform",
                           exc_info=True)
            return None
    return wrapper


@ignore_cast_error
def dollars_filter(number):
    sign = '-' if number < 0 else ''
    return '{0}${1:,}'.format(sign, abs(number))


@ignore_cast_error
def int_filter(text):
    return int(text)


@ignore_cast_error
def float_filter(text):
    return float(RE_NOT_FLOAT.sub('', text))


def text_filter(html):
    if isinstance(html, list):
        html = "".join(html)

    ok, content = SoupOps.extract_text(html)