# Path: via/cache_buster.py
# class PathCacheBuster:
#     """A cache buster which modifies paths to enable immutable caching.
# 
#     Implements `pyramid.interfaces.ICacheBuster` and can be used with
#     `config.add_cache_buster()` to enable rewriting of URLs to a version
#     which contains the last modified time.
# 
#     This allows assets to be statically cached until at least one of them has
#     changed. This is achieved by generating a salt value from a hash of the
#     files which is applied to the input URL.
# 
#     :param path: Path to static for generating the salt value
#     """
# 
#     def __init__(self, path):
#         self.salt = self._generate_salt(path)
# 
#     def __call__(self, request, subpath, kw):  # pylint: disable=invalid-name
#         """Prepend the salt to the path.
# 
#         Implements the ICacheBuster interface.
#         """
#         return f"{self.salt}/{subpath}", kw
# 
#     @property
#     def immutable_path(self):
#         """Return the external URL where immutable content is accessible."""
#         return f"/static/{self.salt}"
# 
#     def get_immutable_file_test(self):
#         """Return an immutability test for use with Whitenoise."""
#         immutable_path = self.immutable_path
# 
#         def _test(_, url):
#             return url.startswith(immutable_path)
# 
#         return _test
# 
#     @staticmethod
#     def _generate_salt(path):
#         """Generate salt based on the last hash of all files.
# 
#         This ensures we only change salt when at least one file has changed.
#         """
#         hasher = hashlib.md5()
# 
#         for base_dir, dirs, file_names in os.walk(path, topdown=True):
#             # os.walk will respect our order as long as topdown=True. This
#             # ensures the same iteration through the files each time
#             dirs.sort()
# 
#             for file_name in sorted(file_names):
#                 with open(os.path.join(base_dir, file_name), "rb") as handle:
#                     hasher.update(handle.read())
# 
#         return hasher.hexdigest()
# 
# Path: via/checkmate.py
# class ViaCheckmateClient(CheckmateClient):
#     def __init__(self, request):
#         super().__init__(
#             host=request.registry.settings["checkmate_url"],
#             api_key=request.registry.settings["checkmate_api_key"],
#         )
#         self._request = request
# 
#     def raise_if_blocked(self, url):
#         """Raise a redirect to Checkmate if the URL is blocked.
# 
#         This will sensibly apply all ignore reasons and other configuration for
#         Checkmate.
# 
#         :param url: The URL to check
#         :raise HTTPTemporaryRedirect: If the URL is blocked
#         """
#         try:
#             blocked = self.check_url(
#                 url,
#                 allow_all=self._request.registry.settings["checkmate_allow_all"],
#                 blocked_for=self._request.params.get("via.blocked_for"),
#                 ignore_reasons=self._request.registry.settings[
#                     "checkmate_ignore_reasons"
#                 ],
#             )
# 
#         except CheckmateException:
#             blocked = None
# 
#         if blocked:
#             raise HTTPTemporaryRedirect(location=blocked.presentation_url)
# 
# Path: via/sentry_filters.py
# SENTRY_FILTERS = []


import os
import importlib_resources
import pyramid.config
from pathlib import Path
from pyramid.settings import asbool
from whitenoise import WhiteNoise
from via.cache_buster import PathCacheBuster
from via.checkmate import ViaCheckmateClient
from via.sentry_filters import SENTRY_FILTERS
    for param, options in PARAMETERS.items():
        formatter = options.get("formatter", lambda v: v)

        value = settings[param] = formatter(
            settings.get(param, os.environ.get(param.upper()))
        )

        if value is None and options.get("required"):
            raise ValueError(f"Param {param} must be provided.")

    # Configure sentry
    settings["h_pyramid_sentry.filters"] = SENTRY_FILTERS

    return settings


def create_app(_=None, **settings):
    """Configure and return the WSGI app."""
    config = pyramid.config.Configurator(settings=load_settings(settings))

    config.include("pyramid_exclog")
    config.include("pyramid_jinja2")
    config.include("pyramid_services")
    config.include("h_pyramid_sentry")

    config.include("via.views")
    config.include("via.services")

    # Configure Pyramid so we can generate static URLs
    static_path = str(importlib_resources.files("via") / "static")

# Path: via/cache_buster.py
# class PathCacheBuster:
#     """A cache buster which modifies paths to enable immutable caching.
# 
#     Implements `pyramid.interfaces.ICacheBuster` and can be used with
#     `config.add_cache_buster()` to enable rewriting of URLs to a version
#     which contains the last modified time.
# 
#     This allows assets to be statically cached until at least one of them has
#     changed. This is achieved by generating a salt value from a hash of the
#     files which is applied to the input URL.
# 
#     :param path: Path to static for generating the salt value
#     """
# 
#     def __init__(self, path):
#         self.salt = self._generate_salt(path)
# 
#     def __call__(self, request, subpath, kw):  # pylint: disable=invalid-name
#         """Prepend the salt to the path.
# 
#         Implements the ICacheBuster interface.
#         """
#         return f"{self.salt}/{subpath}", kw
# 
#     @property
#     def immutable_path(self):
#         """Return the external URL where immutable content is accessible."""
#         return f"/static/{self.salt}"
# 
#     def get_immutable_file_test(self):
#         """Return an immutability test for use with Whitenoise."""
#         immutable_path = self.immutable_path
# 
#         def _test(_, url):
#             return url.startswith(immutable_path)
# 
#         return _test
# 
#     @staticmethod
#     def _generate_salt(path):
#         """Generate salt based on the last hash of all files.
# 
#         This ensures we only change salt when at least one file has changed.
#         """
#         hasher = hashlib.md5()
# 
#         for base_dir, dirs, file_names in os.walk(path, topdown=True):
#             # os.walk will respect our order as long as topdown=True. This
#             # ensures the same iteration through the files each time
#             dirs.sort()
# 
#             for file_name in sorted(file_names):
#                 with open(os.path.join(base_dir, file_name), "rb") as handle:
#                     hasher.update(handle.read())
# 
#         return hasher.hexdigest()
# 
# Path: via/checkmate.py
# class ViaCheckmateClient(CheckmateClient):
#     def __init__(self, request):
#         super().__init__(
#             host=request.registry.settings["checkmate_url"],
#             api_key=request.registry.settings["checkmate_api_key"],
#         )
#         self._request = request
# 
#     def raise_if_blocked(self, url):
#         """Raise a redirect to Checkmate if the URL is blocked.
# 
#         This will sensibly apply all ignore reasons and other configuration for
#         Checkmate.
# 
#         :param url: The URL to check
#         :raise HTTPTemporaryRedirect: If the URL is blocked
#         """
#         try:
#             blocked = self.check_url(
#                 url,
#                 allow_all=self._request.registry.settings["checkmate_allow_all"],
#                 blocked_for=self._request.params.get("via.blocked_for"),
#                 ignore_reasons=self._request.registry.settings[
#                     "checkmate_ignore_reasons"
#                 ],
#             )
# 
#         except CheckmateException:
#             blocked = None
# 
#         if blocked:
#             raise HTTPTemporaryRedirect(location=blocked.presentation_url)
# 
# Path: via/sentry_filters.py
# SENTRY_FILTERS = []


# Path: via/app.py
import os
import importlib_resources
import pyramid.config
from pathlib import Path
from pyramid.settings import asbool
from whitenoise import WhiteNoise
from via.cache_buster import PathCacheBuster
from via.checkmate import ViaCheckmateClient
from via.sentry_filters import SENTRY_FILTERS

    for param, options in PARAMETERS.items():
        formatter = options.get("formatter", lambda v: v)

        value = settings[param] = formatter(
            settings.get(param, os.environ.get(param.upper()))
        )

        if value is None and options.get("required"):
            raise ValueError(f"Param {param} must be provided.")

    # Configure sentry
    settings["h_pyramid_sentry.filters"] = SENTRY_FILTERS

    return settings


def create_app(_=None, **settings):
    """Configure and return the WSGI app."""
    config = pyramid.config.Configurator(settings=load_settings(settings))

    config.include("pyramid_exclog")
    config.include("pyramid_jinja2")
    config.include("pyramid_services")
    config.include("h_pyramid_sentry")

    config.include("via.views")
    config.include("via.services")

    # Configure Pyramid so we can generate static URLs
    static_path = str(importlib_resources.files("via") / "static")

    cache_buster = PathCacheBuster(static_path)