diff --git a/.editorconfig b/.editorconfig index a9c06c97..f1ec6c3d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,7 +3,7 @@ root = true [*] charset = utf-8 end_of_line = lf -indent_size = 4 +indent_size = 2 indent_style = space insert_final_newline = true trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore index 6ea22c9c..c2658d7d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1 @@ -*.egg-info -.*.swp -.*.swo -*.pyc -.DS_Store -docs/_build -docs/*/_build -build -dist -tags -.tox -.coverage -htmlcov -*.orig -venv -samples/output -*.pem -*.lock -.pdm-python -.vale -.venv -**/LC_MESSAGES/*.mo - -# direnv -.envrc - -# IDE cruft -.idea -.vscode +node_modules/ diff --git a/pelican/themes/simple/README.md b/README.md similarity index 100% rename from pelican/themes/simple/README.md rename to README.md diff --git a/pelican/themes/simple/package-lock.json b/package-lock.json similarity index 100% rename from pelican/themes/simple/package-lock.json rename to package-lock.json diff --git a/pelican/themes/simple/package.json b/package.json similarity index 100% rename from pelican/themes/simple/package.json rename to package.json diff --git a/pelican/__init__.py b/pelican/__init__.py deleted file mode 100644 index 96849bae..00000000 --- a/pelican/__init__.py +++ /dev/null @@ -1,687 +0,0 @@ -import argparse -import importlib.metadata -import json -import logging -import multiprocessing -import os -import pprint -import sys -import time -import traceback -from collections.abc import Iterable - -# Combines all paths to `pelican` package accessible from `sys.path` -# Makes it possible to install `pelican` and namespace plugins into different -# locations in the file system (e.g. pip with `-e` or `--user`) -from pkgutil import extend_path - -__path__ = extend_path(__path__, __name__) - -# pelican.log has to be the first pelican module to be loaded -# because logging.setLoggerClass has to be called before logging.getLogger -from pelican.log import console, DEFAULT_LOG_HANDLER # noqa: I001 -from pelican.log import init as init_logging -from pelican.generators import ( - ArticlesGenerator, - PagesGenerator, - SourceFileGenerator, - StaticGenerator, - TemplatePagesGenerator, -) -from pelican.plugins import signals -from pelican.plugins._utils import get_plugin_name, load_plugins -from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer -from pelican.settings import read_settings -from pelican.utils import clean_output_dir, maybe_pluralize, wait_for_changes -from pelican.writers import Writer - -try: - __version__ = importlib.metadata.version("pelican") -except Exception: - __version__ = "unknown" - -DEFAULT_CONFIG_NAME = "pelicanconf.py" -logger = logging.getLogger(__name__) - - -class Pelican: - def __init__(self, settings): - """Pelican initialization - - Performs some checks on the environment before doing anything else. - """ - - # define the default settings - self.settings = settings - - self.path = settings["PATH"] - self.theme = settings["THEME"] - self.output_path = settings["OUTPUT_PATH"] - self.ignore_files = settings["IGNORE_FILES"] - self.delete_outputdir = settings["DELETE_OUTPUT_DIRECTORY"] - self.output_retention = settings["OUTPUT_RETENTION"] - - self.init_path() - self.init_plugins() - signals.initialized.send(self) - - def init_path(self): - if not any(p in sys.path for p in ["", os.curdir]): - logger.debug("Adding current directory to system path") - sys.path.insert(0, "") - - def init_plugins(self): - self.plugins = [] - for plugin in load_plugins(self.settings): - name = get_plugin_name(plugin) - logger.debug("Registering plugin `%s`", name) - try: - plugin.register() - self.plugins.append(plugin) - except Exception as e: - logger.error( - "Cannot register plugin `%s`\n%s", - name, - e, - stacklevel=2, - ) - if self.settings.get("DEBUG", False): - console.print_exception() - - self.settings["PLUGINS"] = [get_plugin_name(p) for p in self.plugins] - - def run(self): - """Run the generators and return""" - start_time = time.time() - - context = self.settings.copy() - # Share these among all the generators and content objects - # They map source paths to Content objects or None - context["generated_content"] = {} - context["static_links"] = set() - context["static_content"] = {} - context["localsiteurl"] = self.settings["SITEURL"] - - generators = [ - cls( - context=context, - settings=self.settings, - path=self.path, - theme=self.theme, - output_path=self.output_path, - ) - for cls in self._get_generator_classes() - ] - - # Delete the output directory if (1) the appropriate setting is True - # and (2) that directory is not the parent of the source directory - if self.delete_outputdir and os.path.commonpath( - [os.path.realpath(self.output_path)] - ) != os.path.commonpath( - [os.path.realpath(self.output_path), os.path.realpath(self.path)] - ): - clean_output_dir(self.output_path, self.output_retention) - - for p in generators: - if hasattr(p, "generate_context"): - p.generate_context() - if hasattr(p, "check_disabled_readers"): - p.check_disabled_readers() - - # for plugins that create/edit the summary - logger.debug("Signal all_generators_finalized.send()") - signals.all_generators_finalized.send(generators) - - # update links in the summary, etc - for p in generators: - if hasattr(p, "refresh_metadata_intersite_links"): - p.refresh_metadata_intersite_links() - - writer = self._get_writer() - - for p in generators: - if hasattr(p, "generate_output"): - p.generate_output(writer) - - signals.finalized.send(self) - - articles_generator = next( - g for g in generators if isinstance(g, ArticlesGenerator) - ) - pages_generator = next(g for g in generators if isinstance(g, PagesGenerator)) - - pluralized_articles = maybe_pluralize( - (len(articles_generator.articles) + len(articles_generator.translations)), - "article", - "articles", - ) - pluralized_drafts = maybe_pluralize( - ( - len(articles_generator.drafts) - + len(articles_generator.drafts_translations) - ), - "draft", - "drafts", - ) - pluralized_hidden_articles = maybe_pluralize( - ( - len(articles_generator.hidden_articles) - + len(articles_generator.hidden_translations) - ), - "hidden article", - "hidden articles", - ) - pluralized_pages = maybe_pluralize( - (len(pages_generator.pages) + len(pages_generator.translations)), - "page", - "pages", - ) - pluralized_hidden_pages = maybe_pluralize( - ( - len(pages_generator.hidden_pages) - + len(pages_generator.hidden_translations) - ), - "hidden page", - "hidden pages", - ) - pluralized_draft_pages = maybe_pluralize( - ( - len(pages_generator.draft_pages) - + len(pages_generator.draft_translations) - ), - "draft page", - "draft pages", - ) - - console.print( - f"Done: Processed {pluralized_articles}, {pluralized_drafts}, {pluralized_hidden_articles}, {pluralized_pages}, {pluralized_hidden_pages} and {pluralized_draft_pages} in {time.time() - start_time:.2f} seconds." - ) - - def _get_generator_classes(self): - discovered_generators = [ - (ArticlesGenerator, "internal"), - (PagesGenerator, "internal"), - ] - - if self.settings["TEMPLATE_PAGES"]: - discovered_generators.append((TemplatePagesGenerator, "internal")) - - if self.settings["OUTPUT_SOURCES"]: - discovered_generators.append((SourceFileGenerator, "internal")) - - for receiver, values in signals.get_generators.send(self): - if not isinstance(values, Iterable): - values = (values,) - for generator in values: - if generator is None: - continue # plugin did not return a generator - discovered_generators.append((generator, receiver.__module__)) - - # StaticGenerator must run last, so it can identify files that - # were skipped by the other generators, and so static files can - # have their output paths overridden by the {attach} link syntax. - discovered_generators.append((StaticGenerator, "internal")) - - generators = [] - - for generator, origin in discovered_generators: - if not isinstance(generator, type): - logger.error("Generator %s (%s) cannot be loaded", generator, origin) - continue - - logger.debug("Found generator: %s (%s)", generator.__name__, origin) - generators.append(generator) - - return generators - - def _get_writer(self): - writers = [w for _, w in signals.get_writer.send(self) if isinstance(w, type)] - num_writers = len(writers) - - if num_writers == 0: - return Writer(self.output_path, settings=self.settings) - - if num_writers > 1: - logger.warning("%s writers found, using only first one", num_writers) - - writer = writers[0] - - logger.debug("Found writer: %s (%s)", writer.__name__, writer.__module__) - return writer(self.output_path, settings=self.settings) - - -class PrintSettings(argparse.Action): - def __call__(self, parser, namespace, values, option_string): - init_logging(name=__name__) - - try: - instance, settings = get_instance(namespace) - except Exception as e: - logger.critical("%s: %s", e.__class__.__name__, e) - console.print_exception() - sys.exit(getattr(e, "exitcode", 1)) - - if values: - # One or more arguments provided, so only print those settings - for setting in values: - if setting in settings: - # Only add newline between setting name and value if dict - if isinstance(settings[setting], (dict, tuple, list)): - setting_format = "\n{}:\n{}" - else: - setting_format = "\n{}: {}" - console.print( - setting_format.format( - setting, pprint.pformat(settings[setting]) - ) - ) - else: - console.print(f"\n{setting} is not a recognized setting.") - break - else: - # No argument was given to --print-settings, so print all settings - console.print(settings) - - parser.exit() - - -class ParseOverrides(argparse.Action): - def __call__(self, parser, namespace, values, option_string=None): - overrides = {} - for item in values: - try: - k, v = item.split("=", 1) - except ValueError: - raise ValueError( - "Extra settings must be specified as KEY=VALUE pairs " - f"but you specified {item}" - ) from None - try: - overrides[k] = json.loads(v) - except json.decoder.JSONDecodeError: - raise ValueError( - f"Invalid JSON value: {v}. " - "Values specified via -e / --extra-settings flags " - "must be in JSON notation. " - "Use -e KEY='\"string\"' to specify a string value; " - "-e KEY=null to specify None; " - "-e KEY=false (or true) to specify False (or True)." - ) from None - setattr(namespace, self.dest, overrides) - - -def parse_arguments(argv=None): - parser = argparse.ArgumentParser( - description="A tool to generate a static blog, " - " with restructured text input files.", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - - parser.add_argument( - dest="path", - nargs="?", - help="Path where to find the content files.", - default=None, - ) - - parser.add_argument( - "-t", - "--theme-path", - dest="theme", - help="Path where to find the theme templates. If not " - "specified, it will use the default one included with " - "pelican.", - ) - - parser.add_argument( - "-o", - "--output", - dest="output", - help="Where to output the generated files. If not " - "specified, a directory will be created, named " - '"output" in the current path.', - ) - - parser.add_argument( - "-s", - "--settings", - dest="settings", - help="The settings of the application, this is " - f"automatically set to {DEFAULT_CONFIG_NAME} if a file exists with this " - "name.", - ) - - parser.add_argument( - "-d", - "--delete-output-directory", - dest="delete_outputdir", - action="store_true", - default=None, - help="Delete the output directory.", - ) - - parser.add_argument( - "-v", - "--verbose", - action="store_const", - const=logging.INFO, - dest="verbosity", - help="Show all messages.", - ) - - parser.add_argument( - "-q", - "--quiet", - action="store_const", - const=logging.CRITICAL, - dest="verbosity", - help="Show only critical errors.", - ) - - parser.add_argument( - "-D", - "--debug", - action="store_const", - const=logging.DEBUG, - dest="verbosity", - help="Show all messages, including debug messages.", - ) - - parser.add_argument( - "--version", - action="version", - version=__version__, - help="Print the pelican version and exit.", - ) - - parser.add_argument( - "-r", - "--autoreload", - dest="autoreload", - action="store_true", - help="Relaunch pelican each time a modification occurs" - " on the content files.", - ) - - parser.add_argument( - "--print-settings", - dest="print_settings", - nargs="*", - action=PrintSettings, - metavar="SETTING_NAME", - help="Print current configuration settings and exit. " - "Append one or more setting name arguments to see the " - "values for specific settings only.", - ) - - parser.add_argument( - "--relative-urls", - dest="relative_paths", - action="store_true", - help="Use relative urls in output, useful for site development", - ) - - parser.add_argument( - "--cache-path", - dest="cache_path", - help=( - "Directory in which to store cache files. " - 'If not specified, defaults to "cache".' - ), - ) - - parser.add_argument( - "--ignore-cache", - action="store_true", - dest="ignore_cache", - help="Ignore content cache from previous runs by not loading cache files.", - ) - - parser.add_argument( - "--fatal", - metavar="errors|warnings", - choices=("errors", "warnings"), - default="", - help=( - "Exit the program with non-zero status if any " - "errors/warnings encountered." - ), - ) - - LOG_HANDLERS = {"plain": None, "rich": DEFAULT_LOG_HANDLER} - parser.add_argument( - "--log-handler", - default="rich", - choices=LOG_HANDLERS, - help=( - "Which handler to use to format log messages. " - "The `rich` handler prints output in columns." - ), - ) - - parser.add_argument( - "--logs-dedup-min-level", - default="WARNING", - choices=("DEBUG", "INFO", "WARNING", "ERROR"), - help=( - "Only enable log de-duplication for levels equal" - " to or above the specified value" - ), - ) - - parser.add_argument( - "-l", - "--listen", - dest="listen", - action="store_true", - help="Serve content files via HTTP and port 8000.", - ) - - parser.add_argument( - "-p", - "--port", - dest="port", - type=int, - help="Port to serve HTTP files at. (default: 8000)", - ) - - parser.add_argument( - "-b", - "--bind", - dest="bind", - help="IP to bind to when serving files via HTTP (default: 127.0.0.1)", - ) - - parser.add_argument( - "-e", - "--extra-settings", - dest="overrides", - help="Specify one or more SETTING=VALUE pairs to " - "override settings. VALUE must be in JSON notation: " - "specify string values as SETTING='\"some string\"'; " - "booleans as SETTING=true or SETTING=false; " - "None as SETTING=null.", - nargs="*", - action=ParseOverrides, - default={}, - ) - - args = parser.parse_args(argv) - - if args.port is not None and not args.listen: - logger.warning("--port without --listen has no effect") - if args.bind is not None and not args.listen: - logger.warning("--bind without --listen has no effect") - - args.log_handler = LOG_HANDLERS[args.log_handler] - - return args - - -def get_config(args): - """Builds a config dictionary based on supplied `args`.""" - config = {} - if args.path: - config["PATH"] = os.path.abspath(os.path.expanduser(args.path)) - if args.output: - config["OUTPUT_PATH"] = os.path.abspath(os.path.expanduser(args.output)) - if args.theme: - abstheme = os.path.abspath(os.path.expanduser(args.theme)) - config["THEME"] = abstheme if os.path.exists(abstheme) else args.theme - if args.delete_outputdir is not None: - config["DELETE_OUTPUT_DIRECTORY"] = args.delete_outputdir - if args.ignore_cache: - config["LOAD_CONTENT_CACHE"] = False - if args.cache_path: - config["CACHE_PATH"] = args.cache_path - if args.relative_paths: - config["RELATIVE_URLS"] = args.relative_paths - if args.port is not None: - config["PORT"] = args.port - if args.bind is not None: - config["BIND"] = args.bind - config["DEBUG"] = args.verbosity == logging.DEBUG - config.update(args.overrides) - - return config - - -def get_instance(args): - config_file = args.settings - if config_file is None and os.path.isfile(DEFAULT_CONFIG_NAME): - config_file = DEFAULT_CONFIG_NAME - args.settings = DEFAULT_CONFIG_NAME - - settings = read_settings(config_file, override=get_config(args)) - - cls = settings["PELICAN_CLASS"] - if isinstance(cls, str): - module, cls_name = cls.rsplit(".", 1) - module = __import__(module) - cls = getattr(module, cls_name) - - return cls(settings), settings - - -def autoreload(args, excqueue=None): - console.print( - " --- AutoReload Mode: Monitoring `content`, `theme` and" - " `settings` for changes. ---" - ) - pelican, settings = get_instance(args) - settings_file = os.path.abspath(args.settings) - while True: - try: - pelican.run() - - changed_files = wait_for_changes(args.settings, settings) - changed_files = {c[1] for c in changed_files} - - if settings_file in changed_files: - pelican, settings = get_instance(args) - - console.print( - "\n-> Modified: {}. re-generating...".format(", ".join(changed_files)) - ) - - except KeyboardInterrupt: - if excqueue is not None: - excqueue.put(None) - return - raise - - except Exception as e: - if args.verbosity == logging.DEBUG: - if excqueue is not None: - excqueue.put(traceback.format_exception_only(type(e), e)[-1]) - else: - raise - logger.warning( - 'Caught exception:\n"%s".', e, exc_info=settings.get("DEBUG", False) - ) - - -def listen(server, port, output, excqueue=None): - # set logging level to at least "INFO" (so we can see the server requests) - if logger.level < logging.INFO: - logger.setLevel(logging.INFO) - - RootedHTTPServer.allow_reuse_address = True - try: - httpd = RootedHTTPServer(output, (server, port), ComplexHTTPRequestHandler) - except OSError as e: - logging.error("Could not listen on port %s, server %s.", port, server) - if excqueue is not None: - excqueue.put(traceback.format_exception_only(type(e), e)[-1]) - return - - try: - console.print(f"Serving site at: http://{server}:{port} - Tap CTRL-C to stop") - httpd.serve_forever() - except Exception as e: - if excqueue is not None: - excqueue.put(traceback.format_exception_only(type(e), e)[-1]) - return - - except KeyboardInterrupt: - httpd.socket.close() - if excqueue is not None: - return - raise - - -def main(argv=None): - args = parse_arguments(argv) - logs_dedup_min_level = getattr(logging, args.logs_dedup_min_level) - init_logging( - level=args.verbosity, - fatal=args.fatal, - name=__name__, - handler=args.log_handler, - logs_dedup_min_level=logs_dedup_min_level, - ) - - logger.debug("Pelican version: %s", __version__) - logger.debug("Python version: %s", sys.version.split()[0]) - - try: - pelican, settings = get_instance(args) - - if args.autoreload and args.listen: - excqueue = multiprocessing.Queue() - p1 = multiprocessing.Process(target=autoreload, args=(args, excqueue)) - p2 = multiprocessing.Process( - target=listen, - args=( - settings.get("BIND"), - settings.get("PORT"), - settings.get("OUTPUT_PATH"), - excqueue, - ), - ) - try: - p1.start() - p2.start() - exc = excqueue.get() - if exc is not None: - logger.critical(exc) - finally: - p1.terminate() - p2.terminate() - elif args.autoreload: - autoreload(args) - elif args.listen: - listen( - settings.get("BIND"), settings.get("PORT"), settings.get("OUTPUT_PATH") - ) - else: - with console.status("Generating..."): - pelican.run() - except KeyboardInterrupt: - logger.warning("Keyboard interrupt received. Exiting.") - except Exception as e: - logger.critical("%s: %s", e.__class__.__name__, e) - - if args.verbosity == logging.DEBUG: - console.print_exception() - sys.exit(getattr(e, "exitcode", 1)) diff --git a/pelican/__main__.py b/pelican/__main__.py deleted file mode 100644 index 41a1f712..00000000 --- a/pelican/__main__.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -python -m pelican module entry point to run via python -m -""" - -from . import main - -if __name__ == "__main__": - main() diff --git a/pelican/cache.py b/pelican/cache.py deleted file mode 100644 index d1f8550e..00000000 --- a/pelican/cache.py +++ /dev/null @@ -1,140 +0,0 @@ -import hashlib -import logging -import os -import pickle - -from pelican.utils import mkdir_p - -logger = logging.getLogger(__name__) - - -class FileDataCacher: - """Class that can cache data contained in files""" - - def __init__(self, settings, cache_name, caching_policy, load_policy): - """Load the specified cache within CACHE_PATH in settings - - only if *load_policy* is True, - May use gzip if GZIP_CACHE ins settings is True. - Sets caching policy according to *caching_policy*. - """ - self.settings = settings - self._cache_path = os.path.join(self.settings["CACHE_PATH"], cache_name) - self._cache_data_policy = caching_policy - if self.settings["GZIP_CACHE"]: - import gzip - - self._cache_open = gzip.open - else: - self._cache_open = open - if load_policy: - try: - with self._cache_open(self._cache_path, "rb") as fhandle: - self._cache = pickle.load(fhandle) - except (OSError, UnicodeDecodeError) as err: - logger.debug( - "Cannot load cache %s (this is normal on first " - "run). Proceeding with empty cache.\n%s", - self._cache_path, - err, - ) - self._cache = {} - except pickle.PickleError as err: - logger.warning( - "Cannot unpickle cache %s, cache may be using " - "an incompatible protocol (see pelican " - "caching docs). " - "Proceeding with empty cache.\n%s", - self._cache_path, - err, - ) - self._cache = {} - else: - self._cache = {} - - def cache_data(self, filename, data): - """Cache data for given file""" - if self._cache_data_policy: - self._cache[filename] = data - - def get_cached_data(self, filename, default=None): - """Get cached data for the given file - - if no data is cached, return the default object - """ - return self._cache.get(filename, default) - - def save_cache(self): - """Save the updated cache""" - if self._cache_data_policy: - try: - mkdir_p(self.settings["CACHE_PATH"]) - with self._cache_open(self._cache_path, "wb") as fhandle: - pickle.dump(self._cache, fhandle) - except (OSError, pickle.PicklingError, TypeError) as err: - logger.warning( - "Could not save cache %s\n ... %s", self._cache_path, err - ) - - -class FileStampDataCacher(FileDataCacher): - """Subclass that also caches the stamp of the file""" - - def __init__(self, settings, cache_name, caching_policy, load_policy): - """This subclass additionally sets filestamp function - and base path for filestamping operations - """ - - super().__init__(settings, cache_name, caching_policy, load_policy) - - method = self.settings["CHECK_MODIFIED_METHOD"] - if method == "mtime": - self._filestamp_func = os.path.getmtime - else: - try: - hash_func = getattr(hashlib, method) - - def filestamp_func(filename): - """return hash of file contents""" - with open(filename, "rb") as fhandle: - return hash_func(fhandle.read()).digest() - - self._filestamp_func = filestamp_func - except AttributeError as err: - logger.warning("Could not get hashing function\n\t%s", err) - self._filestamp_func = None - - def cache_data(self, filename, data): - """Cache stamp and data for the given file""" - stamp = self._get_file_stamp(filename) - super().cache_data(filename, (stamp, data)) - - def _get_file_stamp(self, filename): - """Check if the given file has been modified - since the previous build. - - depending on CHECK_MODIFIED_METHOD - a float may be returned for 'mtime', - a hash for a function name in the hashlib module - or an empty bytes string otherwise - """ - - try: - return self._filestamp_func(filename) - except (OSError, TypeError) as err: - logger.warning("Cannot get modification stamp for %s\n\t%s", filename, err) - return "" - - def get_cached_data(self, filename, default=None): - """Get the cached data for the given filename - if the file has not been modified. - - If no record exists or file has been modified, return default. - Modification is checked by comparing the cached - and current file stamp. - """ - - stamp, data = super().get_cached_data(filename, (None, default)) - if stamp != self._get_file_stamp(filename): - return default - return data diff --git a/pelican/contents.py b/pelican/contents.py deleted file mode 100644 index 0769f875..00000000 --- a/pelican/contents.py +++ /dev/null @@ -1,692 +0,0 @@ -import copy -import datetime -import locale -import logging -import os -import re -from datetime import timezone -from html import unescape -from typing import Any, Dict, Optional, Set, Tuple -from urllib.parse import ParseResult, unquote, urljoin, urlparse, urlunparse - -try: - from zoneinfo import ZoneInfo -except ModuleNotFoundError: - from backports.zoneinfo import ZoneInfo - - -from pelican.plugins import signals -from pelican.settings import DEFAULT_CONFIG, Settings - -# Import these so that they're available when you import from pelican.contents. -from pelican.urlwrappers import Author, Category, Tag, URLWrapper # NOQA -from pelican.utils import ( - deprecated_attribute, - memoized, - path_to_url, - posixize_path, - sanitised_join, - set_date_tzinfo, - slugify, - truncate_html_paragraphs, - truncate_html_words, -) - -logger = logging.getLogger(__name__) - - -class Content: - """Represents a content. - - :param content: the string to parse, containing the original content. - :param metadata: the metadata associated to this page (optional). - :param settings: the settings dictionary (optional). - :param source_path: The location of the source of this content (if any). - :param context: The shared context between generators. - - """ - - default_template: Optional[str] = None - mandatory_properties: Tuple[str, ...] = () - - @deprecated_attribute(old="filename", new="source_path", since=(3, 2, 0)) - def filename(): - return None - - def __init__( - self, - content: str, - metadata: Optional[Dict[str, Any]] = None, - settings: Optional[Settings] = None, - source_path: Optional[str] = None, - context: Optional[Dict[Any, Any]] = None, - ): - if metadata is None: - metadata = {} - if settings is None: - settings = copy.deepcopy(DEFAULT_CONFIG) - - self.settings = settings - self._content = content - if context is None: - context = {} - self._context = context - self.translations = [] - - local_metadata = {} - local_metadata.update(metadata) - - # set metadata as attributes - for key, value in local_metadata.items(): - if key in ("save_as", "url"): - key = "override_" + key - setattr(self, key.lower(), value) - - # also keep track of the metadata attributes available - self.metadata = local_metadata - - # default template if it's not defined in page - self.template = self._get_template() - - # First, read the authors from "authors", if not, fallback to "author" - # and if not use the settings defined one, if any. - if not hasattr(self, "author"): - if hasattr(self, "authors"): - self.author = self.authors[0] - elif "AUTHOR" in settings: - self.author = Author(settings["AUTHOR"], settings) - - if not hasattr(self, "authors") and hasattr(self, "author"): - self.authors = [self.author] - - # XXX Split all the following code into pieces, there is too much here. - - # manage languages - self.in_default_lang = True - if "DEFAULT_LANG" in settings: - default_lang = settings["DEFAULT_LANG"].lower() - if not hasattr(self, "lang"): - self.lang = default_lang - - self.in_default_lang = self.lang == default_lang - - # create the slug if not existing, generate slug according to - # setting of SLUG_ATTRIBUTE - if not hasattr(self, "slug"): - if settings["SLUGIFY_SOURCE"] == "title" and hasattr(self, "title"): - value = self.title - elif settings["SLUGIFY_SOURCE"] == "basename" and source_path is not None: - value = os.path.basename(os.path.splitext(source_path)[0]) - else: - value = None - if value is not None: - self.slug = slugify( - value, - regex_subs=settings.get("SLUG_REGEX_SUBSTITUTIONS", []), - preserve_case=settings.get("SLUGIFY_PRESERVE_CASE", False), - use_unicode=settings.get("SLUGIFY_USE_UNICODE", False), - ) - - self.source_path = source_path - self.relative_source_path = self.get_relative_source_path() - - # manage the date format - if not hasattr(self, "date_format"): - if hasattr(self, "lang") and self.lang in settings["DATE_FORMATS"]: - self.date_format = settings["DATE_FORMATS"][self.lang] - else: - self.date_format = settings["DEFAULT_DATE_FORMAT"] - - if isinstance(self.date_format, tuple): - locale_string = self.date_format[0] - locale.setlocale(locale.LC_ALL, locale_string) - self.date_format = self.date_format[1] - - # manage timezone - default_timezone = settings.get("TIMEZONE", "UTC") - timezone = getattr(self, "timezone", default_timezone) - self.timezone = ZoneInfo(timezone) - - if hasattr(self, "date"): - self.date = set_date_tzinfo(self.date, timezone) - self.locale_date = self.date.strftime(self.date_format) - - if hasattr(self, "modified"): - self.modified = set_date_tzinfo(self.modified, timezone) - self.locale_modified = self.modified.strftime(self.date_format) - - # manage status - if not hasattr(self, "status"): - # Previous default of None broke comment plugins and perhaps others - self.status = getattr(self, "default_status", "") - - # store the summary metadata if it is set - if "summary" in metadata: - self._summary = metadata["summary"] - - signals.content_object_init.send(self) - - def __str__(self) -> str: - return self.source_path or repr(self) - - def _has_valid_mandatory_properties(self) -> bool: - """Test mandatory properties are set.""" - for prop in self.mandatory_properties: - if not hasattr(self, prop): - logger.error( - "Skipping %s: could not find information about '%s'", self, prop - ) - return False - return True - - def _has_valid_save_as(self) -> bool: - """Return true if save_as doesn't write outside output path, false - otherwise.""" - try: - output_path = self.settings["OUTPUT_PATH"] - except KeyError: - # we cannot check - return True - - try: - sanitised_join(output_path, self.save_as) - except RuntimeError: # outside output_dir - logger.error( - "Skipping %s: file %r would be written outside output path", - self, - self.save_as, - ) - return False - - return True - - def _has_valid_status(self) -> bool: - if hasattr(self, "allowed_statuses"): - if self.status not in self.allowed_statuses: - logger.error( - "Unknown status '%s' for file %s, skipping it. (Not in %s)", - self.status, - self, - self.allowed_statuses, - ) - return False - - # if undefined we allow all - return True - - def is_valid(self) -> bool: - """Validate Content""" - # Use all() to not short circuit and get results of all validations - return all( - [ - self._has_valid_mandatory_properties(), - self._has_valid_save_as(), - self._has_valid_status(), - ] - ) - - @property - def url_format(self) -> Dict[str, Any]: - """Returns the URL, formatted with the proper values""" - metadata = copy.copy(self.metadata) - path = self.metadata.get("path", self.get_relative_source_path()) - metadata.update( - { - "path": path_to_url(path), - "slug": getattr(self, "slug", ""), - "lang": getattr(self, "lang", "en"), - "date": getattr(self, "date", datetime.datetime.now()), - "author": self.author.slug if hasattr(self, "author") else "", - "category": self.category.slug if hasattr(self, "category") else "", - } - ) - return metadata - - def _expand_settings(self, key: str, klass: Optional[str] = None) -> str: - if not klass: - klass = self.__class__.__name__ - fq_key = (f"{klass}_{key}").upper() - return str(self.settings[fq_key]).format(**self.url_format) - - def get_url_setting(self, key: str) -> str: - if hasattr(self, "override_" + key): - return getattr(self, "override_" + key) - key = key if self.in_default_lang else f"lang_{key}" - return self._expand_settings(key) - - def _link_replacer(self, siteurl: str, m: re.Match) -> str: - what = m.group("what") - value = urlparse(m.group("value")) - path = value.path - origin = m.group("path") - - # urllib.parse.urljoin() produces `a.html` for urljoin("..", "a.html") - # so if RELATIVE_URLS are enabled, we fall back to os.path.join() to - # properly get `../a.html`. However, os.path.join() produces - # `baz/http://foo/bar.html` for join("baz", "http://foo/bar.html") - # instead of correct "http://foo/bar.html", so one has to pick a side - # as there is no silver bullet. - if self.settings["RELATIVE_URLS"]: - joiner = os.path.join - else: - joiner = urljoin - - # However, it's not *that* simple: urljoin("blog", "index.html") - # produces just `index.html` instead of `blog/index.html` (unlike - # os.path.join()), so in order to get a correct answer one needs to - # append a trailing slash to siteurl in that case. This also makes - # the new behavior fully compatible with Pelican 3.7.1. - if not siteurl.endswith("/"): - siteurl += "/" - - # XXX Put this in a different location. - if what in {"filename", "static", "attach"}: - - def _get_linked_content(key: str, url: ParseResult) -> Optional[Content]: - nonlocal value - - def _find_path(path: str) -> Optional[Content]: - if path.startswith("/"): - path = path[1:] - else: - # relative to the source path of this content - path = self.get_relative_source_path( # type: ignore - os.path.join(self.relative_dir, path) - ) - return self._context[key].get(path, None) - - # try path - result = _find_path(url.path) - if result is not None: - return result - - # try unquoted path - result = _find_path(unquote(url.path)) - if result is not None: - return result - - # try html unescaped url - unescaped_url = urlparse(unescape(url.geturl())) - result = _find_path(unescaped_url.path) - if result is not None: - value = unescaped_url - return result - - # check if a static file is linked with {filename} - if what == "filename" and key == "generated_content": - linked_content = _get_linked_content("static_content", value) - if linked_content: - logger.warning( - "{filename} used for linking to static" - " content %s in %s. Use {static} instead", - value.path, - self.get_relative_source_path(), - ) - return linked_content - - return None - - if what == "filename": - key = "generated_content" - else: - key = "static_content" - - linked_content = _get_linked_content(key, value) - if linked_content: - if what == "attach": - linked_content.attach_to(self) # type: ignore - origin = joiner(siteurl, linked_content.url) - origin = origin.replace("\\", "/") # for Windows paths. - else: - logger.warning( - "Unable to find '%s', skipping url replacement.", - value.geturl(), - extra={ - "limit_msg": ( - "Other resources were not found " - "and their urls not replaced" - ) - }, - ) - elif what == "category": - origin = joiner(siteurl, Category(path, self.settings).url) - elif what == "tag": - origin = joiner(siteurl, Tag(path, self.settings).url) - elif what == "index": - origin = joiner(siteurl, self.settings["INDEX_SAVE_AS"]) - elif what == "author": - origin = joiner(siteurl, Author(path, self.settings).url) - else: - logger.warning( - "Replacement Indicator '%s' not recognized, skipping replacement", - what, - ) - - # keep all other parts, such as query, fragment, etc. - parts = list(value) - parts[2] = origin - origin = urlunparse(parts) - - return "".join((m.group("markup"), m.group("quote"), origin, m.group("quote"))) - - def _get_intrasite_link_regex(self) -> re.Pattern: - intrasite_link_regex = self.settings["INTRASITE_LINK_REGEX"] - regex = rf""" - (?P<[^\>]+ # match tag with all url-value attributes - (?:href|src|poster|data|cite|formaction|action|content)\s*=\s*) - - (?P["\']) # require value to be quoted - (?P{intrasite_link_regex}(?P.*?)) # the url value - (?P=quote)""" - return re.compile(regex, re.X) - - def _update_content(self, content: str, siteurl: str) -> str: - """Update the content attribute. - - Change all the relative paths of the content to relative paths - suitable for the output content. - - :param content: content resource that will be passed to the templates. - :param siteurl: siteurl which is locally generated by the writer in - case of RELATIVE_URLS. - """ - if not content: - return content - - hrefs = self._get_intrasite_link_regex() - return hrefs.sub(lambda m: self._link_replacer(siteurl, m), content) - - def get_static_links(self) -> Set[str]: - static_links = set() - hrefs = self._get_intrasite_link_regex() - for m in hrefs.finditer(self._content): - what = m.group("what") - value = urlparse(m.group("value")) - path = value.path - if what not in {"static", "attach"}: - continue - if path.startswith("/"): - path = path[1:] - else: - # relative to the source path of this content - path = self.get_relative_source_path( - os.path.join(self.relative_dir, path) - ) - path = path.replace("%20", " ") # type: ignore - static_links.add(path) - return static_links - - def get_siteurl(self) -> str: - return self._context.get("localsiteurl", "") - - @memoized - def get_content(self, siteurl: str) -> str: - if hasattr(self, "_get_content"): - content = self._get_content() - else: - content = self._content - return self._update_content(content, siteurl) - - @property - def content(self) -> str: - return self.get_content(self.get_siteurl()) - - @memoized - def get_summary(self, siteurl: str) -> str: - """Returns the summary of an article. - - This is based on the summary metadata if set, otherwise truncate the - content. - """ - if "summary" in self.metadata: - return self.metadata["summary"] - - content = self.content - max_paragraphs = self.settings.get("SUMMARY_MAX_PARAGRAPHS") - if max_paragraphs is not None: - content = truncate_html_paragraphs(self.content, max_paragraphs) - - if self.settings["SUMMARY_MAX_LENGTH"] is None: - return content - - return truncate_html_words( - self.content, - self.settings["SUMMARY_MAX_LENGTH"], - self.settings["SUMMARY_END_SUFFIX"], - ) - - @property - def summary(self) -> str: - return self.get_summary(self.get_siteurl()) - - def _get_summary(self) -> str: - """deprecated function to access summary""" - - logger.warning( - "_get_summary() has been deprecated since 3.6.4. " - "Use the summary decorator instead" - ) - return self.summary - - @summary.setter - def summary(self, value: str): - """Dummy function""" - - @property - def status(self) -> str: - return self._status - - @status.setter - def status(self, value: str) -> None: - # TODO maybe typecheck - self._status = value.lower() - - @property - def url(self) -> str: - return self.get_url_setting("url") - - @property - def save_as(self) -> str: - return self.get_url_setting("save_as") - - def _get_template(self) -> str: - if hasattr(self, "template") and self.template is not None: - return self.template - else: - return self.default_template - - def get_relative_source_path( - self, source_path: Optional[str] = None - ) -> Optional[str]: - """Return the relative path (from the content path) to the given - source_path. - - If no source path is specified, use the source path of this - content object. - """ - if not source_path: - source_path = self.source_path - if source_path is None: - return None - - return posixize_path( - os.path.relpath( - os.path.abspath(os.path.join(self.settings["PATH"], source_path)), - os.path.abspath(self.settings["PATH"]), - ) - ) - - @property - def relative_dir(self) -> str: - return posixize_path( - os.path.dirname( - os.path.relpath( - os.path.abspath(self.source_path), - os.path.abspath(self.settings["PATH"]), - ) - ) - ) - - def refresh_metadata_intersite_links(self) -> None: - for key in self.settings["FORMATTED_FIELDS"]: - if key in self.metadata and key != "summary": - value = self._update_content(self.metadata[key], self.get_siteurl()) - self.metadata[key] = value - setattr(self, key.lower(), value) - - # _summary is an internal variable that some plugins may be writing to, - # so ensure changes to it are picked up, and write summary back to it - if "summary" in self.settings["FORMATTED_FIELDS"]: - if hasattr(self, "_summary"): - self.metadata["summary"] = self._summary - - if "summary" in self.metadata: - self.metadata["summary"] = self._update_content( - self.metadata["summary"], self.get_siteurl() - ) - self._summary = self.metadata["summary"] - - -class SkipStub(Content): - """Stub class representing content that should not be processed in any way.""" - - def __init__( - self, content, metadata=None, settings=None, source_path=None, context=None - ): - self.source_path = source_path - - def is_valid(self): - return False - - @property - def content(self): - raise NotImplementedError("Stub content should not be read") - - @property - def save_as(self): - raise NotImplementedError("Stub content cannot be saved") - - -class Page(Content): - mandatory_properties = ("title",) - allowed_statuses = ("published", "hidden", "draft", "skip") - default_status = "published" - default_template = "page" - - def _expand_settings(self, key: str) -> str: - klass = "draft_page" if self.status == "draft" else None - return super()._expand_settings(key, klass) - - -class Article(Content): - mandatory_properties = ("title", "date", "category") - allowed_statuses = ("published", "hidden", "draft", "skip") - default_status = "published" - default_template = "article" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - # handle WITH_FUTURE_DATES (designate article to draft based on date) - if not self.settings["WITH_FUTURE_DATES"] and hasattr(self, "date"): - if self.date.tzinfo is None: - now = datetime.datetime.now() - else: - now = datetime.datetime.utcnow().replace(tzinfo=timezone.utc) - if self.date > now: - self.status = "draft" - - # if we are a draft and there is no date provided, set max datetime - if not hasattr(self, "date") and self.status == "draft": - self.date = datetime.datetime.max.replace(tzinfo=self.timezone) - - def _expand_settings(self, key: str) -> str: - klass = "draft" if self.status == "draft" else "article" - return super()._expand_settings(key, klass) - - -class Static(Content): - mandatory_properties = ("title",) - default_status = "published" - default_template = None - - def __init__(self, *args, **kwargs) -> None: - super().__init__(*args, **kwargs) - self._output_location_referenced = False - - @deprecated_attribute(old="filepath", new="source_path", since=(3, 2, 0)) - def filepath(): - return None - - @deprecated_attribute(old="src", new="source_path", since=(3, 2, 0)) - def src(): - return None - - @deprecated_attribute(old="dst", new="save_as", since=(3, 2, 0)) - def dst(): - return None - - @property - def url(self) -> str: - # Note when url has been referenced, so we can avoid overriding it. - self._output_location_referenced = True - return super().url - - @property - def save_as(self) -> str: - # Note when save_as has been referenced, so we can avoid overriding it. - self._output_location_referenced = True - return super().save_as - - def attach_to(self, content: Content) -> None: - """Override our output directory with that of the given content object.""" - - # Determine our file's new output path relative to the linking - # document. If it currently lives beneath the linking - # document's source directory, preserve that relationship on output. - # Otherwise, make it a sibling. - - linking_source_dir = os.path.dirname(content.source_path) - tail_path = os.path.relpath(self.source_path, linking_source_dir) - if tail_path.startswith(os.pardir + os.sep): - tail_path = os.path.basename(tail_path) - new_save_as = os.path.join(os.path.dirname(content.save_as), tail_path) - - # We do not build our new url by joining tail_path with the linking - # document's url, because we cannot know just by looking at the latter - # whether it points to the document itself or to its parent directory. - # (An url like 'some/content' might mean a directory named 'some' - # with a file named 'content', or it might mean a directory named - # 'some/content' with a file named 'index.html'.) Rather than trying - # to figure it out by comparing the linking document's url and save_as - # path, we simply build our new url from our new save_as path. - - new_url = path_to_url(new_save_as) - - def _log_reason(reason: str) -> None: - logger.warning( - "The {attach} link in %s cannot relocate " - "%s because %s. Falling back to " - "{filename} link behavior instead.", - content.get_relative_source_path(), - self.get_relative_source_path(), - reason, - extra={"limit_msg": "More {attach} warnings silenced."}, - ) - - # We never override an override, because we don't want to interfere - # with user-defined overrides that might be in EXTRA_PATH_METADATA. - if hasattr(self, "override_save_as") or hasattr(self, "override_url"): - if new_save_as != self.save_as or new_url != self.url: - _log_reason("its output location was already overridden") - return - - # We never change an output path that has already been referenced, - # because we don't want to break links that depend on that path. - if self._output_location_referenced: - if new_save_as != self.save_as or new_url != self.url: - _log_reason("another link already referenced its location") - return - - self.override_save_as = new_save_as - self.override_url = new_url diff --git a/pelican/generators.py b/pelican/generators.py deleted file mode 100644 index 6b44d79e..00000000 --- a/pelican/generators.py +++ /dev/null @@ -1,1138 +0,0 @@ -import calendar -import errno -import fnmatch -import logging -import os -from collections import defaultdict -from functools import partial -from itertools import chain, groupby -from operator import attrgetter -from typing import List, Optional, Set - -from jinja2 import ( - BaseLoader, - ChoiceLoader, - Environment, - FileSystemLoader, - PrefixLoader, - TemplateNotFound, -) - -from pelican.cache import FileStampDataCacher -from pelican.contents import Article, Page, SkipStub, Static -from pelican.plugins import signals -from pelican.plugins._utils import plugin_enabled -from pelican.readers import Readers -from pelican.utils import ( - DateFormatter, - copy, - mkdir_p, - order_content, - posixize_path, - process_translations, -) - -logger = logging.getLogger(__name__) - - -class PelicanTemplateNotFound(Exception): - pass - - -class Generator: - """Baseclass generator""" - - def __init__( - self, - context, - settings, - path, - theme, - output_path, - readers_cache_name="", - **kwargs, - ): - self.context = context - self.settings = settings - self.path = path - self.theme = theme - self.output_path = output_path - - for arg, value in kwargs.items(): - setattr(self, arg, value) - - self.readers = Readers(self.settings, readers_cache_name) - - # templates cache - self._templates = {} - self._templates_path = list(self.settings["THEME_TEMPLATES_OVERRIDES"]) - - theme_templates_path = os.path.expanduser(os.path.join(self.theme, "templates")) - self._templates_path.append(theme_templates_path) - theme_loader = FileSystemLoader(theme_templates_path) - - simple_theme_path = os.path.dirname(os.path.abspath(__file__)) - simple_loader = FileSystemLoader( - os.path.join(simple_theme_path, "themes", "simple", "templates") - ) - - self.env = Environment( - loader=ChoiceLoader( - [ - FileSystemLoader(self._templates_path), - simple_loader, # implicit inheritance - PrefixLoader( - {"!simple": simple_loader, "!theme": theme_loader} - ), # explicit ones - ] - ), - **self.settings["JINJA_ENVIRONMENT"], - ) - - logger.debug("Template list: %s", self.env.list_templates()) - - # provide utils.strftime as a jinja filter - self.env.filters.update({"strftime": DateFormatter()}) - - # get custom Jinja filters from user settings - custom_filters = self.settings["JINJA_FILTERS"] - self.env.filters.update(custom_filters) - - # get custom Jinja globals from user settings - custom_globals = self.settings["JINJA_GLOBALS"] - self.env.globals.update(custom_globals) - - # get custom Jinja tests from user settings - custom_tests = self.settings["JINJA_TESTS"] - self.env.tests["plugin_enabled"] = partial( - plugin_enabled, plugin_list=self.settings["PLUGINS"] - ) - self.env.tests.update(custom_tests) - - signals.generator_init.send(self) - - def get_template(self, name): - """Return the template by name. - Use self.theme to get the templates to use, and return a list of - templates ready to use with Jinja2. - """ - if name not in self._templates: - for ext in self.settings["TEMPLATE_EXTENSIONS"]: - try: - self._templates[name] = self.env.get_template(name + ext) - break - except TemplateNotFound: - continue - - if name not in self._templates: - raise PelicanTemplateNotFound( - "[templates] unable to load {}[{}] from {}".format( - name, - ", ".join(self.settings["TEMPLATE_EXTENSIONS"]), - self._templates_path, - ) - ) - - return self._templates[name] - - def _include_path(self, path, extensions=None): - """Inclusion logic for .get_files(), returns True/False - - :param path: the path which might be including - :param extensions: the list of allowed extensions, or False if all - extensions are allowed - """ - if extensions is None: - extensions = tuple(self.readers.extensions) - basename = os.path.basename(path) - - # check IGNORE_FILES - ignores = self.settings["IGNORE_FILES"] - if any(fnmatch.fnmatch(basename, ignore) for ignore in ignores): - return False - - ext = os.path.splitext(basename)[1][1:] - if extensions is False or ext in extensions: - return True - - return False - - def get_files( - self, paths, exclude: Optional[List[str]] = None, extensions=None - ) -> Set[str]: - """Return a list of files to use, based on rules - - :param paths: the list pf paths to search (relative to self.path) - :param exclude: the list of path to exclude - :param extensions: the list of allowed extensions (if False, all - extensions are allowed) - """ - if exclude is None: - exclude = [] - # backward compatibility for older generators - if isinstance(paths, str): - paths = [paths] - - # group the exclude dir names by parent path, for use with os.walk() - exclusions_by_dirpath = {} - for e in exclude: - parent_path, subdir = os.path.split(os.path.join(self.path, e)) - exclusions_by_dirpath.setdefault(parent_path, set()).add(subdir) - - files = set() - ignores = self.settings["IGNORE_FILES"] - for path in paths: - # careful: os.path.join() will add a slash when path == ''. - root = os.path.join(self.path, path) if path else self.path - - if os.path.isdir(root): - for dirpath, dirs, temp_files in os.walk( - root, topdown=True, followlinks=True - ): - excl = exclusions_by_dirpath.get(dirpath, ()) - # We copy the `dirs` list as we will modify it in the loop: - for d in list(dirs): - if d in excl or any( - fnmatch.fnmatch(d, ignore) for ignore in ignores - ): - if d in dirs: - dirs.remove(d) - - reldir = os.path.relpath(dirpath, self.path) - for f in temp_files: - fp = os.path.join(reldir, f) - if self._include_path(fp, extensions): - files.add(fp) - elif os.path.exists(root) and self._include_path(path, extensions): - files.add(path) # can't walk non-directories - return files - - def add_source_path(self, content, static=False): - """Record a source file path that a Generator found and processed. - Store a reference to its Content object, for url lookups later. - """ - location = content.get_relative_source_path() - key = "static_content" if static else "generated_content" - self.context[key][location] = content - - def _add_failed_source_path(self, path, static=False): - """Record a source file path that a Generator failed to process. - (For example, one that was missing mandatory metadata.) - The path argument is expected to be relative to self.path. - """ - key = "static_content" if static else "generated_content" - self.context[key][posixize_path(os.path.normpath(path))] = None - - def _is_potential_source_path(self, path, static=False): - """Return True if path was supposed to be used as a source file. - (This includes all source files that have been found by generators - before this method is called, even if they failed to process.) - The path argument is expected to be relative to self.path. - """ - key = "static_content" if static else "generated_content" - return posixize_path(os.path.normpath(path)) in self.context[key] - - def add_static_links(self, content): - """Add file links in content to context to be processed as Static - content. - """ - self.context["static_links"] |= content.get_static_links() - - def _update_context(self, items): - """Update the context with the given items from the current processor. - - Note that dictionary arguments will be converted to a list of tuples. - """ - for item in items: - value = getattr(self, item) - if hasattr(value, "items"): - value = list(value.items()) # py3k safeguard for iterators - self.context[item] = value - - def __str__(self): - # return the name of the class for logging purposes - return self.__class__.__name__ - - def _check_disabled_readers(self, paths, exclude: Optional[List[str]]) -> None: - """Log warnings for files that would have been processed by disabled readers.""" - for fil in self.get_files( - paths, exclude=exclude, extensions=self.readers.disabled_extensions - ): - self.readers.check_file(fil) - - -class CachingGenerator(Generator, FileStampDataCacher): - """Subclass of Generator and FileStampDataCacher classes - - enables content caching, either at the generator or reader level - """ - - def __init__(self, *args, **kwargs): - """Initialize the generator, then set up caching - - note the multiple inheritance structure - """ - cls_name = self.__class__.__name__ - Generator.__init__( - self, *args, readers_cache_name=(cls_name + "-Readers"), **kwargs - ) - - cache_this_level = self.settings["CONTENT_CACHING_LAYER"] == "generator" - caching_policy = cache_this_level and self.settings["CACHE_CONTENT"] - load_policy = cache_this_level and self.settings["LOAD_CONTENT_CACHE"] - FileStampDataCacher.__init__( - self, self.settings, cls_name, caching_policy, load_policy - ) - - def _get_file_stamp(self, filename): - """Get filestamp for path relative to generator.path""" - filename = os.path.join(self.path, filename) - return super()._get_file_stamp(filename) - - -class _FileLoader(BaseLoader): - def __init__(self, path, basedir): - self.path = path - self.fullpath = os.path.join(basedir, path) - - def get_source(self, environment, template): - if template != self.path or not os.path.exists(self.fullpath): - raise TemplateNotFound(template) - mtime = os.path.getmtime(self.fullpath) - with open(self.fullpath, encoding="utf-8") as f: - source = f.read() - return (source, self.fullpath, lambda: mtime == os.path.getmtime(self.fullpath)) - - -class TemplatePagesGenerator(Generator): - def generate_output(self, writer): - for source, dest in self.settings["TEMPLATE_PAGES"].items(): - self.env.loader.loaders.insert(0, _FileLoader(source, self.path)) - try: - template = self.env.get_template(source) - rurls = self.settings["RELATIVE_URLS"] - writer.write_file( - dest, template, self.context, rurls, override_output=True, url="" - ) - finally: - del self.env.loader.loaders[0] - - -class ArticlesGenerator(CachingGenerator): - """Generate blog articles""" - - def __init__(self, *args, **kwargs): - """initialize properties""" - # Published, listed articles - self.articles = [] # only articles in default language - self.translations = [] - # Published, unlisted articles - self.hidden_articles = [] - self.hidden_translations = [] - # Draft articles - self.drafts = [] # only drafts in default language - self.drafts_translations = [] - self.dates = {} - self.period_archives = defaultdict(list) - self.tags = defaultdict(list) - self.categories = defaultdict(list) - self.related_posts = [] - self.authors = defaultdict(list) - super().__init__(*args, **kwargs) - signals.article_generator_init.send(self) - - def generate_feeds(self, writer): - """Generate the feeds from the current context, and output files.""" - - if self.settings.get("FEED_ATOM"): - writer.write_feed( - self.articles, - self.context, - self.settings["FEED_ATOM"], - self.settings.get("FEED_ATOM_URL", self.settings["FEED_ATOM"]), - ) - - if self.settings.get("FEED_RSS"): - writer.write_feed( - self.articles, - self.context, - self.settings["FEED_RSS"], - self.settings.get("FEED_RSS_URL", self.settings["FEED_RSS"]), - feed_type="rss", - ) - - if self.settings.get("FEED_ALL_ATOM") or self.settings.get("FEED_ALL_RSS"): - all_articles = list(self.articles) - for article in self.articles: - all_articles.extend(article.translations) - order_content(all_articles, order_by=self.settings["ARTICLE_ORDER_BY"]) - - if self.settings.get("FEED_ALL_ATOM"): - writer.write_feed( - all_articles, - self.context, - self.settings["FEED_ALL_ATOM"], - self.settings.get( - "FEED_ALL_ATOM_URL", self.settings["FEED_ALL_ATOM"] - ), - ) - - if self.settings.get("FEED_ALL_RSS"): - writer.write_feed( - all_articles, - self.context, - self.settings["FEED_ALL_RSS"], - self.settings.get( - "FEED_ALL_RSS_URL", self.settings["FEED_ALL_RSS"] - ), - feed_type="rss", - ) - - for cat, arts in self.categories: - if self.settings.get("CATEGORY_FEED_ATOM"): - writer.write_feed( - arts, - self.context, - str(self.settings["CATEGORY_FEED_ATOM"]).format(slug=cat.slug), - self.settings.get( - "CATEGORY_FEED_ATOM_URL", - str(self.settings["CATEGORY_FEED_ATOM"]), - ).format(slug=cat.slug), - feed_title=cat.name, - ) - - if self.settings.get("CATEGORY_FEED_RSS"): - writer.write_feed( - arts, - self.context, - str(self.settings["CATEGORY_FEED_RSS"]).format(slug=cat.slug), - self.settings.get( - "CATEGORY_FEED_RSS_URL", - str(self.settings["CATEGORY_FEED_RSS"]), - ).format(slug=cat.slug), - feed_title=cat.name, - feed_type="rss", - ) - - for auth, arts in self.authors: - if self.settings.get("AUTHOR_FEED_ATOM"): - writer.write_feed( - arts, - self.context, - str(self.settings["AUTHOR_FEED_ATOM"]).format(slug=auth.slug), - self.settings.get( - "AUTHOR_FEED_ATOM_URL", - str(self.settings["AUTHOR_FEED_ATOM"]), - ).format(slug=auth.slug), - feed_title=auth.name, - ) - - if self.settings.get("AUTHOR_FEED_RSS"): - writer.write_feed( - arts, - self.context, - str(self.settings["AUTHOR_FEED_RSS"]).format(slug=auth.slug), - self.settings.get( - "AUTHOR_FEED_RSS_URL", - str(self.settings["AUTHOR_FEED_RSS"]), - ).format(slug=auth.slug), - feed_title=auth.name, - feed_type="rss", - ) - - if self.settings.get("TAG_FEED_ATOM") or self.settings.get("TAG_FEED_RSS"): - for tag, arts in self.tags.items(): - if self.settings.get("TAG_FEED_ATOM"): - writer.write_feed( - arts, - self.context, - str(self.settings["TAG_FEED_ATOM"]).format(slug=tag.slug), - self.settings.get( - "TAG_FEED_ATOM_URL", - str(self.settings["TAG_FEED_ATOM"]), - ).format(slug=tag.slug), - feed_title=tag.name, - ) - - if self.settings.get("TAG_FEED_RSS"): - writer.write_feed( - arts, - self.context, - str(self.settings["TAG_FEED_RSS"]).format(slug=tag.slug), - self.settings.get( - "TAG_FEED_RSS_URL", - str(self.settings["TAG_FEED_RSS"]), - ).format(slug=tag.slug), - feed_title=tag.name, - feed_type="rss", - ) - - if self.settings.get("TRANSLATION_FEED_ATOM") or self.settings.get( - "TRANSLATION_FEED_RSS" - ): - translations_feeds = defaultdict(list) - for article in chain(self.articles, self.translations): - translations_feeds[article.lang].append(article) - - for lang, items in translations_feeds.items(): - items = order_content(items, order_by=self.settings["ARTICLE_ORDER_BY"]) - if self.settings.get("TRANSLATION_FEED_ATOM"): - writer.write_feed( - items, - self.context, - str(self.settings["TRANSLATION_FEED_ATOM"]).format(lang=lang), - self.settings.get( - "TRANSLATION_FEED_ATOM_URL", - str(self.settings["TRANSLATION_FEED_ATOM"]), - ).format(lang=lang), - ) - if self.settings.get("TRANSLATION_FEED_RSS"): - writer.write_feed( - items, - self.context, - str(self.settings["TRANSLATION_FEED_RSS"]).format(lang=lang), - self.settings.get( - "TRANSLATION_FEED_RSS_URL", - str(self.settings["TRANSLATION_FEED_RSS"]), - ).format(lang=lang), - feed_type="rss", - ) - - def generate_articles(self, write): - """Generate the articles.""" - for article in chain( - self.translations, - self.articles, - self.hidden_translations, - self.hidden_articles, - ): - signals.article_generator_write_article.send(self, content=article) - write( - article.save_as, - self.get_template(article.template), - self.context, - article=article, - category=article.category, - override_output=hasattr(article, "override_save_as"), - url=article.url, - blog=True, - ) - - def generate_period_archives(self, write): - """Generate per-year, per-month, and per-day archives.""" - try: - template = self.get_template("period_archives") - except PelicanTemplateNotFound: - template = self.get_template("archives") - - for granularity in self.period_archives: - for period in self.period_archives[granularity]: - context = self.context.copy() - context["period"] = period["period"] - context["period_num"] = period["period_num"] - - write( - period["save_as"], - template, - context, - articles=period["articles"], - dates=period["dates"], - template_name="period_archives", - blog=True, - url=period["url"], - all_articles=self.articles, - ) - - def generate_direct_templates(self, write): - """Generate direct templates pages""" - for template in self.settings["DIRECT_TEMPLATES"]: - save_as = self.settings.get( - f"{template.upper()}_SAVE_AS", f"{template}.html" - ) - url = self.settings.get(f"{template.upper()}_URL", f"{template}.html") - if not save_as: - continue - - write( - save_as, - self.get_template(template), - self.context, - articles=self.articles, - dates=self.dates, - blog=True, - template_name=template, - page_name=os.path.splitext(save_as)[0], - url=url, - ) - - def generate_tags(self, write): - """Generate Tags pages.""" - tag_template = self.get_template("tag") - for tag, articles in self.tags.items(): - dates = [article for article in self.dates if article in articles] - write( - tag.save_as, - tag_template, - self.context, - tag=tag, - url=tag.url, - articles=articles, - dates=dates, - template_name="tag", - blog=True, - page_name=tag.page_name, - all_articles=self.articles, - ) - - def generate_categories(self, write): - """Generate category pages.""" - category_template = self.get_template("category") - for cat, articles in self.categories: - dates = [article for article in self.dates if article in articles] - write( - cat.save_as, - category_template, - self.context, - url=cat.url, - category=cat, - articles=articles, - dates=dates, - template_name="category", - blog=True, - page_name=cat.page_name, - all_articles=self.articles, - ) - - def generate_authors(self, write): - """Generate Author pages.""" - author_template = self.get_template("author") - for aut, articles in self.authors: - dates = [article for article in self.dates if article in articles] - write( - aut.save_as, - author_template, - self.context, - url=aut.url, - author=aut, - articles=articles, - dates=dates, - template_name="author", - blog=True, - page_name=aut.page_name, - all_articles=self.articles, - ) - - def generate_drafts(self, write): - """Generate drafts pages.""" - for draft in chain(self.drafts_translations, self.drafts): - write( - draft.save_as, - self.get_template(draft.template), - self.context, - article=draft, - category=draft.category, - override_output=hasattr(draft, "override_save_as"), - blog=True, - all_articles=self.articles, - url=draft.url, - ) - - def generate_pages(self, writer): - """Generate the pages on the disk""" - write = partial(writer.write_file, relative_urls=self.settings["RELATIVE_URLS"]) - - # to minimize the number of relative path stuff modification - # in writer, articles pass first - self.generate_articles(write) - self.generate_period_archives(write) - self.generate_direct_templates(write) - - # and subfolders after that - self.generate_tags(write) - self.generate_categories(write) - self.generate_authors(write) - self.generate_drafts(write) - - def check_disabled_readers(self) -> None: - self._check_disabled_readers( - self.settings["ARTICLE_PATHS"], exclude=self.settings["ARTICLE_EXCLUDES"] - ) - - def generate_context(self): - """Add the articles into the shared context""" - - all_articles = [] - all_drafts = [] - hidden_articles = [] - for f in self.get_files( - self.settings["ARTICLE_PATHS"], exclude=self.settings["ARTICLE_EXCLUDES"] - ): - article = self.get_cached_data(f, None) - if article is None: - try: - article = self.readers.read_file( - base_path=self.path, - path=f, - content_class=Article, - context=self.context, - preread_signal=signals.article_generator_preread, - preread_sender=self, - context_signal=signals.article_generator_context, - context_sender=self, - ) - except Exception as e: - logger.error( - "Could not process %s\n%s", - f, - e, - exc_info=self.settings.get("DEBUG", False), - ) - self._add_failed_source_path(f) - continue - - if isinstance(article, SkipStub): - logger.debug("Safely skipping %s", f) - continue - - if not article.is_valid(): - self._add_failed_source_path(f) - continue - - self.cache_data(f, article) - - if article.status == "published": - all_articles.append(article) - elif article.status == "draft": - all_drafts.append(article) - elif article.status == "hidden": - hidden_articles.append(article) - elif article.status == "skip": - raise AssertionError("Documents with 'skip' status should be skipped") - - self.add_source_path(article) - self.add_static_links(article) - - def _process(arts): - origs, translations = process_translations( - arts, translation_id=self.settings["ARTICLE_TRANSLATION_ID"] - ) - origs = order_content(origs, self.settings["ARTICLE_ORDER_BY"]) - return origs, translations - - self.articles, self.translations = _process(all_articles) - self.hidden_articles, self.hidden_translations = _process(hidden_articles) - self.drafts, self.drafts_translations = _process(all_drafts) - - signals.article_generator_pretaxonomy.send(self) - - for article in self.articles: - # only main articles are listed in categories and tags - # not translations or hidden articles - self.categories[article.category].append(article) - if hasattr(article, "tags"): - for tag in article.tags: - self.tags[tag].append(article) - for author in getattr(article, "authors", []): - self.authors[author].append(article) - - self.dates = list(self.articles) - self.dates.sort( - key=attrgetter("date"), reverse=self.context["NEWEST_FIRST_ARCHIVES"] - ) - - self.period_archives = self._build_period_archives( - self.dates, self.articles, self.settings - ) - - # and generate the output :) - - # order the categories per name - self.categories = list(self.categories.items()) - self.categories.sort(reverse=self.settings["REVERSE_CATEGORY_ORDER"]) - - self.authors = list(self.authors.items()) - self.authors.sort() - - self._update_context( - ( - "articles", - "drafts", - "hidden_articles", - "dates", - "tags", - "categories", - "authors", - "related_posts", - ) - ) - # _update_context flattens dicts, which should not happen to - # period_archives, so we update the context directly for it: - self.context["period_archives"] = self.period_archives - self.save_cache() - self.readers.save_cache() - signals.article_generator_finalized.send(self) - - def _build_period_archives(self, sorted_articles, articles, settings): - """ - Compute the groupings of articles, with related attributes, for - per-year, per-month, and per-day archives. - """ - - period_archives = defaultdict(list) - - period_archives_settings = { - "year": { - "save_as": settings["YEAR_ARCHIVE_SAVE_AS"], - "url": settings["YEAR_ARCHIVE_URL"], - }, - "month": { - "save_as": settings["MONTH_ARCHIVE_SAVE_AS"], - "url": settings["MONTH_ARCHIVE_URL"], - }, - "day": { - "save_as": settings["DAY_ARCHIVE_SAVE_AS"], - "url": settings["DAY_ARCHIVE_URL"], - }, - } - - granularity_key_func = { - "year": attrgetter("date.year"), - "month": attrgetter("date.year", "date.month"), - "day": attrgetter("date.year", "date.month", "date.day"), - } - - for granularity in "year", "month", "day": - save_as_fmt = period_archives_settings[granularity]["save_as"] - url_fmt = period_archives_settings[granularity]["url"] - key_func = granularity_key_func[granularity] - - if not save_as_fmt: - # the archives for this period granularity are not needed - continue - - for period, group in groupby(sorted_articles, key=key_func): - archive = {} - - dates = list(group) - archive["dates"] = dates - archive["articles"] = [a for a in articles if a in dates] - - # use the first date to specify the period archive URL - # and save_as; the specific date used does not matter as - # they all belong to the same period - d = dates[0].date - archive["save_as"] = save_as_fmt.format(date=d) - archive["url"] = url_fmt.format(date=d) - - if granularity == "year": - archive["period"] = (period,) - archive["period_num"] = (period,) - else: - month_name = calendar.month_name[period[1]] - if granularity == "month": - archive["period"] = (period[0], month_name) - else: - archive["period"] = (period[0], month_name, period[2]) - archive["period_num"] = tuple(period) - - period_archives[granularity].append(archive) - - return period_archives - - def generate_output(self, writer): - self.generate_feeds(writer) - self.generate_pages(writer) - signals.article_writer_finalized.send(self, writer=writer) - - def refresh_metadata_intersite_links(self): - for e in chain( - self.articles, - self.translations, - self.drafts, - self.drafts_translations, - self.hidden_articles, - self.hidden_translations, - ): - if hasattr(e, "refresh_metadata_intersite_links"): - e.refresh_metadata_intersite_links() - - -class PagesGenerator(CachingGenerator): - """Generate pages""" - - def __init__(self, *args, **kwargs): - self.pages = [] - self.translations = [] - self.hidden_pages = [] - self.hidden_translations = [] - self.draft_pages = [] - self.draft_translations = [] - super().__init__(*args, **kwargs) - signals.page_generator_init.send(self) - - def check_disabled_readers(self) -> None: - self._check_disabled_readers( - self.settings["PAGE_PATHS"], exclude=self.settings["PAGE_EXCLUDES"] - ) - - def generate_context(self): - all_pages = [] - hidden_pages = [] - draft_pages = [] - for f in self.get_files( - self.settings["PAGE_PATHS"], exclude=self.settings["PAGE_EXCLUDES"] - ): - page = self.get_cached_data(f, None) - if page is None: - try: - page = self.readers.read_file( - base_path=self.path, - path=f, - content_class=Page, - context=self.context, - preread_signal=signals.page_generator_preread, - preread_sender=self, - context_signal=signals.page_generator_context, - context_sender=self, - ) - except Exception as e: - logger.error( - "Could not process %s\n%s", - f, - e, - exc_info=self.settings.get("DEBUG", False), - ) - self._add_failed_source_path(f) - continue - - if isinstance(page, SkipStub): - logger.debug("Safely skipping %s", f) - continue - - if not page.is_valid(): - self._add_failed_source_path(f) - continue - - self.cache_data(f, page) - - if page.status == "published": - all_pages.append(page) - elif page.status == "hidden": - hidden_pages.append(page) - elif page.status == "draft": - draft_pages.append(page) - elif page.status == "skip": - raise AssertionError("Documents with 'skip' status should be skipped") - - self.add_source_path(page) - self.add_static_links(page) - - def _process(pages): - origs, translations = process_translations( - pages, translation_id=self.settings["PAGE_TRANSLATION_ID"] - ) - origs = order_content(origs, self.settings["PAGE_ORDER_BY"]) - return origs, translations - - self.pages, self.translations = _process(all_pages) - self.hidden_pages, self.hidden_translations = _process(hidden_pages) - self.draft_pages, self.draft_translations = _process(draft_pages) - - self._update_context(("pages", "hidden_pages", "draft_pages")) - - self.save_cache() - self.readers.save_cache() - signals.page_generator_finalized.send(self) - - def generate_output(self, writer): - for page in chain( - self.translations, - self.pages, - self.hidden_translations, - self.hidden_pages, - self.draft_translations, - self.draft_pages, - ): - signals.page_generator_write_page.send(self, content=page) - writer.write_file( - page.save_as, - self.get_template(page.template), - self.context, - page=page, - relative_urls=self.settings["RELATIVE_URLS"], - override_output=hasattr(page, "override_save_as"), - url=page.url, - ) - signals.page_writer_finalized.send(self, writer=writer) - - def refresh_metadata_intersite_links(self): - for e in chain( - self.pages, - self.hidden_pages, - self.hidden_translations, - self.draft_pages, - self.draft_translations, - ): - if hasattr(e, "refresh_metadata_intersite_links"): - e.refresh_metadata_intersite_links() - - -class StaticGenerator(Generator): - """copy static paths (what you want to copy, like images, medias etc. - to output""" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.fallback_to_symlinks = False - signals.static_generator_init.send(self) - - def check_disabled_readers(self) -> None: - self._check_disabled_readers( - self.settings["STATIC_PATHS"], exclude=self.settings["STATIC_EXCLUDES"] - ) - - def generate_context(self): - self.staticfiles = [] - linked_files = set(self.context["static_links"]) - found_files = self.get_files( - self.settings["STATIC_PATHS"], - exclude=self.settings["STATIC_EXCLUDES"], - extensions=False, - ) - for f in linked_files | found_files: - # skip content source files unless the user explicitly wants them - if self.settings["STATIC_EXCLUDE_SOURCES"]: - if self._is_potential_source_path(f): - continue - - static = self.readers.read_file( - base_path=self.path, - path=f, - content_class=Static, - fmt="static", - context=self.context, - preread_signal=signals.static_generator_preread, - preread_sender=self, - context_signal=signals.static_generator_context, - context_sender=self, - ) - self.staticfiles.append(static) - self.add_source_path(static, static=True) - self._update_context(("staticfiles",)) - signals.static_generator_finalized.send(self) - - def generate_output(self, writer): - self._copy_paths( - self.settings["THEME_STATIC_PATHS"], - self.theme, - self.settings["THEME_STATIC_DIR"], - self.output_path, - os.curdir, - ) - for sc in self.context["staticfiles"]: - if self._file_update_required(sc): - self._link_or_copy_staticfile(sc) - else: - logger.debug("%s is up to date, not copying", sc.source_path) - - def _copy_paths(self, paths, source, destination, output_path, final_path=None): - """Copy all the paths from source to destination""" - for path in paths: - source_path = os.path.join(source, path) - - if final_path: - if os.path.isfile(source_path): - destination_path = os.path.join( - output_path, destination, final_path, os.path.basename(path) - ) - else: - destination_path = os.path.join( - output_path, destination, final_path - ) - else: - destination_path = os.path.join(output_path, destination, path) - - copy(source_path, destination_path, self.settings["IGNORE_FILES"]) - - def _file_update_required(self, staticfile): - source_path = os.path.join(self.path, staticfile.source_path) - save_as = os.path.join(self.output_path, staticfile.save_as) - if not os.path.exists(save_as): - return True - elif self.settings["STATIC_CREATE_LINKS"] and os.path.samefile( - source_path, save_as - ): - return False - elif ( - self.settings["STATIC_CREATE_LINKS"] - and os.path.realpath(save_as) == source_path - ): - return False - elif not self.settings["STATIC_CHECK_IF_MODIFIED"]: - return True - else: - return self._source_is_newer(staticfile) - - def _source_is_newer(self, staticfile): - source_path = os.path.join(self.path, staticfile.source_path) - save_as = os.path.join(self.output_path, staticfile.save_as) - s_mtime = os.path.getmtime(source_path) - d_mtime = os.path.getmtime(save_as) - return s_mtime - d_mtime > 0.000001 # noqa: PLR2004 - - def _link_or_copy_staticfile(self, sc): - if self.settings["STATIC_CREATE_LINKS"]: - self._link_staticfile(sc) - else: - self._copy_staticfile(sc) - - def _copy_staticfile(self, sc): - source_path = os.path.join(self.path, sc.source_path) - save_as = os.path.join(self.output_path, sc.save_as) - self._mkdir(os.path.dirname(save_as)) - copy(source_path, save_as) - logger.info("Copying %s to %s", sc.source_path, sc.save_as) - - def _link_staticfile(self, sc): - source_path = os.path.join(self.path, sc.source_path) - save_as = os.path.join(self.output_path, sc.save_as) - self._mkdir(os.path.dirname(save_as)) - try: - if os.path.lexists(save_as): - os.unlink(save_as) - logger.info("Linking %s and %s", sc.source_path, sc.save_as) - if self.fallback_to_symlinks: - os.symlink(source_path, save_as) - else: - os.link(source_path, save_as) - except OSError as err: - if err.errno == errno.EXDEV: # 18: Invalid cross-device link - logger.debug( - "Cross-device links not valid. Creating symbolic links instead." - ) - self.fallback_to_symlinks = True - self._link_staticfile(sc) - else: - raise err - - def _mkdir(self, path): - if os.path.lexists(path) and not os.path.isdir(path): - os.unlink(path) - mkdir_p(path) - - -class SourceFileGenerator(Generator): - def generate_context(self): - self.output_extension = self.settings["OUTPUT_SOURCES_EXTENSION"] - - def _create_source(self, obj): - output_path, _ = os.path.splitext(obj.save_as) - dest = os.path.join(self.output_path, output_path + self.output_extension) - copy(obj.source_path, dest) - - def generate_output(self, writer=None): - logger.info("Generating source files...") - for obj in chain(self.context["articles"], self.context["pages"]): - self._create_source(obj) - for obj_trans in obj.translations: - self._create_source(obj_trans) diff --git a/pelican/log.py b/pelican/log.py deleted file mode 100644 index edf2f182..00000000 --- a/pelican/log.py +++ /dev/null @@ -1,174 +0,0 @@ -import logging -from collections import defaultdict - -from rich.console import Console -from rich.logging import RichHandler - -__all__ = ["init"] - -console = Console() - - -class LimitFilter(logging.Filter): - """ - Remove duplicates records, and limit the number of records in the same - group. - - Groups are specified by the message to use when the number of records in - the same group hit the limit. - E.g.: log.warning(('43 is not the answer', 'More erroneous answers')) - """ - - LOGS_DEDUP_MIN_LEVEL = logging.WARNING - - _ignore = set() - _raised_messages = set() - _threshold = 5 - _group_count = defaultdict(int) - - def filter(self, record): - # don't limit log messages for anything above "warning" - if record.levelno > self.LOGS_DEDUP_MIN_LEVEL: - return True - - # extract group - group = record.__dict__.get("limit_msg", None) - group_args = record.__dict__.get("limit_args", ()) - - # ignore record if it was already raised - message_key = (record.levelno, record.getMessage()) - if message_key in self._raised_messages: - return False - else: - self._raised_messages.add(message_key) - - # ignore LOG_FILTER records by templates or messages - # when "debug" isn't enabled - logger_level = logging.getLogger().getEffectiveLevel() - if logger_level > logging.DEBUG: - template_key = (record.levelno, record.msg) - message_key = (record.levelno, record.getMessage()) - if template_key in self._ignore or message_key in self._ignore: - return False - - # check if we went over threshold - if group: - key = (record.levelno, group) - self._group_count[key] += 1 - if self._group_count[key] == self._threshold: - record.msg = group - record.args = group_args - elif self._group_count[key] > self._threshold: - return False - return True - - -class LimitLogger(logging.Logger): - """ - A logger which adds LimitFilter automatically - """ - - limit_filter = LimitFilter() - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.enable_filter() - - def disable_filter(self): - self.removeFilter(LimitLogger.limit_filter) - - def enable_filter(self): - self.addFilter(LimitLogger.limit_filter) - - -class FatalLogger(LimitLogger): - warnings_fatal = False - errors_fatal = False - - def warning(self, *args, stacklevel=1, **kwargs): - """ - Displays a logging warning. - - Wrapping it here allows Pelican to filter warnings, and conditionally - make warnings fatal. - - Args: - stacklevel (int): the stacklevel that would be used to display the - calling location, except for this function. Adjusting the - stacklevel allows you to see the "true" calling location of the - warning, rather than this wrapper location. - """ - stacklevel += 1 - super().warning(*args, stacklevel=stacklevel, **kwargs) - if FatalLogger.warnings_fatal: - raise RuntimeError("Warning encountered") - - def error(self, *args, stacklevel=1, **kwargs): - """ - Displays a logging error. - - Wrapping it here allows Pelican to filter errors, and conditionally - make errors non-fatal. - - Args: - stacklevel (int): the stacklevel that would be used to display the - calling location, except for this function. Adjusting the - stacklevel allows you to see the "true" calling location of the - error, rather than this wrapper location. - """ - stacklevel += 1 - super().error(*args, stacklevel=stacklevel, **kwargs) - if FatalLogger.errors_fatal: - raise RuntimeError("Error encountered") - - -logging.setLoggerClass(FatalLogger) -# force root logger to be of our preferred class -logging.getLogger().__class__ = FatalLogger - -DEFAULT_LOG_HANDLER = RichHandler(console=console) - - -def init( - level=None, - fatal="", - handler=DEFAULT_LOG_HANDLER, - name=None, - logs_dedup_min_level=None, -): - FatalLogger.warnings_fatal = fatal.startswith("warning") - FatalLogger.errors_fatal = bool(fatal) - - LOG_FORMAT = "%(message)s" - logging.basicConfig( - level=level, - format=LOG_FORMAT, - datefmt="[%H:%M:%S]", - handlers=[handler] if handler else [], - ) - - logger = logging.getLogger(name) - - if level: - logger.setLevel(level) - if logs_dedup_min_level: - LimitFilter.LOGS_DEDUP_MIN_LEVEL = logs_dedup_min_level - - -def log_warnings(): - import warnings - - logging.captureWarnings(True) - warnings.simplefilter("default", DeprecationWarning) - init(logging.DEBUG, name="py.warnings") - - -if __name__ == "__main__": - init(level=logging.DEBUG, name=__name__) - - root_logger = logging.getLogger(__name__) - root_logger.debug("debug") - root_logger.info("info") - root_logger.warning("warning") - root_logger.error("error") - root_logger.critical("critical") diff --git a/pelican/paginator.py b/pelican/paginator.py deleted file mode 100644 index 4a7c1aa2..00000000 --- a/pelican/paginator.py +++ /dev/null @@ -1,171 +0,0 @@ -import functools -import logging -import os -from collections import namedtuple -from math import ceil - -logger = logging.getLogger(__name__) -PaginationRule = namedtuple( # noqa: PYI024 - "PaginationRule", - "min_page URL SAVE_AS", -) - - -class Paginator: - def __init__(self, name, url, object_list, settings, per_page=None): - self.name = name - self.url = url - self.object_list = object_list - self.settings = settings - if per_page: - self.per_page = per_page - self.orphans = settings["DEFAULT_ORPHANS"] - else: - self.per_page = len(object_list) - self.orphans = 0 - - self._num_pages = self._count = None - - def page(self, number): - "Returns a Page object for the given 1-based page number." - bottom = (number - 1) * self.per_page - top = bottom + self.per_page - if top + self.orphans >= self.count: - top = self.count - return Page( - self.name, - self.url, - self.object_list[bottom:top], - number, - self, - self.settings, - ) - - def _get_count(self): - "Returns the total number of objects, across all pages." - if self._count is None: - self._count = len(self.object_list) - return self._count - - count = property(_get_count) - - def _get_num_pages(self): - "Returns the total number of pages." - if self._num_pages is None: - hits = max(1, self.count - self.orphans) - self._num_pages = int(ceil(hits / (float(self.per_page) or 1))) - return self._num_pages - - num_pages = property(_get_num_pages) - - def _get_page_range(self): - """ - Returns a 1-based range of pages for iterating through within - a template for loop. - """ - return list(range(1, self.num_pages + 1)) - - page_range = property(_get_page_range) - - -class Page: - def __init__(self, name, url, object_list, number, paginator, settings): - self.full_name = name - self.name, self.extension = os.path.splitext(name) - dn, fn = os.path.split(name) - self.base_name = dn if fn in ("index.htm", "index.html") else self.name - self.base_url = url - self.object_list = object_list - self.number = number - self.paginator = paginator - self.settings = settings - - def __repr__(self): - return f"" - - def has_next(self): - return self.number < self.paginator.num_pages - - def has_previous(self): - return self.number > 1 - - def has_other_pages(self): - return self.has_previous() or self.has_next() - - def next_page_number(self): - return self.number + 1 - - def previous_page_number(self): - return self.number - 1 - - def start_index(self): - """ - Returns the 1-based index of the first object on this page, - relative to total objects in the paginator. - """ - # Special case, return zero if no items. - if self.paginator.count == 0: - return 0 - return (self.paginator.per_page * (self.number - 1)) + 1 - - def end_index(self): - """ - Returns the 1-based index of the last object on this page, - relative to total objects found (hits). - """ - # Special case for the last page because there can be orphans. - if self.number == self.paginator.num_pages: - return self.paginator.count - return self.number * self.paginator.per_page - - def _from_settings(self, key): - """Returns URL information as defined in settings. Similar to - URLWrapper._from_settings, but specialized to deal with pagination - logic.""" - - rule = None - - # find the last matching pagination rule - for p in self.settings["PAGINATION_PATTERNS"]: - if p.min_page == -1: - if not self.has_next(): - rule = p - break - elif p.min_page <= self.number: - rule = p - - if not rule: - return "" - - prop_value = getattr(rule, key) - - if not isinstance(prop_value, str): - logger.warning("%s is set to %s", key, prop_value) - return prop_value - - # URL or SAVE_AS is a string, format it with a controlled context - context = { - "save_as": self.full_name, - "url": self.base_url, - "name": self.name, - "base_name": self.base_name, - "extension": self.extension, - "number": self.number, - } - - ret = prop_value.format(**context) - # Remove a single leading slash, if any. This is done for backwards - # compatibility reasons. If a leading slash is needed (for URLs - # relative to server root or absolute URLs without the scheme such as - # //blog.my.site/), it can be worked around by prefixing the pagination - # pattern by an additional slash (which then gets removed, preserving - # the other slashes). This also means the following code *can't* be - # changed to lstrip() because that would remove all leading slashes and - # thus make the workaround impossible. See - # test_custom_pagination_pattern() for a verification of this. - if ret.startswith("/"): - ret = ret[1:] - return ret - - url = property(functools.partial(_from_settings, key="URL")) - save_as = property(functools.partial(_from_settings, key="SAVE_AS")) diff --git a/pelican/plugins/_utils.py b/pelican/plugins/_utils.py deleted file mode 100644 index 9dfc8f81..00000000 --- a/pelican/plugins/_utils.py +++ /dev/null @@ -1,138 +0,0 @@ -import importlib -import importlib.machinery -import importlib.util -import inspect -import logging -import pkgutil -import sys - -logger = logging.getLogger(__name__) - - -def iter_namespace(ns_pkg): - # Specifying the second argument (prefix) to iter_modules makes the - # returned name an absolute name instead of a relative one. This allows - # import_module to work without having to do additional modification to - # the name. - return pkgutil.iter_modules(ns_pkg.__path__, ns_pkg.__name__ + ".") - - -def get_namespace_plugins(ns_pkg=None): - if ns_pkg is None: - import pelican.plugins as ns_pkg - - return { - name: importlib.import_module(name) - for finder, name, ispkg in iter_namespace(ns_pkg) - if ispkg - } - - -def list_plugins(ns_pkg=None): - from pelican.log import init as init_logging - - init_logging(logging.INFO) - ns_plugins = get_namespace_plugins(ns_pkg) - if ns_plugins: - logger.info("Plugins found:\n" + "\n".join(ns_plugins)) - else: - logger.info("No plugins are installed") - - -def plugin_enabled(name, plugin_list=None): - if plugin_list is None or not plugin_list: - # no plugins are loaded - return False - - if name in plugin_list: - # search name as is - return True - - if f"pelican.plugins.{name}" in plugin_list: - # check if short name is a namespace plugin - return True - - return False - - -def load_legacy_plugin(plugin, plugin_paths): - if "." in plugin: - # it is in a package, try to resolve package first - package, _, _ = plugin.rpartition(".") - load_legacy_plugin(package, plugin_paths) - - # Try to find plugin in PLUGIN_PATHS - spec = importlib.machinery.PathFinder.find_spec(plugin, plugin_paths) - if spec is None: - # If failed, try to find it in normal importable locations - spec = importlib.util.find_spec(plugin) - if spec is None: - raise ImportError(f"Cannot import plugin `{plugin}`") - else: - # Avoid loading the same plugin twice - if spec.name in sys.modules: - return sys.modules[spec.name] - # create module object from spec - mod = importlib.util.module_from_spec(spec) - # place it into sys.modules cache - # necessary if module imports itself at some point (e.g. packages) - sys.modules[spec.name] = mod - try: - # try to execute it inside module object - spec.loader.exec_module(mod) - except Exception: # problem with import - try: - # remove module from sys.modules since it can't be loaded - del sys.modules[spec.name] - except KeyError: - pass - raise - - # if all went well, we have the plugin module - return mod - - -def load_plugins(settings): - logger.debug("Finding namespace plugins") - namespace_plugins = get_namespace_plugins() - if namespace_plugins: - logger.debug("Namespace plugins found:\n" + "\n".join(namespace_plugins)) - plugins = [] - if settings.get("PLUGINS") is not None: - for plugin in settings["PLUGINS"]: - if isinstance(plugin, str): - logger.debug("Loading plugin `%s`", plugin) - # try to find in namespace plugins - if plugin in namespace_plugins: - plugin = namespace_plugins[plugin] - elif f"pelican.plugins.{plugin}" in namespace_plugins: - plugin = namespace_plugins[f"pelican.plugins.{plugin}"] - # try to import it - else: - try: - plugin = load_legacy_plugin( - plugin, settings.get("PLUGIN_PATHS", []) - ) - except ImportError as e: - logger.error("Cannot load plugin `%s`\n%s", plugin, e) - continue - plugins.append(plugin) - else: - plugins = list(namespace_plugins.values()) - - return plugins - - -def get_plugin_name(plugin): - """ - Plugins can be passed as module objects, however this breaks caching as - module objects cannot be pickled. To work around this, all plugins are - stringified post-initialization. - """ - if inspect.isclass(plugin): - return plugin.__qualname__ - - if inspect.ismodule(plugin): - return plugin.__name__ - - return type(plugin).__qualname__ diff --git a/pelican/plugins/signals.py b/pelican/plugins/signals.py deleted file mode 100644 index c36f595d..00000000 --- a/pelican/plugins/signals.py +++ /dev/null @@ -1,53 +0,0 @@ -from blinker import Signal, signal -from ordered_set import OrderedSet - -# Signals will call functions in the order of connection, i.e. plugin order -Signal.set_class = OrderedSet - -# Run-level signals: - -initialized = signal("pelican_initialized") -get_generators = signal("get_generators") -all_generators_finalized = signal("all_generators_finalized") -get_writer = signal("get_writer") -finalized = signal("pelican_finalized") - -# Reader-level signals - -readers_init = signal("readers_init") - -# Generator-level signals - -generator_init = signal("generator_init") - -article_generator_init = signal("article_generator_init") -article_generator_pretaxonomy = signal("article_generator_pretaxonomy") -article_generator_finalized = signal("article_generator_finalized") -article_generator_write_article = signal("article_generator_write_article") -article_writer_finalized = signal("article_writer_finalized") - -page_generator_init = signal("page_generator_init") -page_generator_finalized = signal("page_generator_finalized") -page_generator_write_page = signal("page_generator_write_page") -page_writer_finalized = signal("page_writer_finalized") - -static_generator_init = signal("static_generator_init") -static_generator_finalized = signal("static_generator_finalized") - -# Page-level signals - -article_generator_preread = signal("article_generator_preread") -article_generator_context = signal("article_generator_context") - -page_generator_preread = signal("page_generator_preread") -page_generator_context = signal("page_generator_context") - -static_generator_preread = signal("static_generator_preread") -static_generator_context = signal("static_generator_context") - -content_object_init = signal("content_object_init") - -# Writers signals -content_written = signal("content_written") -feed_generated = signal("feed_generated") -feed_written = signal("feed_written") diff --git a/pelican/readers.py b/pelican/readers.py deleted file mode 100644 index 59aa7ca3..00000000 --- a/pelican/readers.py +++ /dev/null @@ -1,811 +0,0 @@ -import datetime -import logging -import os -import re -from collections import OrderedDict -from html import escape -from html.parser import HTMLParser -from io import StringIO - -import docutils -import docutils.core -import docutils.io -from docutils.parsers.rst.languages import get_language as get_docutils_lang -from docutils.writers.html4css1 import HTMLTranslator, Writer - -from pelican import rstdirectives # NOQA -from pelican.cache import FileStampDataCacher -from pelican.contents import Author, Category, Page, SkipStub, Tag -from pelican.plugins import signals -from pelican.utils import file_suffix, get_date, pelican_open, posixize_path - -try: - from markdown import Markdown -except ImportError: - Markdown = False - -# Metadata processors have no way to discard an unwanted value, so we have -# them return this value instead to signal that it should be discarded later. -# This means that _filter_discardable_metadata() must be called on processed -# metadata dicts before use, to remove the items with the special value. -_DISCARD = object() - -DUPLICATES_DEFINITIONS_ALLOWED = { - "tags": False, - "date": False, - "modified": False, - "status": False, - "category": False, - "author": False, - "save_as": False, - "url": False, - "authors": False, - "slug": False, -} - -METADATA_PROCESSORS = { - "tags": lambda x, y: ([Tag(tag, y) for tag in ensure_metadata_list(x)] or _DISCARD), - "date": lambda x, y: get_date(x.replace("_", " ")), - "modified": lambda x, y: get_date(x), - "status": lambda x, y: x.strip() or _DISCARD, - "category": lambda x, y: _process_if_nonempty(Category, x, y), - "author": lambda x, y: _process_if_nonempty(Author, x, y), - "authors": lambda x, y: ( - [Author(author, y) for author in ensure_metadata_list(x)] or _DISCARD - ), - "slug": lambda x, y: x.strip() or _DISCARD, -} - -logger = logging.getLogger(__name__) - - -def ensure_metadata_list(text): - """Canonicalize the format of a list of authors or tags. This works - the same way as Docutils' "authors" field: if it's already a list, - those boundaries are preserved; otherwise, it must be a string; - if the string contains semicolons, it is split on semicolons; - otherwise, it is split on commas. This allows you to write - author lists in either "Jane Doe, John Doe" or "Doe, Jane; Doe, John" - format. - - Regardless, all list items undergo .strip() before returning, and - empty items are discarded. - """ - if isinstance(text, str): - if ";" in text: - text = text.split(";") - else: - text = text.split(",") - - return list(OrderedDict.fromkeys([v for v in (w.strip() for w in text) if v])) - - -def _process_if_nonempty(processor, name, settings): - """Removes extra whitespace from name and applies a metadata processor. - If name is empty or all whitespace, returns _DISCARD instead. - """ - name = name.strip() - return processor(name, settings) if name else _DISCARD - - -def _filter_discardable_metadata(metadata): - """Return a copy of a dict, minus any items marked as discardable.""" - return {name: val for name, val in metadata.items() if val is not _DISCARD} - - -class BaseReader: - """Base class to read files. - - This class is used to process static files, and it can be inherited for - other types of file. A Reader class must have the following attributes: - - - enabled: (boolean) tell if the Reader class is enabled. It - generally depends on the import of some dependency. - - file_extensions: a list of file extensions that the Reader will process. - - extensions: a list of extensions to use in the reader (typical use is - Markdown). - - """ - - enabled = True - file_extensions = ["static"] - extensions = None - - def __init__(self, settings): - self.settings = settings - - def process_metadata(self, name, value): - if name in METADATA_PROCESSORS: - return METADATA_PROCESSORS[name](value, self.settings) - return value - - def read(self, source_path): - "No-op parser" - content = None - metadata = {} - return content, metadata - - def disabled_message(self) -> str: - """Message about why this plugin was disabled.""" - return "" - - -class _FieldBodyTranslator(HTMLTranslator): - def __init__(self, document): - super().__init__(document) - self.compact_p = None - - def astext(self): - return "".join(self.body) - - def visit_field_body(self, node): - pass - - def depart_field_body(self, node): - pass - - -def render_node_to_html(document, node, field_body_translator_class): - visitor = field_body_translator_class(document) - node.walkabout(visitor) - return visitor.astext() - - -class PelicanHTMLWriter(Writer): - def __init__(self): - super().__init__() - self.translator_class = PelicanHTMLTranslator - - -class PelicanHTMLTranslator(HTMLTranslator): - def visit_abbreviation(self, node): - attrs = {} - if node.hasattr("explanation"): - attrs["title"] = node["explanation"] - self.body.append(self.starttag(node, "abbr", "", **attrs)) - - def depart_abbreviation(self, node): - self.body.append("") - - def visit_image(self, node): - # set an empty alt if alt is not specified - # avoids that alt is taken from src - node["alt"] = node.get("alt", "") - return HTMLTranslator.visit_image(self, node) - - -class RstReader(BaseReader): - """Reader for reStructuredText files - - By default the output HTML is written using - docutils.writers.html4css1.Writer and translated using a subclass of - docutils.writers.html4css1.HTMLTranslator. If you want to override it with - your own writer/translator (e.g. a HTML5-based one), pass your classes to - these two attributes. Look in the source code for details. - - writer_class Used for writing contents - field_body_translator_class Used for translating metadata such - as article summary - - """ - - enabled = bool(docutils) - file_extensions = ["rst"] - - writer_class = PelicanHTMLWriter - field_body_translator_class = _FieldBodyTranslator - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - lang_code = self.settings.get("DEFAULT_LANG", "en") - if get_docutils_lang(lang_code): - self._language_code = lang_code - else: - logger.warning( - "Docutils has no localization for '%s'. Using 'en' instead.", - lang_code, - ) - self._language_code = "en" - - def _parse_metadata(self, document, source_path): - """Return the dict containing document metadata""" - formatted_fields = self.settings["FORMATTED_FIELDS"] - - output = {} - - if document.first_child_matching_class(docutils.nodes.title) is None: - logger.warning( - "Document title missing in file %s: " - "Ensure exactly one top level section", - source_path, - ) - - try: - # docutils 0.18.1+ - nodes = document.findall(docutils.nodes.docinfo) - except AttributeError: - # docutils 0.18.0 or before - nodes = document.traverse(docutils.nodes.docinfo) - - for docinfo in nodes: - for element in docinfo.children: - if element.tagname == "field": # custom fields (e.g. summary) - name_elem, body_elem = element.children - name = name_elem.astext() - if name.lower() in formatted_fields: - value = render_node_to_html( - document, body_elem, self.field_body_translator_class - ) - else: - value = body_elem.astext() - elif element.tagname == "authors": # author list - name = element.tagname - value = [element.astext() for element in element.children] - else: # standard fields (e.g. address) - name = element.tagname - value = element.astext() - name = name.lower() - - output[name] = self.process_metadata(name, value) - return output - - def _get_publisher(self, source_path): - extra_params = { - "initial_header_level": "2", - "syntax_highlight": "short", - "input_encoding": "utf-8", - "language_code": self._language_code, - "halt_level": 2, - "traceback": True, - "warning_stream": StringIO(), - "embed_stylesheet": False, - } - user_params = self.settings.get("DOCUTILS_SETTINGS") - if user_params: - extra_params.update(user_params) - - pub = docutils.core.Publisher( - writer=self.writer_class(), destination_class=docutils.io.StringOutput - ) - pub.set_components("standalone", "restructuredtext", "html") - pub.process_programmatic_settings(None, extra_params, None) - pub.set_source(source_path=source_path) - pub.publish() - return pub - - def read(self, source_path): - """Parses restructured text""" - pub = self._get_publisher(source_path) - parts = pub.writer.parts - content = parts.get("body") - - metadata = self._parse_metadata(pub.document, source_path) - metadata.setdefault("title", parts.get("title")) - - return content, metadata - - -class MarkdownReader(BaseReader): - """Reader for Markdown files""" - - enabled = bool(Markdown) - file_extensions = ["md", "markdown", "mkd", "mdown"] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - settings = self.settings["MARKDOWN"] - settings.setdefault("extension_configs", {}) - settings.setdefault("extensions", []) - for extension in settings["extension_configs"].keys(): - if extension not in settings["extensions"]: - settings["extensions"].append(extension) - if "markdown.extensions.meta" not in settings["extensions"]: - settings["extensions"].append("markdown.extensions.meta") - self._source_path = None - - def _parse_metadata(self, meta): - """Return the dict containing document metadata""" - formatted_fields = self.settings["FORMATTED_FIELDS"] - - # prevent metadata extraction in fields - self._md.preprocessors.deregister("meta") - - output = {} - for name, value in meta.items(): - name = name.lower() - if name in formatted_fields: - # formatted metadata is special case and join all list values - formatted_values = "\n".join(value) - # reset the markdown instance to clear any state - self._md.reset() - formatted = self._md.convert(formatted_values) - output[name] = self.process_metadata(name, formatted) - elif not DUPLICATES_DEFINITIONS_ALLOWED.get(name, True): - if len(value) > 1: - logger.warning( - "Duplicate definition of `%s` for %s. Using first one.", - name, - self._source_path, - ) - output[name] = self.process_metadata(name, value[0]) - elif len(value) > 1: - # handle list metadata as list of string - output[name] = self.process_metadata(name, value) - else: - # otherwise, handle metadata as single string - output[name] = self.process_metadata(name, value[0]) - return output - - def read(self, source_path): - """Parse content and metadata of markdown files""" - - self._source_path = source_path - self._md = Markdown(**self.settings["MARKDOWN"]) - with pelican_open(source_path) as text: - content = self._md.convert(text) - - if hasattr(self._md, "Meta"): - metadata = self._parse_metadata(self._md.Meta) - else: - metadata = {} - return content, metadata - - def disabled_message(self) -> str: - return ( - "Could not import 'markdown.Markdown'. " - "Have you installed the 'markdown' package?" - ) - - -class HTMLReader(BaseReader): - """Parses HTML files as input, looking for meta, title, and body tags""" - - file_extensions = ["htm", "html"] - enabled = True - - class _HTMLParser(HTMLParser): - def __init__(self, settings, filename): - super().__init__(convert_charrefs=False) - self.body = "" - self.metadata = {} - self.settings = settings - - self._data_buffer = "" - - self._filename = filename - - self._in_top_level = True - self._in_head = False - self._in_title = False - self._in_body = False - self._in_tags = False - - def handle_starttag(self, tag, attrs): - if tag == "head" and self._in_top_level: - self._in_top_level = False - self._in_head = True - elif tag == "title" and self._in_head: - self._in_title = True - self._data_buffer = "" - elif tag == "body" and self._in_top_level: - self._in_top_level = False - self._in_body = True - self._data_buffer = "" - elif tag == "meta" and self._in_head: - self._handle_meta_tag(attrs) - - elif self._in_body: - self._data_buffer += self.build_tag(tag, attrs, False) - - def handle_endtag(self, tag): - if tag == "head": - if self._in_head: - self._in_head = False - self._in_top_level = True - elif self._in_head and tag == "title": - self._in_title = False - self.metadata["title"] = self._data_buffer - elif tag == "body": - self.body = self._data_buffer - self._in_body = False - self._in_top_level = True - elif self._in_body: - self._data_buffer += f"" - - def handle_startendtag(self, tag, attrs): - if tag == "meta" and self._in_head: - self._handle_meta_tag(attrs) - if self._in_body: - self._data_buffer += self.build_tag(tag, attrs, True) - - def handle_comment(self, data): - self._data_buffer += f"" - - def handle_data(self, data): - self._data_buffer += data - - def handle_entityref(self, data): - self._data_buffer += f"&{data};" - - def handle_charref(self, data): - self._data_buffer += f"&#{data};" - - def build_tag(self, tag, attrs, close_tag): - result = f"<{escape(tag)}" - for k, v in attrs: - result += " " + escape(k) - if v is not None: - # If the attribute value contains a double quote, surround - # with single quotes, otherwise use double quotes. - if '"' in v: - result += f"='{escape(v, quote=False)}'" - else: - result += f'="{escape(v, quote=False)}"' - if close_tag: - return result + " />" - return result + ">" - - def _handle_meta_tag(self, attrs): - name = self._attr_value(attrs, "name") - if name is None: - attr_list = [f'{k}="{v}"' for k, v in attrs] - attr_serialized = ", ".join(attr_list) - logger.warning( - "Meta tag in file %s does not have a 'name' " - "attribute, skipping. Attributes: %s", - self._filename, - attr_serialized, - ) - return - name = name.lower() - contents = self._attr_value(attrs, "content", "") - if not contents: - contents = self._attr_value(attrs, "contents", "") - if contents: - logger.warning( - "Meta tag attribute 'contents' used in file %s, should" - " be changed to 'content'", - self._filename, - extra={ - "limit_msg": "Other files have meta tag " - "attribute 'contents' that should " - "be changed to 'content'" - }, - ) - - if name == "keywords": - name = "tags" - - if name in self.metadata: - # if this metadata already exists (i.e. a previous tag with the - # same name has already been specified then either convert to - # list or append to list - if isinstance(self.metadata[name], list): - self.metadata[name].append(contents) - else: - self.metadata[name] = [self.metadata[name], contents] - else: - self.metadata[name] = contents - - @classmethod - def _attr_value(cls, attrs, name, default=None): - return next((x[1] for x in attrs if x[0] == name), default) - - def read(self, filename): - """Parse content and metadata of HTML files""" - with pelican_open(filename) as content: - parser = self._HTMLParser(self.settings, filename) - parser.feed(content) - parser.close() - - metadata = {} - for k in parser.metadata: - metadata[k] = self.process_metadata(k, parser.metadata[k]) - return parser.body, metadata - - -class Readers(FileStampDataCacher): - """Interface for all readers. - - This class contains a mapping of file extensions / Reader classes, to know - which Reader class must be used to read a file (based on its extension). - This is customizable both with the 'READERS' setting, and with the - 'readers_init' signall for plugins. - - """ - - def __init__(self, settings=None, cache_name=""): - self.settings = settings or {} - self.readers = {} - self.disabled_readers = {} - # extension => reader for readers that are enabled - self.reader_classes = {} - # extension => reader for readers that are not enabled - disabled_reader_classes = {} - - for cls in [BaseReader] + BaseReader.__subclasses__(): - if not cls.enabled: - logger.debug( - "Missing dependencies for %s", ", ".join(cls.file_extensions) - ) - - for ext in cls.file_extensions: - if cls.enabled: - self.reader_classes[ext] = cls - else: - disabled_reader_classes[ext] = cls - - if self.settings["READERS"]: - self.reader_classes.update(self.settings["READERS"]) - - signals.readers_init.send(self) - - for fmt, reader_class in self.reader_classes.items(): - if not reader_class: - continue - - self.readers[fmt] = reader_class(self.settings) - - for fmt, reader_class in disabled_reader_classes.items(): - self.disabled_readers[fmt] = reader_class(self.settings) - - # set up caching - cache_this_level = ( - cache_name != "" and self.settings["CONTENT_CACHING_LAYER"] == "reader" - ) - caching_policy = cache_this_level and self.settings["CACHE_CONTENT"] - load_policy = cache_this_level and self.settings["LOAD_CONTENT_CACHE"] - super().__init__(settings, cache_name, caching_policy, load_policy) - - @property - def extensions(self): - """File extensions that will be processed by a reader.""" - return self.readers.keys() - - @property - def disabled_extensions(self): - return self.disabled_readers.keys() - - def read_file( - self, - base_path, - path, - content_class=Page, - fmt=None, - context=None, - preread_signal=None, - preread_sender=None, - context_signal=None, - context_sender=None, - ): - """Return a content object parsed with the given format.""" - - path = os.path.abspath(os.path.join(base_path, path)) - source_path = posixize_path(os.path.relpath(path, base_path)) - logger.debug("Read file %s -> %s", source_path, content_class.__name__) - - if not fmt: - fmt = file_suffix(path) - - if fmt not in self.readers: - raise TypeError("Pelican does not know how to parse %s", path) - - if preread_signal: - logger.debug("Signal %s.send(%s)", preread_signal.name, preread_sender) - preread_signal.send(preread_sender) - - reader = self.readers[fmt] - - metadata = _filter_discardable_metadata( - default_metadata(settings=self.settings, process=reader.process_metadata) - ) - metadata.update( - path_metadata( - full_path=path, source_path=source_path, settings=self.settings - ) - ) - metadata.update( - _filter_discardable_metadata( - parse_path_metadata( - source_path=source_path, - settings=self.settings, - process=reader.process_metadata, - ) - ) - ) - reader_name = reader.__class__.__name__ - metadata["reader"] = reader_name.replace("Reader", "").lower() - - content, reader_metadata = self.get_cached_data(path, (None, None)) - if content is None: - content, reader_metadata = reader.read(path) - reader_metadata = _filter_discardable_metadata(reader_metadata) - self.cache_data(path, (content, reader_metadata)) - metadata.update(reader_metadata) - - if content: - # find images with empty alt - find_empty_alt(content, path) - - # eventually filter the content with typogrify if asked so - if self.settings["TYPOGRIFY"]: - import smartypants - from typogrify.filters import typogrify - - typogrify_dashes = self.settings["TYPOGRIFY_DASHES"] - if typogrify_dashes == "oldschool": - smartypants.Attr.default = smartypants.Attr.set2 - elif typogrify_dashes == "oldschool_inverted": - smartypants.Attr.default = smartypants.Attr.set3 - else: - smartypants.Attr.default = smartypants.Attr.set1 - - # Tell `smartypants` to also replace " HTML entities with - # smart quotes. This is necessary because Docutils has already - # replaced double quotes with said entities by the time we run - # this filter. - smartypants.Attr.default |= smartypants.Attr.w - - def typogrify_wrapper(text): - """Ensures ignore_tags feature is backward compatible""" - try: - return typogrify(text, self.settings["TYPOGRIFY_IGNORE_TAGS"]) - except TypeError: - return typogrify(text) - - if content: - content = typogrify_wrapper(content) - - if "title" in metadata: - metadata["title"] = typogrify_wrapper(metadata["title"]) - - if "summary" in metadata: - metadata["summary"] = typogrify_wrapper(metadata["summary"]) - - if context_signal: - logger.debug( - "Signal %s.send(%s, )", context_signal.name, context_sender - ) - context_signal.send(context_sender, metadata=metadata) - - if metadata.get("status") == "skip": - content_class = SkipStub - - return content_class( - content=content, - metadata=metadata, - settings=self.settings, - source_path=path, - context=context, - ) - - def check_file(self, source_path: str) -> None: - """Log a warning if a file is processed by a disabled reader.""" - reader = self.disabled_readers.get(file_suffix(source_path), None) - if reader: - logger.warning(f"{source_path}: {reader.disabled_message()}") - - -def find_empty_alt(content, path): - """Find images with empty alt - - Create warnings for all images with empty alt (up to a certain number), - as they are really likely to be accessibility flaws. - - """ - imgs = re.compile( - r""" - (?: - # src before alt - ]* - src=(['"])(.*?)\1 - [^\>]* - alt=(['"])\3 - )|(?: - # alt before src - ]* - alt=(['"])\4 - [^\>]* - src=(['"])(.*?)\5 - ) - """, - re.X, - ) - for match in re.findall(imgs, content): - logger.warning( - "Empty alt attribute for image %s in %s", - os.path.basename(match[1] + match[5]), - path, - extra={"limit_msg": "Other images have empty alt attributes"}, - ) - - -def default_metadata(settings=None, process=None): - metadata = {} - if settings: - for name, value in dict(settings.get("DEFAULT_METADATA", {})).items(): - if process: - value = process(name, value) - metadata[name] = value - if "DEFAULT_CATEGORY" in settings: - value = settings["DEFAULT_CATEGORY"] - if process: - value = process("category", value) - metadata["category"] = value - if settings.get("DEFAULT_DATE", None) and settings["DEFAULT_DATE"] != "fs": - if isinstance(settings["DEFAULT_DATE"], str): - metadata["date"] = get_date(settings["DEFAULT_DATE"]) - else: - metadata["date"] = datetime.datetime(*settings["DEFAULT_DATE"]) - return metadata - - -def path_metadata(full_path, source_path, settings=None): - metadata = {} - if settings: - if settings.get("DEFAULT_DATE", None) == "fs": - metadata["date"] = datetime.datetime.fromtimestamp( - os.stat(full_path).st_mtime - ) - metadata["modified"] = metadata["date"] - - # Apply EXTRA_PATH_METADATA for the source path and the paths of any - # parent directories. Sorting EPM first ensures that the most specific - # path wins conflicts. - - epm = settings.get("EXTRA_PATH_METADATA", {}) - for path, meta in sorted(epm.items()): - # Enforce a trailing slash when checking for parent directories. - # This prevents false positives when one file or directory's name - # is a prefix of another's. - dirpath = posixize_path(os.path.join(path, "")) - if source_path == path or source_path.startswith(dirpath): - metadata.update(meta) - - return metadata - - -def parse_path_metadata(source_path, settings=None, process=None): - r"""Extract a metadata dictionary from a file's path - - >>> import pprint - >>> settings = { - ... 'FILENAME_METADATA': r'(?P[^.]*).*', - ... 'PATH_METADATA': - ... r'(?P[^/]*)/(?P\d{4}-\d{2}-\d{2})/.*', - ... } - >>> reader = BaseReader(settings=settings) - >>> metadata = parse_path_metadata( - ... source_path='my-cat/2013-01-01/my-slug.html', - ... settings=settings, - ... process=reader.process_metadata) - >>> pprint.pprint(metadata) # doctest: +ELLIPSIS - {'category': , - 'date': datetime.datetime(2013, 1, 1, 0, 0), - 'slug': 'my-slug'} - """ - metadata = {} - dirname, basename = os.path.split(source_path) - base, ext = os.path.splitext(basename) - subdir = os.path.basename(dirname) - if settings: - checks = [] - for key, data in [("FILENAME_METADATA", base), ("PATH_METADATA", source_path)]: - checks.append((settings.get(key, None), data)) - if settings.get("USE_FOLDER_AS_CATEGORY", None): - checks.append(("(?P.*)", subdir)) - for regexp, data in checks: - if regexp and data: - match = re.match(regexp, data) - if match: - # .items() for py3k compat. - for k, v in match.groupdict().items(): - k = k.lower() # metadata must be lowercase - if v is not None and k not in metadata: - if process: - v = process(k, v) - metadata[k] = v - return metadata diff --git a/pelican/rstdirectives.py b/pelican/rstdirectives.py deleted file mode 100644 index 9022ac83..00000000 --- a/pelican/rstdirectives.py +++ /dev/null @@ -1,91 +0,0 @@ -import re - -from docutils import nodes, utils -from docutils.parsers.rst import Directive, directives, roles -from pygments import highlight -from pygments.formatters import HtmlFormatter -from pygments.lexers import TextLexer, get_lexer_by_name - -import pelican.settings as pys - - -class Pygments(Directive): - """Source code syntax highlighting.""" - - required_arguments = 1 - optional_arguments = 0 - final_argument_whitespace = True - option_spec = { - "anchorlinenos": directives.flag, - "classprefix": directives.unchanged, - "hl_lines": directives.unchanged, - "lineanchors": directives.unchanged, - "linenos": directives.unchanged, - "linenospecial": directives.nonnegative_int, - "linenostart": directives.nonnegative_int, - "linenostep": directives.nonnegative_int, - "lineseparator": directives.unchanged, - "linespans": directives.unchanged, - "nobackground": directives.flag, - "nowrap": directives.flag, - "tagsfile": directives.unchanged, - "tagurlformat": directives.unchanged, - } - has_content = True - - def run(self): - self.assert_has_content() - try: - lexer = get_lexer_by_name(self.arguments[0]) - except ValueError: - # no lexer found - use the text one instead of an exception - lexer = TextLexer() - - # Fetch the defaults - if pys.PYGMENTS_RST_OPTIONS is not None: - for k, v in pys.PYGMENTS_RST_OPTIONS.items(): - # Locally set options overrides the defaults - if k not in self.options: - self.options[k] = v - - if "linenos" in self.options and self.options["linenos"] not in ( - "table", - "inline", - ): - if self.options["linenos"] == "none": - self.options.pop("linenos") - else: - self.options["linenos"] = "table" - - for flag in ("nowrap", "nobackground", "anchorlinenos"): - if flag in self.options: - self.options[flag] = True - - # noclasses should already default to False, but just in case... - formatter = HtmlFormatter(noclasses=False, **self.options) - parsed = highlight("\n".join(self.content), lexer, formatter) - return [nodes.raw("", parsed, format="html")] - - -directives.register_directive("code-block", Pygments) -directives.register_directive("sourcecode", Pygments) - - -_abbr_re = re.compile(r"\((.*)\)$", re.DOTALL) - - -class abbreviation(nodes.Inline, nodes.TextElement): - pass - - -def abbr_role(typ, rawtext, text, lineno, inliner, options=None, content=None): - text = utils.unescape(text) - m = _abbr_re.search(text) - if m is None: - return [abbreviation(text, text)], [] - abbr = text[: m.start()].strip() - expl = m.group(1) - return [abbreviation(abbr, abbr, explanation=expl)], [] - - -roles.register_local_role("abbr", abbr_role) diff --git a/pelican/server.py b/pelican/server.py deleted file mode 100644 index ebf13677..00000000 --- a/pelican/server.py +++ /dev/null @@ -1,166 +0,0 @@ -import argparse -import logging -import os -import posixpath -import ssl -import sys -import urllib -from http import server - -try: - from magic import from_file as magic_from_file -except ImportError: - magic_from_file = None - -from pelican.log import console # noqa: F401 -from pelican.log import init as init_logging - -logger = logging.getLogger(__name__) - - -def parse_arguments(): - parser = argparse.ArgumentParser( - description="Pelican Development Server", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "port", default=8000, type=int, nargs="?", help="Port to Listen On" - ) - parser.add_argument("server", default="", nargs="?", help="Interface to Listen On") - parser.add_argument("--ssl", action="store_true", help="Activate SSL listener") - parser.add_argument( - "--cert", - default="./cert.pem", - nargs="?", - help="Path to certificate file. Relative to current directory", - ) - parser.add_argument( - "--key", - default="./key.pem", - nargs="?", - help="Path to certificate key file. Relative to current directory", - ) - parser.add_argument( - "--path", - default=".", - help="Path to pelican source directory to serve. Relative to current directory", - ) - return parser.parse_args() - - -class ComplexHTTPRequestHandler(server.SimpleHTTPRequestHandler): - SUFFIXES = [".html", "/index.html", "/", ""] - - extensions_map = { - **server.SimpleHTTPRequestHandler.extensions_map, - # web fonts - ".oft": "font/oft", - ".sfnt": "font/sfnt", - ".ttf": "font/ttf", - ".woff": "font/woff", - ".woff2": "font/woff2", - } - - def translate_path(self, path): - # abandon query parameters - path = path.split("?", 1)[0] - path = path.split("#", 1)[0] - # Don't forget explicit trailing slash when normalizing. Issue17324 - trailing_slash = path.rstrip().endswith("/") - path = urllib.parse.unquote(path) - path = posixpath.normpath(path) - words = path.split("/") - words = filter(None, words) - path = self.base_path - for word in words: - if os.path.dirname(word) or word in (os.curdir, os.pardir): - # Ignore components that are not a simple file/directory name - continue - path = os.path.join(path, word) - if trailing_slash: - path += "/" - return path - - def do_GET(self): - # cut off a query string - original_path = self.path.split("?", 1)[0] - # try to find file - self.path = self.get_path_that_exists(original_path) - - if not self.path: - return - - server.SimpleHTTPRequestHandler.do_GET(self) - - def get_path_that_exists(self, original_path): - # Try to strip trailing slash - trailing_slash = original_path.endswith("/") - original_path = original_path.rstrip("/") - # Try to detect file by applying various suffixes - tries = [] - for suffix in self.SUFFIXES: - if not trailing_slash and suffix == "/": - # if original request does not have trailing slash, skip the '/' suffix - # so that base class can redirect if needed - continue - path = original_path + suffix - if os.path.exists(self.translate_path(path)): - return path - tries.append(path) - logger.warning( - "Unable to find `%s` or variations:\n%s", original_path, "\n".join(tries) - ) - return None - - def guess_type(self, path): - """Guess at the mime type for the specified file.""" - mimetype = server.SimpleHTTPRequestHandler.guess_type(self, path) - - # If the default guess is too generic, try the python-magic library - if mimetype == "application/octet-stream" and magic_from_file: - mimetype = magic_from_file(path, mime=True) - - return mimetype - - def log_message(self, format, *args): - logger.info(format, *args) - - -class RootedHTTPServer(server.HTTPServer): - def __init__(self, base_path, *args, **kwargs): - server.HTTPServer.__init__(self, *args, **kwargs) - self.RequestHandlerClass.base_path = base_path - - -if __name__ == "__main__": - init_logging(level=logging.INFO) - logger.warning( - "'python -m pelican.server' is deprecated.\nThe " - "Pelican development server should be run via " - "'pelican --listen' or 'pelican -l'.\nThis can be combined " - "with regeneration as 'pelican -lr'.\nRerun 'pelican-" - "quickstart' to get new Makefile and tasks.py files." - ) - args = parse_arguments() - RootedHTTPServer.allow_reuse_address = True - try: - httpd = RootedHTTPServer( - args.path, (args.server, args.port), ComplexHTTPRequestHandler - ) - if args.ssl: - httpd.socket = ssl.wrap_socket( - httpd.socket, keyfile=args.key, certfile=args.cert, server_side=True - ) - except ssl.SSLError as e: - logger.error( - "Couldn't open certificate file %s or key file %s", args.cert, args.key - ) - logger.error("Could not listen on port %s, server %s.", args.port, args.server) - sys.exit(getattr(e, "exitcode", 1)) - - logger.info("Serving at port %s, server %s.", args.port, args.server) - try: - httpd.serve_forever() - except KeyboardInterrupt: - logger.info("Shutting down server.") - httpd.socket.close() diff --git a/pelican/settings.py b/pelican/settings.py deleted file mode 100644 index 66d6beeb..00000000 --- a/pelican/settings.py +++ /dev/null @@ -1,742 +0,0 @@ -import copy -import importlib.util -import inspect -import locale -import logging -import os -import re -import sys -from os.path import isabs -from pathlib import Path -from types import ModuleType -from typing import Any, Dict, Optional - -from pelican.log import LimitFilter - - -def load_source(name: str, path: str) -> ModuleType: - spec = importlib.util.spec_from_file_location(name, path) - mod = importlib.util.module_from_spec(spec) - sys.modules[name] = mod - spec.loader.exec_module(mod) - return mod - - -logger = logging.getLogger(__name__) - -Settings = Dict[str, Any] - -DEFAULT_THEME = os.path.join( - os.path.dirname(os.path.abspath(__file__)), "themes", "notmyidea" -) -DEFAULT_CONFIG = { - "PATH": os.curdir, - "ARTICLE_PATHS": [""], - "ARTICLE_EXCLUDES": [], - "PAGE_PATHS": ["pages"], - "PAGE_EXCLUDES": [], - "THEME": DEFAULT_THEME, - "OUTPUT_PATH": "output", - "READERS": {}, - "STATIC_PATHS": ["images"], - "STATIC_EXCLUDES": [], - "STATIC_EXCLUDE_SOURCES": True, - "THEME_STATIC_DIR": "theme", - "THEME_STATIC_PATHS": [ - "static", - ], - "FEED_ALL_ATOM": "feeds/all.atom.xml", - "CATEGORY_FEED_ATOM": "feeds/{slug}.atom.xml", - "AUTHOR_FEED_ATOM": "feeds/{slug}.atom.xml", - "AUTHOR_FEED_RSS": "feeds/{slug}.rss.xml", - "TRANSLATION_FEED_ATOM": "feeds/all-{lang}.atom.xml", - "FEED_MAX_ITEMS": 100, - "RSS_FEED_SUMMARY_ONLY": True, - "FEED_APPEND_REF": False, - "SITEURL": "", - "SITENAME": "A Pelican Blog", - "DISPLAY_PAGES_ON_MENU": True, - "DISPLAY_CATEGORIES_ON_MENU": True, - "DOCUTILS_SETTINGS": {}, - "OUTPUT_SOURCES": False, - "OUTPUT_SOURCES_EXTENSION": ".text", - "USE_FOLDER_AS_CATEGORY": True, - "DEFAULT_CATEGORY": "misc", - "WITH_FUTURE_DATES": True, - "CSS_FILE": "main.css", - "NEWEST_FIRST_ARCHIVES": True, - "REVERSE_CATEGORY_ORDER": False, - "DELETE_OUTPUT_DIRECTORY": False, - "OUTPUT_RETENTION": [], - "INDEX_SAVE_AS": "index.html", - "ARTICLE_URL": "{slug}.html", - "ARTICLE_SAVE_AS": "{slug}.html", - "ARTICLE_ORDER_BY": "reversed-date", - "ARTICLE_LANG_URL": "{slug}-{lang}.html", - "ARTICLE_LANG_SAVE_AS": "{slug}-{lang}.html", - "DRAFT_URL": "drafts/{slug}.html", - "DRAFT_SAVE_AS": "drafts/{slug}.html", - "DRAFT_LANG_URL": "drafts/{slug}-{lang}.html", - "DRAFT_LANG_SAVE_AS": "drafts/{slug}-{lang}.html", - "PAGE_URL": "pages/{slug}.html", - "PAGE_SAVE_AS": "pages/{slug}.html", - "PAGE_ORDER_BY": "basename", - "PAGE_LANG_URL": "pages/{slug}-{lang}.html", - "PAGE_LANG_SAVE_AS": "pages/{slug}-{lang}.html", - "DRAFT_PAGE_URL": "drafts/pages/{slug}.html", - "DRAFT_PAGE_SAVE_AS": "drafts/pages/{slug}.html", - "DRAFT_PAGE_LANG_URL": "drafts/pages/{slug}-{lang}.html", - "DRAFT_PAGE_LANG_SAVE_AS": "drafts/pages/{slug}-{lang}.html", - "STATIC_URL": "{path}", - "STATIC_SAVE_AS": "{path}", - "STATIC_CREATE_LINKS": False, - "STATIC_CHECK_IF_MODIFIED": False, - "CATEGORY_URL": "category/{slug}.html", - "CATEGORY_SAVE_AS": "category/{slug}.html", - "TAG_URL": "tag/{slug}.html", - "TAG_SAVE_AS": "tag/{slug}.html", - "AUTHOR_URL": "author/{slug}.html", - "AUTHOR_SAVE_AS": "author/{slug}.html", - "PAGINATION_PATTERNS": [ - (1, "{name}{extension}", "{name}{extension}"), - (2, "{name}{number}{extension}", "{name}{number}{extension}"), - ], - "YEAR_ARCHIVE_URL": "", - "YEAR_ARCHIVE_SAVE_AS": "", - "MONTH_ARCHIVE_URL": "", - "MONTH_ARCHIVE_SAVE_AS": "", - "DAY_ARCHIVE_URL": "", - "DAY_ARCHIVE_SAVE_AS": "", - "RELATIVE_URLS": False, - "DEFAULT_LANG": "en", - "ARTICLE_TRANSLATION_ID": "slug", - "PAGE_TRANSLATION_ID": "slug", - "DIRECT_TEMPLATES": ["index", "tags", "categories", "authors", "archives"], - "THEME_TEMPLATES_OVERRIDES": [], - "PAGINATED_TEMPLATES": { - "index": None, - "tag": None, - "category": None, - "author": None, - }, - "PELICAN_CLASS": "pelican.Pelican", - "DEFAULT_DATE_FORMAT": "%a %d %B %Y", - "DATE_FORMATS": {}, - "MARKDOWN": { - "extension_configs": { - "markdown.extensions.codehilite": {"css_class": "highlight"}, - "markdown.extensions.extra": {}, - "markdown.extensions.meta": {}, - }, - "output_format": "html5", - }, - "JINJA_FILTERS": {}, - "JINJA_GLOBALS": {}, - "JINJA_TESTS": {}, - "JINJA_ENVIRONMENT": { - "trim_blocks": True, - "lstrip_blocks": True, - "extensions": [], - }, - "LOG_FILTER": [], - "LOCALE": [""], # defaults to user locale - "DEFAULT_PAGINATION": False, - "DEFAULT_ORPHANS": 0, - "DEFAULT_METADATA": {}, - "FILENAME_METADATA": r"(?P\d{4}-\d{2}-\d{2}).*", - "PATH_METADATA": "", - "EXTRA_PATH_METADATA": {}, - "ARTICLE_PERMALINK_STRUCTURE": "", - "TYPOGRIFY": False, - "TYPOGRIFY_IGNORE_TAGS": [], - "TYPOGRIFY_DASHES": "default", - "SUMMARY_END_SUFFIX": "…", - "SUMMARY_MAX_LENGTH": 50, - "PLUGIN_PATHS": [], - "PLUGINS": None, - "PYGMENTS_RST_OPTIONS": {}, - "TEMPLATE_PAGES": {}, - "TEMPLATE_EXTENSIONS": [".html"], - "IGNORE_FILES": [".#*"], - "SLUG_REGEX_SUBSTITUTIONS": [ - (r"[^\w\s-]", ""), # remove non-alphabetical/whitespace/'-' chars - (r"(?u)\A\s*", ""), # strip leading whitespace - (r"(?u)\s*\Z", ""), # strip trailing whitespace - (r"[-\s]+", "-"), # reduce multiple whitespace or '-' to single '-' - ], - "INTRASITE_LINK_REGEX": "[{|](?P.*?)[|}]", - "SLUGIFY_SOURCE": "title", - "SLUGIFY_USE_UNICODE": False, - "SLUGIFY_PRESERVE_CASE": False, - "CACHE_CONTENT": False, - "CONTENT_CACHING_LAYER": "reader", - "CACHE_PATH": "cache", - "GZIP_CACHE": True, - "CHECK_MODIFIED_METHOD": "mtime", - "LOAD_CONTENT_CACHE": False, - "FORMATTED_FIELDS": ["summary"], - "PORT": 8000, - "BIND": "127.0.0.1", -} - -PYGMENTS_RST_OPTIONS = None - - -def read_settings( - path: Optional[str] = None, override: Optional[Settings] = None -) -> Settings: - settings = override or {} - - if path: - settings = dict(get_settings_from_file(path), **settings) - - if settings: - settings = handle_deprecated_settings(settings) - - if path: - # Make relative paths absolute - def getabs(maybe_relative, base_path=path): - if isabs(maybe_relative): - return maybe_relative - return os.path.abspath( - os.path.normpath( - os.path.join(os.path.dirname(base_path), maybe_relative) - ) - ) - - for p in ["PATH", "OUTPUT_PATH", "THEME", "CACHE_PATH"]: - if settings.get(p) is not None: - absp = getabs(settings[p]) - # THEME may be a name rather than a path - if p != "THEME" or os.path.exists(absp): - settings[p] = absp - - if settings.get("PLUGIN_PATHS") is not None: - settings["PLUGIN_PATHS"] = [ - getabs(pluginpath) for pluginpath in settings["PLUGIN_PATHS"] - ] - - settings = dict(copy.deepcopy(DEFAULT_CONFIG), **settings) - settings = configure_settings(settings) - - # This is because there doesn't seem to be a way to pass extra - # parameters to docutils directive handlers, so we have to have a - # variable here that we'll import from within Pygments.run (see - # rstdirectives.py) to see what the user defaults were. - global PYGMENTS_RST_OPTIONS # noqa: PLW0603 - PYGMENTS_RST_OPTIONS = settings.get("PYGMENTS_RST_OPTIONS", None) - return settings - - -def get_settings_from_module(module: Optional[ModuleType] = None) -> Settings: - """Loads settings from a module, returns a dictionary.""" - - context = {} - if module is not None: - context.update((k, v) for k, v in inspect.getmembers(module) if k.isupper()) - return context - - -def get_settings_from_file(path: str) -> Settings: - """Loads settings from a file path, returning a dict.""" - - name, ext = os.path.splitext(os.path.basename(path)) - module = load_source(name, path) - return get_settings_from_module(module) - - -def get_jinja_environment(settings: Settings) -> Settings: - """Sets the environment for Jinja""" - - jinja_env = settings.setdefault( - "JINJA_ENVIRONMENT", DEFAULT_CONFIG["JINJA_ENVIRONMENT"] - ) - - # Make sure we include the defaults if the user has set env variables - for key, value in DEFAULT_CONFIG["JINJA_ENVIRONMENT"].items(): - if key not in jinja_env: - jinja_env[key] = value - - return settings - - -def _printf_s_to_format_field(printf_string: str, format_field: str) -> str: - """Tries to replace %s with {format_field} in the provided printf_string. - Raises ValueError in case of failure. - """ - TEST_STRING = "PELICAN_PRINTF_S_DEPRECATION" - expected = printf_string % TEST_STRING - - result = printf_string.replace("{", "{{").replace("}", "}}") % f"{{{format_field}}}" - if result.format(**{format_field: TEST_STRING}) != expected: - raise ValueError(f"Failed to safely replace %s with {{{format_field}}}") - - return result - - -def handle_deprecated_settings(settings: Settings) -> Settings: - """Converts deprecated settings and issues warnings. Issues an exception - if both old and new setting is specified. - """ - - # PLUGIN_PATH -> PLUGIN_PATHS - if "PLUGIN_PATH" in settings: - logger.warning( - "PLUGIN_PATH setting has been replaced by " - "PLUGIN_PATHS, moving it to the new setting name." - ) - settings["PLUGIN_PATHS"] = settings["PLUGIN_PATH"] - del settings["PLUGIN_PATH"] - - # PLUGIN_PATHS: str -> [str] - if isinstance(settings.get("PLUGIN_PATHS"), str): - logger.warning( - "Defining PLUGIN_PATHS setting as string " - "has been deprecated (should be a list)" - ) - settings["PLUGIN_PATHS"] = [settings["PLUGIN_PATHS"]] - - # JINJA_EXTENSIONS -> JINJA_ENVIRONMENT > extensions - if "JINJA_EXTENSIONS" in settings: - logger.warning( - "JINJA_EXTENSIONS setting has been deprecated, " - "moving it to JINJA_ENVIRONMENT setting." - ) - settings["JINJA_ENVIRONMENT"]["extensions"] = settings["JINJA_EXTENSIONS"] - del settings["JINJA_EXTENSIONS"] - - # {ARTICLE,PAGE}_DIR -> {ARTICLE,PAGE}_PATHS - for key in ["ARTICLE", "PAGE"]: - old_key = key + "_DIR" - new_key = key + "_PATHS" - if old_key in settings: - logger.warning( - "Deprecated setting %s, moving it to %s list", old_key, new_key - ) - settings[new_key] = [settings[old_key]] # also make a list - del settings[old_key] - - # EXTRA_TEMPLATES_PATHS -> THEME_TEMPLATES_OVERRIDES - if "EXTRA_TEMPLATES_PATHS" in settings: - logger.warning( - "EXTRA_TEMPLATES_PATHS is deprecated use " - "THEME_TEMPLATES_OVERRIDES instead." - ) - if settings.get("THEME_TEMPLATES_OVERRIDES"): - raise Exception( - "Setting both EXTRA_TEMPLATES_PATHS and " - "THEME_TEMPLATES_OVERRIDES is not permitted. Please move to " - "only setting THEME_TEMPLATES_OVERRIDES." - ) - settings["THEME_TEMPLATES_OVERRIDES"] = settings["EXTRA_TEMPLATES_PATHS"] - del settings["EXTRA_TEMPLATES_PATHS"] - - # MD_EXTENSIONS -> MARKDOWN - if "MD_EXTENSIONS" in settings: - logger.warning( - "MD_EXTENSIONS is deprecated use MARKDOWN " - "instead. Falling back to the default." - ) - settings["MARKDOWN"] = DEFAULT_CONFIG["MARKDOWN"] - - # LESS_GENERATOR -> Webassets plugin - # FILES_TO_COPY -> STATIC_PATHS, EXTRA_PATH_METADATA - for old, new, doc in [ - ("LESS_GENERATOR", "the Webassets plugin", None), - ( - "FILES_TO_COPY", - "STATIC_PATHS and EXTRA_PATH_METADATA", - "https://github.com/getpelican/pelican/" - "blob/main/docs/settings.rst#path-metadata", - ), - ]: - if old in settings: - message = f"The {old} setting has been removed in favor of {new}" - if doc: - message += f", see {doc} for details" - logger.warning(message) - - # PAGINATED_DIRECT_TEMPLATES -> PAGINATED_TEMPLATES - if "PAGINATED_DIRECT_TEMPLATES" in settings: - message = "The {} setting has been removed in favor of {}".format( - "PAGINATED_DIRECT_TEMPLATES", "PAGINATED_TEMPLATES" - ) - logger.warning(message) - - # set PAGINATED_TEMPLATES - if "PAGINATED_TEMPLATES" not in settings: - settings["PAGINATED_TEMPLATES"] = { - "tag": None, - "category": None, - "author": None, - } - - for t in settings["PAGINATED_DIRECT_TEMPLATES"]: - if t not in settings["PAGINATED_TEMPLATES"]: - settings["PAGINATED_TEMPLATES"][t] = None - del settings["PAGINATED_DIRECT_TEMPLATES"] - - # {SLUG,CATEGORY,TAG,AUTHOR}_SUBSTITUTIONS -> - # {SLUG,CATEGORY,TAG,AUTHOR}_REGEX_SUBSTITUTIONS - url_settings_url = "http://docs.getpelican.com/en/latest/settings.html#url-settings" - flavours = {"SLUG", "CATEGORY", "TAG", "AUTHOR"} - old_values = { - f: settings[f + "_SUBSTITUTIONS"] - for f in flavours - if f + "_SUBSTITUTIONS" in settings - } - new_values = { - f: settings[f + "_REGEX_SUBSTITUTIONS"] - for f in flavours - if f + "_REGEX_SUBSTITUTIONS" in settings - } - if old_values and new_values: - raise Exception( - "Setting both {new_key} and {old_key} (or variants thereof) is " - "not permitted. Please move to only setting {new_key}.".format( - old_key="SLUG_SUBSTITUTIONS", new_key="SLUG_REGEX_SUBSTITUTIONS" - ) - ) - if old_values: - message = ( - "{} and variants thereof are deprecated and will be " - "removed in the future. Please use {} and variants thereof " - "instead. Check {}.".format( - "SLUG_SUBSTITUTIONS", "SLUG_REGEX_SUBSTITUTIONS", url_settings_url - ) - ) - logger.warning(message) - if old_values.get("SLUG"): - for f in ("CATEGORY", "TAG"): - if old_values.get(f): - old_values[f] = old_values["SLUG"] + old_values[f] - old_values["AUTHOR"] = old_values.get("AUTHOR", []) - for f in flavours: - if old_values.get(f) is not None: - regex_subs = [] - # by default will replace non-alphanum characters - replace = True - for tpl in old_values[f]: - try: - src, dst, skip = tpl - if skip: - replace = False - except ValueError: - src, dst = tpl - regex_subs.append((re.escape(src), dst.replace("\\", r"\\"))) - - if replace: - regex_subs += [ - (r"[^\w\s-]", ""), - (r"(?u)\A\s*", ""), - (r"(?u)\s*\Z", ""), - (r"[-\s]+", "-"), - ] - else: - regex_subs += [ - (r"(?u)\A\s*", ""), - (r"(?u)\s*\Z", ""), - ] - settings[f + "_REGEX_SUBSTITUTIONS"] = regex_subs - settings.pop(f + "_SUBSTITUTIONS", None) - - # `%s` -> '{slug}` or `{lang}` in FEED settings - for key in ["TRANSLATION_FEED_ATOM", "TRANSLATION_FEED_RSS"]: - if ( - settings.get(key) - and not isinstance(settings[key], Path) - and "%s" in settings[key] - ): - logger.warning("%%s usage in %s is deprecated, use {lang} instead.", key) - try: - settings[key] = _printf_s_to_format_field(settings[key], "lang") - except ValueError: - logger.warning( - "Failed to convert %%s to {lang} for %s. " - "Falling back to default.", - key, - ) - settings[key] = DEFAULT_CONFIG[key] - for key in [ - "AUTHOR_FEED_ATOM", - "AUTHOR_FEED_RSS", - "CATEGORY_FEED_ATOM", - "CATEGORY_FEED_RSS", - "TAG_FEED_ATOM", - "TAG_FEED_RSS", - ]: - if ( - settings.get(key) - and not isinstance(settings[key], Path) - and "%s" in settings[key] - ): - logger.warning("%%s usage in %s is deprecated, use {slug} instead.", key) - try: - settings[key] = _printf_s_to_format_field(settings[key], "slug") - except ValueError: - logger.warning( - "Failed to convert %%s to {slug} for %s. " - "Falling back to default.", - key, - ) - settings[key] = DEFAULT_CONFIG[key] - - # CLEAN_URLS - if settings.get("CLEAN_URLS", False): - logger.warning( - "Found deprecated `CLEAN_URLS` in settings." - " Modifying the following settings for the" - " same behaviour." - ) - - settings["ARTICLE_URL"] = "{slug}/" - settings["ARTICLE_LANG_URL"] = "{slug}-{lang}/" - settings["PAGE_URL"] = "pages/{slug}/" - settings["PAGE_LANG_URL"] = "pages/{slug}-{lang}/" - - for setting in ("ARTICLE_URL", "ARTICLE_LANG_URL", "PAGE_URL", "PAGE_LANG_URL"): - logger.warning("%s = '%s'", setting, settings[setting]) - - # AUTORELOAD_IGNORE_CACHE -> --ignore-cache - if settings.get("AUTORELOAD_IGNORE_CACHE"): - logger.warning( - "Found deprecated `AUTORELOAD_IGNORE_CACHE` in " - "settings. Use --ignore-cache instead." - ) - settings.pop("AUTORELOAD_IGNORE_CACHE") - - # ARTICLE_PERMALINK_STRUCTURE - if settings.get("ARTICLE_PERMALINK_STRUCTURE", False): - logger.warning( - "Found deprecated `ARTICLE_PERMALINK_STRUCTURE` in" - " settings. Modifying the following settings for" - " the same behaviour." - ) - - structure = settings["ARTICLE_PERMALINK_STRUCTURE"] - - # Convert %(variable) into {variable}. - structure = re.sub(r"%\((\w+)\)s", r"{\g<1>}", structure) - - # Convert %x into {date:%x} for strftime - structure = re.sub(r"(%[A-z])", r"{date:\g<1>}", structure) - - # Strip a / prefix - structure = re.sub("^/", "", structure) - - for setting in ( - "ARTICLE_URL", - "ARTICLE_LANG_URL", - "PAGE_URL", - "PAGE_LANG_URL", - "DRAFT_URL", - "DRAFT_LANG_URL", - "ARTICLE_SAVE_AS", - "ARTICLE_LANG_SAVE_AS", - "DRAFT_SAVE_AS", - "DRAFT_LANG_SAVE_AS", - "PAGE_SAVE_AS", - "PAGE_LANG_SAVE_AS", - ): - settings[setting] = os.path.join(structure, settings[setting]) - logger.warning("%s = '%s'", setting, settings[setting]) - - # {,TAG,CATEGORY,TRANSLATION}_FEED -> {,TAG,CATEGORY,TRANSLATION}_FEED_ATOM - for new, old in [ - ("FEED", "FEED_ATOM"), - ("TAG_FEED", "TAG_FEED_ATOM"), - ("CATEGORY_FEED", "CATEGORY_FEED_ATOM"), - ("TRANSLATION_FEED", "TRANSLATION_FEED_ATOM"), - ]: - if settings.get(new, False): - logger.warning( - "Found deprecated `%(new)s` in settings. Modify %(new)s " - "to %(old)s in your settings and theme for the same " - "behavior. Temporarily setting %(old)s for backwards " - "compatibility.", - {"new": new, "old": old}, - ) - settings[old] = settings[new] - - # Warn if removed WRITE_SELECTED is present - if "WRITE_SELECTED" in settings: - logger.warning( - "WRITE_SELECTED is present in settings but this functionality was removed. " - "It will have no effect." - ) - - return settings - - -def configure_settings(settings: Settings) -> Settings: - """Provide optimizations, error checking, and warnings for the given - settings. - Also, specify the log messages to be ignored. - """ - if "PATH" not in settings or not os.path.isdir(settings["PATH"]): - raise Exception( - "You need to specify a path containing the content" - " (see pelican --help for more information)" - ) - - # specify the log messages to be ignored - log_filter = settings.get("LOG_FILTER", DEFAULT_CONFIG["LOG_FILTER"]) - LimitFilter._ignore.update(set(log_filter)) - - # lookup the theme in "pelican/themes" if the given one doesn't exist - if not os.path.isdir(settings["THEME"]): - theme_path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), "themes", settings["THEME"] - ) - if os.path.exists(theme_path): - settings["THEME"] = theme_path - else: - raise Exception("Could not find the theme {}".format(settings["THEME"])) - - # standardize strings to lowercase strings - for key in ["DEFAULT_LANG"]: - if key in settings: - settings[key] = settings[key].lower() - - # set defaults for Jinja environment - settings = get_jinja_environment(settings) - - # standardize strings to lists - for key in ["LOCALE"]: - if key in settings and isinstance(settings[key], str): - settings[key] = [settings[key]] - - # check settings that must be a particular type - for key, types in [ - ("OUTPUT_SOURCES_EXTENSION", str), - ("FILENAME_METADATA", str), - ]: - if key in settings and not isinstance(settings[key], types): - value = settings.pop(key) - logger.warn( - "Detected misconfigured %s (%s), falling back to the default (%s)", - key, - value, - DEFAULT_CONFIG[key], - ) - - # try to set the different locales, fallback on the default. - locales = settings.get("LOCALE", DEFAULT_CONFIG["LOCALE"]) - - for locale_ in locales: - try: - locale.setlocale(locale.LC_ALL, str(locale_)) - break # break if it is successful - except locale.Error: - pass - else: - logger.warning( - "Locale could not be set. Check the LOCALE setting, ensuring it " - "is valid and available on your system." - ) - - if "SITEURL" in settings: - # If SITEURL has a trailing slash, remove it and provide a warning - siteurl = settings["SITEURL"] - if siteurl.endswith("/"): - settings["SITEURL"] = siteurl[:-1] - logger.warning("Removed extraneous trailing slash from SITEURL.") - # If SITEURL is defined but FEED_DOMAIN isn't, - # set FEED_DOMAIN to SITEURL - if "FEED_DOMAIN" not in settings: - settings["FEED_DOMAIN"] = settings["SITEURL"] - - # check content caching layer and warn of incompatibilities - if ( - settings.get("CACHE_CONTENT", False) - and settings.get("CONTENT_CACHING_LAYER", "") == "generator" - and not settings.get("WITH_FUTURE_DATES", True) - ): - logger.warning( - "WITH_FUTURE_DATES conflicts with CONTENT_CACHING_LAYER " - "set to 'generator', use 'reader' layer instead" - ) - - # Warn if feeds are generated with both SITEURL & FEED_DOMAIN undefined - feed_keys = [ - "FEED_ATOM", - "FEED_RSS", - "FEED_ALL_ATOM", - "FEED_ALL_RSS", - "CATEGORY_FEED_ATOM", - "CATEGORY_FEED_RSS", - "AUTHOR_FEED_ATOM", - "AUTHOR_FEED_RSS", - "TAG_FEED_ATOM", - "TAG_FEED_RSS", - "TRANSLATION_FEED_ATOM", - "TRANSLATION_FEED_RSS", - ] - - if any(settings.get(k) for k in feed_keys): - if not settings.get("SITEURL"): - logger.warning( - "Feeds generated without SITEURL set properly may not be valid" - ) - - if "TIMEZONE" not in settings: - logger.warning( - "No timezone information specified in the settings. Assuming" - " your timezone is UTC for feed generation. Check " - "https://docs.getpelican.com/en/latest/settings.html#TIMEZONE " - "for more information" - ) - - # fix up pagination rules - from pelican.paginator import PaginationRule - - pagination_rules = [ - PaginationRule(*r) - for r in settings.get( - "PAGINATION_PATTERNS", - DEFAULT_CONFIG["PAGINATION_PATTERNS"], - ) - ] - settings["PAGINATION_PATTERNS"] = sorted( - pagination_rules, - key=lambda r: r[0], - ) - - # Save people from accidentally setting a string rather than a list - path_keys = ( - "ARTICLE_EXCLUDES", - "DEFAULT_METADATA", - "DIRECT_TEMPLATES", - "THEME_TEMPLATES_OVERRIDES", - "FILES_TO_COPY", - "IGNORE_FILES", - "PAGINATED_DIRECT_TEMPLATES", - "PLUGINS", - "STATIC_EXCLUDES", - "STATIC_PATHS", - "THEME_STATIC_PATHS", - "ARTICLE_PATHS", - "PAGE_PATHS", - ) - for PATH_KEY in filter(lambda k: k in settings, path_keys): - if isinstance(settings[PATH_KEY], str): - logger.warning( - "Detected misconfiguration with %s setting " - "(must be a list), falling back to the default", - PATH_KEY, - ) - settings[PATH_KEY] = DEFAULT_CONFIG[PATH_KEY] - - # Add {PAGE,ARTICLE}_PATHS to {ARTICLE,PAGE}_EXCLUDES - mutually_exclusive = ("ARTICLE", "PAGE") - for type_1, type_2 in [mutually_exclusive, mutually_exclusive[::-1]]: - try: - includes = settings[type_1 + "_PATHS"] - excludes = settings[type_2 + "_EXCLUDES"] - for path in includes: - if path not in excludes: - excludes.append(path) - except KeyError: - continue # setting not specified, nothing to do - - return settings diff --git a/pelican/signals.py b/pelican/signals.py deleted file mode 100644 index 4d232e34..00000000 --- a/pelican/signals.py +++ /dev/null @@ -1,4 +0,0 @@ -raise ImportError( - "Importing from `pelican.signals` is deprecated. " - "Use `from pelican import signals` or `import pelican.plugins.signals` instead." -) diff --git a/pelican/tests/TestPages/bad_page.rst b/pelican/tests/TestPages/bad_page.rst deleted file mode 100644 index bc62948b..00000000 --- a/pelican/tests/TestPages/bad_page.rst +++ /dev/null @@ -1,8 +0,0 @@ -This is a test bad page -####################### - -:status: invalid - -The quick brown fox jumped over the lazy dog's back. - -The status here is invalid, the page should not render. diff --git a/pelican/tests/TestPages/draft_page.rst b/pelican/tests/TestPages/draft_page.rst deleted file mode 100644 index 19ca0646..00000000 --- a/pelican/tests/TestPages/draft_page.rst +++ /dev/null @@ -1,8 +0,0 @@ -This is a test draft page -########################## - -:status: draft - -The quick brown fox . - -This page is a draft. diff --git a/pelican/tests/TestPages/draft_page_markdown.md b/pelican/tests/TestPages/draft_page_markdown.md deleted file mode 100644 index 0f378a55..00000000 --- a/pelican/tests/TestPages/draft_page_markdown.md +++ /dev/null @@ -1,12 +0,0 @@ -title: This is a markdown test draft page -status: draft - -Test Markdown File Header -========================= - -Used for pelican test ---------------------- - -The quick brown fox . - -This page is a draft diff --git a/pelican/tests/TestPages/draft_page_with_template.rst b/pelican/tests/TestPages/draft_page_with_template.rst deleted file mode 100644 index 9d46e717..00000000 --- a/pelican/tests/TestPages/draft_page_with_template.rst +++ /dev/null @@ -1,11 +0,0 @@ -This is a test draft page with a custom template -################################################# - -:status: draft -:template: custom - -The quick brown fox . - -This page is a draft - -This page has a custom template to be called when rendered diff --git a/pelican/tests/TestPages/hidden_page.rst b/pelican/tests/TestPages/hidden_page.rst deleted file mode 100644 index 57ca329c..00000000 --- a/pelican/tests/TestPages/hidden_page.rst +++ /dev/null @@ -1,8 +0,0 @@ -This is a test hidden page -########################## - -:status: hidden - -The quick brown fox jumped over the lazy dog's back. - -This page is hidden diff --git a/pelican/tests/TestPages/hidden_page_markdown.md b/pelican/tests/TestPages/hidden_page_markdown.md deleted file mode 100644 index 1e532fe7..00000000 --- a/pelican/tests/TestPages/hidden_page_markdown.md +++ /dev/null @@ -1,12 +0,0 @@ -title: This is a markdown test hidden page -status: hidden - -Test Markdown File Header -========================= - -Used for pelican test ---------------------- - -The quick brown fox jumped over the lazy dog's back. - -This page is hidden diff --git a/pelican/tests/TestPages/hidden_page_with_template.rst b/pelican/tests/TestPages/hidden_page_with_template.rst deleted file mode 100644 index 36104a09..00000000 --- a/pelican/tests/TestPages/hidden_page_with_template.rst +++ /dev/null @@ -1,11 +0,0 @@ -This is a test hidden page with a custom template -################################################# - -:status: hidden -:template: custom - -The quick brown fox jumped over the lazy dog's back. - -This page is hidden - -This page has a custom template to be called when rendered diff --git a/pelican/tests/TestPages/page.rst b/pelican/tests/TestPages/page.rst deleted file mode 100644 index 2d13976d..00000000 --- a/pelican/tests/TestPages/page.rst +++ /dev/null @@ -1,4 +0,0 @@ -This is a test page -################### - -The quick brown fox jumped over the lazy dog's back. diff --git a/pelican/tests/TestPages/page_markdown.md b/pelican/tests/TestPages/page_markdown.md deleted file mode 100644 index d5416a6f..00000000 --- a/pelican/tests/TestPages/page_markdown.md +++ /dev/null @@ -1,9 +0,0 @@ -title: This is a markdown test page - -Test Markdown File Header -========================= - -Used for pelican test ---------------------- - -The quick brown fox jumped over the lazy dog's back. diff --git a/pelican/tests/TestPages/page_used_for_sorting_test.rst b/pelican/tests/TestPages/page_used_for_sorting_test.rst deleted file mode 100644 index 40cdc7ea..00000000 --- a/pelican/tests/TestPages/page_used_for_sorting_test.rst +++ /dev/null @@ -1,6 +0,0 @@ -A Page (Test) for sorting -######################### - -:slug: zzzz - -When using title, should be first. When using slug, should be last. diff --git a/pelican/tests/TestPages/page_with_category_and_tag_links.md b/pelican/tests/TestPages/page_with_category_and_tag_links.md deleted file mode 100644 index 6806a570..00000000 --- a/pelican/tests/TestPages/page_with_category_and_tag_links.md +++ /dev/null @@ -1,7 +0,0 @@ -Title: Page with a bunch of links - -My links: - -[Link 1]({tag}マック) - -[Link 2]({category}Yeah) diff --git a/pelican/tests/TestPages/page_with_static_links.md b/pelican/tests/TestPages/page_with_static_links.md deleted file mode 100644 index 1967cfcf..00000000 --- a/pelican/tests/TestPages/page_with_static_links.md +++ /dev/null @@ -1,7 +0,0 @@ -Title: Page with static links - -My links: - -[Link 0]({static}image0.jpg) - -[Link 1]({attach}image1.jpg) diff --git a/pelican/tests/TestPages/page_with_template.rst b/pelican/tests/TestPages/page_with_template.rst deleted file mode 100644 index 9388dc2f..00000000 --- a/pelican/tests/TestPages/page_with_template.rst +++ /dev/null @@ -1,8 +0,0 @@ -This is a test page with a preset template -########################################## - -:template: custom - -The quick brown fox jumped over the lazy dog's back. - -This article has a custom template to be called when rendered diff --git a/pelican/tests/__init__.py b/pelican/tests/__init__.py deleted file mode 100644 index 564e417c..00000000 --- a/pelican/tests/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -import logging -import warnings - -from pelican.log import log_warnings - -# redirect warnings module to use logging instead -log_warnings() - -# setup warnings to log DeprecationWarning's and error on -# warnings in pelican's codebase -warnings.simplefilter("default", DeprecationWarning) -warnings.filterwarnings("error", ".*", Warning, "pelican") - -# Add a NullHandler to silence warning about no available handlers -logging.getLogger().addHandler(logging.NullHandler()) diff --git a/pelican/tests/build_test/conftest.py b/pelican/tests/build_test/conftest.py deleted file mode 100644 index b1d1a54b..00000000 --- a/pelican/tests/build_test/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -def pytest_addoption(parser): - parser.addoption( - "--check-build", - action="store", - default=False, - help="Check wheel contents.", - ) diff --git a/pelican/tests/build_test/test_build_files.py b/pelican/tests/build_test/test_build_files.py deleted file mode 100644 index c59d9235..00000000 --- a/pelican/tests/build_test/test_build_files.py +++ /dev/null @@ -1,69 +0,0 @@ -import importlib.metadata -import tarfile -from pathlib import Path -from re import match -from zipfile import ZipFile - -import pytest - -version = importlib.metadata.version("pelican") - - -@pytest.mark.skipif( - "not config.getoption('--check-build')", - reason="Only run when --check-build is given", -) -def test_wheel_contents(pytestconfig): - """ - This test should test the contents of the wheel to make sure - that everything that is needed is included in the final build - """ - dist_folder = pytestconfig.getoption("--check-build") - wheels = Path(dist_folder).rglob(f"pelican-{version}-py3-none-any.whl") - for wheel_file in wheels: - files_list = ZipFile(wheel_file).namelist() - # Check if theme files are copied to wheel - simple_theme = Path("./pelican/themes/simple/templates") - for x in simple_theme.iterdir(): - assert str(x) in files_list - - # Check if tool templates are copied to wheel - tools = Path("./pelican/tools/templates") - for x in tools.iterdir(): - assert str(x) in files_list - - assert "pelican/tools/templates/tasks.py.jinja2" in files_list - - -@pytest.mark.skipif( - "not config.getoption('--check-build')", - reason="Only run when --check-build is given", -) -@pytest.mark.parametrize( - "expected_file", - [ - ("THANKS"), - ("README.rst"), - ("CONTRIBUTING.rst"), - ("docs/changelog.rst"), - ("samples/"), - ], -) -def test_sdist_contents(pytestconfig, expected_file): - """ - This test should test the contents of the source distribution to make sure - that everything that is needed is included in the final build. - """ - dist_folder = pytestconfig.getoption("--check-build") - sdist_files = Path(dist_folder).rglob(f"pelican-{version}.tar.gz") - for dist in sdist_files: - files_list = tarfile.open(dist, "r:gz").getnames() - dir_matcher = "" - if expected_file.endswith("/"): - dir_matcher = ".*" - filtered_values = [ - path - for path in files_list - if match(rf"^pelican-{version}/{expected_file}{dir_matcher}$", path) - ] - assert len(filtered_values) > 0 diff --git a/pelican/tests/content/2012-11-29_rst_w_filename_meta#foo-bar.rst b/pelican/tests/content/2012-11-29_rst_w_filename_meta#foo-bar.rst deleted file mode 100644 index 43f05a15..00000000 --- a/pelican/tests/content/2012-11-29_rst_w_filename_meta#foo-bar.rst +++ /dev/null @@ -1,6 +0,0 @@ - -Rst with filename metadata -########################## - -:category: yeah -:author: Alexis Métaireau diff --git a/pelican/tests/content/2012-11-30_md_w_filename_meta#foo-bar.md b/pelican/tests/content/2012-11-30_md_w_filename_meta#foo-bar.md deleted file mode 100644 index 8b3c0bcf..00000000 --- a/pelican/tests/content/2012-11-30_md_w_filename_meta#foo-bar.md +++ /dev/null @@ -1,5 +0,0 @@ -category: yeah -author: Alexis Métaireau - -Markdown with filename metadata -=============================== diff --git a/pelican/tests/content/TestCategory/article_with_category.rst b/pelican/tests/content/TestCategory/article_with_category.rst deleted file mode 100644 index 69ffa98b..00000000 --- a/pelican/tests/content/TestCategory/article_with_category.rst +++ /dev/null @@ -1,7 +0,0 @@ -This is an article with category ! -################################## - -:category: yeah -:date: 1970-01-01 - -This article should be in 'yeah' category. diff --git a/pelican/tests/content/TestCategory/article_without_category.rst b/pelican/tests/content/TestCategory/article_without_category.rst deleted file mode 100644 index 4bc5d78d..00000000 --- a/pelican/tests/content/TestCategory/article_without_category.rst +++ /dev/null @@ -1,4 +0,0 @@ -This is an article without category ! -##################################### - -This article should be in 'TestCategory' category. diff --git a/pelican/tests/content/article.rst b/pelican/tests/content/article.rst deleted file mode 100644 index 793e6869..00000000 --- a/pelican/tests/content/article.rst +++ /dev/null @@ -1,6 +0,0 @@ -Article title -############# - -THIS is some content. With some stuff to "typogrify"... - -Now with added support for :abbr:`TLA (three letter acronym)`. diff --git a/pelican/tests/content/article_draft.md b/pelican/tests/content/article_draft.md deleted file mode 100644 index d2235553..00000000 --- a/pelican/tests/content/article_draft.md +++ /dev/null @@ -1,5 +0,0 @@ -Title: Draft article -Date: 2012-10-31 -Status: draft - -This is some content. diff --git a/pelican/tests/content/article_hidden.md b/pelican/tests/content/article_hidden.md deleted file mode 100644 index d449f701..00000000 --- a/pelican/tests/content/article_hidden.md +++ /dev/null @@ -1,5 +0,0 @@ -Title: Hidden article -Date: 2012-10-31 -Status: hidden - -This is some unlisted content. diff --git a/pelican/tests/content/article_skip.md b/pelican/tests/content/article_skip.md deleted file mode 100644 index 02cd5a52..00000000 --- a/pelican/tests/content/article_skip.md +++ /dev/null @@ -1,5 +0,0 @@ -Title: Skipped article -Date: 2024-06-30 -Status: skip - -This content will not be rendered. diff --git a/pelican/tests/content/article_with_attributes_containing_double_quotes.html b/pelican/tests/content/article_with_attributes_containing_double_quotes.html deleted file mode 100644 index 7daa5801..00000000 --- a/pelican/tests/content/article_with_attributes_containing_double_quotes.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - Ensure that if an attribute value contains a double quote, it is - surrounded with single quotes, otherwise with double quotes. - Span content - Span content - Span content - - diff --git a/pelican/tests/content/article_with_capitalized_metadata.rst b/pelican/tests/content/article_with_capitalized_metadata.rst deleted file mode 100644 index 93ed5b15..00000000 --- a/pelican/tests/content/article_with_capitalized_metadata.rst +++ /dev/null @@ -1,16 +0,0 @@ - -This is a super article ! -######################### - -:TAGS: foo, bar, foobar -:DATE: 2010-12-02 10:14 -:MODIFIED: 2010-12-02 10:20 -:CATEGORY: yeah -:AUTHOR: Alexis Métaireau -:SUMMARY: - Multi-line metadata should be supported - as well as **inline markup** and stuff to "typogrify"... -:CUSTOM_FIELD: http://notmyidea.org -:CUSTOM_FORMATTED_FIELD: - Multi-line metadata should also be supported - as well as *inline markup* and stuff to "typogrify"... diff --git a/pelican/tests/content/article_with_code_block.rst b/pelican/tests/content/article_with_code_block.rst deleted file mode 100644 index 586878cf..00000000 --- a/pelican/tests/content/article_with_code_block.rst +++ /dev/null @@ -1,15 +0,0 @@ -An Article With Code Block To Test Typogrify Ignore -################################################### - -An article with some code - -.. code-block:: python - - x & y - -A block quote: - - x & y - -Normal: -x & y diff --git a/pelican/tests/content/article_with_comments.html b/pelican/tests/content/article_with_comments.html deleted file mode 100644 index 289e4a66..00000000 --- a/pelican/tests/content/article_with_comments.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - Body content - - - diff --git a/pelican/tests/content/article_with_duplicate_tags_authors.md b/pelican/tests/content/article_with_duplicate_tags_authors.md deleted file mode 100644 index 7ab046f9..00000000 --- a/pelican/tests/content/article_with_duplicate_tags_authors.md +++ /dev/null @@ -1,15 +0,0 @@ -Title: Test metadata duplicates -Category: test -Tags: foo, bar, foobar, foo, bar -Authors: Author, First; Author, Second; Author, First -Date: 2010-12-02 10:14 -Modified: 2010-12-02 10:20 -Summary: I have a lot to test - -Test Markdown File Header -========================= - -Used for pelican test ---------------------- - -The quick brown fox jumped over the lazy dog's back. diff --git a/pelican/tests/content/article_with_inline_svg.html b/pelican/tests/content/article_with_inline_svg.html deleted file mode 100644 index 06725704..00000000 --- a/pelican/tests/content/article_with_inline_svg.html +++ /dev/null @@ -1,17 +0,0 @@ - - - Article with an inline SVG - - - Ensure that the title attribute in an inline svg is not handled as an HTML title. - - - A different title inside the inline SVG - - - - - - - - diff --git a/pelican/tests/content/article_with_keywords.html b/pelican/tests/content/article_with_keywords.html deleted file mode 100644 index 0744c754..00000000 --- a/pelican/tests/content/article_with_keywords.html +++ /dev/null @@ -1,6 +0,0 @@ - - - This is a super article ! - - - diff --git a/pelican/tests/content/article_with_markdown_and_empty_tags.md b/pelican/tests/content/article_with_markdown_and_empty_tags.md deleted file mode 100644 index ba013fe9..00000000 --- a/pelican/tests/content/article_with_markdown_and_empty_tags.md +++ /dev/null @@ -1,4 +0,0 @@ -Title: Article with markdown and empty tags -Tags: - -This is some content. diff --git a/pelican/tests/content/article_with_markdown_and_footnote.md b/pelican/tests/content/article_with_markdown_and_footnote.md deleted file mode 100644 index 6fea2d6e..00000000 --- a/pelican/tests/content/article_with_markdown_and_footnote.md +++ /dev/null @@ -1,15 +0,0 @@ -Title: Article with markdown containing footnotes -Date: 2012-10-31 -Modified: 2012-11-01 -Summary: Summary with **inline** markup *should* be supported. -Multiline: Line Metadata should be handle properly. - See syntax of Meta-Data extension of Python Markdown package: - If a line is indented by 4 or more spaces, - that line is assumed to be an additional line of the value - for the previous keyword. - A keyword may have as many lines as desired. - -This is some content[^1] with some footnotes[^footnote] - -[^1]: Numbered footnote -[^footnote]: Named footnote diff --git a/pelican/tests/content/article_with_markdown_and_nested_metadata.md b/pelican/tests/content/article_with_markdown_and_nested_metadata.md deleted file mode 100644 index 3968027b..00000000 --- a/pelican/tests/content/article_with_markdown_and_nested_metadata.md +++ /dev/null @@ -1,5 +0,0 @@ -Title: Article with markdown and nested summary metadata -Date: 2012-10-30 -Summary: Test: This metadata value looks like metadata - -This is some content. diff --git a/pelican/tests/content/article_with_markdown_and_nonascii_summary.md b/pelican/tests/content/article_with_markdown_and_nonascii_summary.md deleted file mode 100644 index d76ed4a1..00000000 --- a/pelican/tests/content/article_with_markdown_and_nonascii_summary.md +++ /dev/null @@ -1,19 +0,0 @@ -Title: マックOS X 10.8でパイソンとVirtualenvをインストールと設定 -Slug: python-virtualenv-on-mac-osx-mountain-lion-10.8 -Date: 2012-12-20 -Modified: 2012-12-22 -Tags: パイソン, マック -Category: 指導書 -Summary: パイソンとVirtualenvをまっくでインストールする方法について明確に説明します。 - -Writing unicode is certainly fun. - -パイソンとVirtualenvをまっくでインストールする方法について明確に説明します。 - -And let's mix languages. - -первый пост - -Now another. - -İlk yazı çok özel değil. diff --git a/pelican/tests/content/article_with_markdown_and_summary_metadata_multi.md b/pelican/tests/content/article_with_markdown_and_summary_metadata_multi.md deleted file mode 100644 index c5f62a0a..00000000 --- a/pelican/tests/content/article_with_markdown_and_summary_metadata_multi.md +++ /dev/null @@ -1,10 +0,0 @@ -Title: Article with markdown and summary metadata multi -Date: 2012-10-31 -Summary: - A multi-line summary should be supported - as well as **inline markup**. -custom_formatted_field: - Multi-line metadata should also be supported - as well as *inline markup* and stuff to "typogrify"... - -This is some content. diff --git a/pelican/tests/content/article_with_markdown_and_summary_metadata_single.md b/pelican/tests/content/article_with_markdown_and_summary_metadata_single.md deleted file mode 100644 index a7d6f09b..00000000 --- a/pelican/tests/content/article_with_markdown_and_summary_metadata_single.md +++ /dev/null @@ -1,5 +0,0 @@ -Title: Article with markdown and summary metadata single -Date: 2012-10-30 -Summary: A single-line summary should be supported as well as **inline markup**. - -This is some content. diff --git a/pelican/tests/content/article_with_markdown_extension.markdown b/pelican/tests/content/article_with_markdown_extension.markdown deleted file mode 100644 index 94e92871..00000000 --- a/pelican/tests/content/article_with_markdown_extension.markdown +++ /dev/null @@ -1,10 +0,0 @@ -title: Test markdown File -category: test - -Test Markdown File Header -========================= - -Used for pelican test ---------------------- - -This is another markdown test file. Uses the markdown extension. diff --git a/pelican/tests/content/article_with_markdown_markup_extensions.md b/pelican/tests/content/article_with_markdown_markup_extensions.md deleted file mode 100644 index 7eff4dcb..00000000 --- a/pelican/tests/content/article_with_markdown_markup_extensions.md +++ /dev/null @@ -1,7 +0,0 @@ -Title: Test Markdown extensions - -[TOC] - -## Level1 - -### Level2 diff --git a/pelican/tests/content/article_with_md_extension.md b/pelican/tests/content/article_with_md_extension.md deleted file mode 100644 index 89b6980c..00000000 --- a/pelican/tests/content/article_with_md_extension.md +++ /dev/null @@ -1,14 +0,0 @@ -Title: Test md File -Category: test -Tags: foo, bar, foobar -Date: 2010-12-02 10:14 -Modified: 2010-12-02 10:20 -Summary: I have a lot to test - -Test Markdown File Header -========================= - -Used for pelican test ---------------------- - -The quick brown fox jumped over the lazy dog's back. diff --git a/pelican/tests/content/article_with_mdown_extension.mdown b/pelican/tests/content/article_with_mdown_extension.mdown deleted file mode 100644 index bdaf74cd..00000000 --- a/pelican/tests/content/article_with_mdown_extension.mdown +++ /dev/null @@ -1,10 +0,0 @@ -title: Test mdown File -category: test - -Test Markdown File Header -========================= - -Used for pelican test ---------------------- - -This is another markdown test file. Uses the mdown extension. diff --git a/pelican/tests/content/article_with_metadata.html b/pelican/tests/content/article_with_metadata.html deleted file mode 100644 index b501ea29..00000000 --- a/pelican/tests/content/article_with_metadata.html +++ /dev/null @@ -1,15 +0,0 @@ - - - This is a super article ! - - - - - - - - - Multi-line metadata should be supported - as well as inline markup. - - diff --git a/pelican/tests/content/article_with_metadata.rst b/pelican/tests/content/article_with_metadata.rst deleted file mode 100644 index 5f3d77bc..00000000 --- a/pelican/tests/content/article_with_metadata.rst +++ /dev/null @@ -1,16 +0,0 @@ - -This is a super article ! -######################### - -:tags: foo, bar, foobar -:date: 2010-12-02 10:14 -:modified: 2010-12-02 10:20 -:category: yeah -:author: Alexis Métaireau -:summary: - Multi-line metadata should be supported - as well as **inline markup** and stuff to "typogrify"... -:custom_field: http://notmyidea.org -:custom_formatted_field: - Multi-line metadata should also be supported - as well as *inline markup* and stuff to "typogrify"... diff --git a/pelican/tests/content/article_with_metadata.unknownextension b/pelican/tests/content/article_with_metadata.unknownextension deleted file mode 100644 index d4bac1c0..00000000 --- a/pelican/tests/content/article_with_metadata.unknownextension +++ /dev/null @@ -1,12 +0,0 @@ - -This is a super article ! -######################### - -:tags: foo, bar, foobar -:date: 2010-12-02 10:14 -:category: yeah -:author: Alexis Métaireau -:summary: - Multi-line metadata should be supported - as well as **inline markup**. -:custom_field: http://notmyidea.org diff --git a/pelican/tests/content/article_with_metadata_and_contents.html b/pelican/tests/content/article_with_metadata_and_contents.html deleted file mode 100644 index b108ac8a..00000000 --- a/pelican/tests/content/article_with_metadata_and_contents.html +++ /dev/null @@ -1,15 +0,0 @@ - - - This is a super article ! - - - - - - - - - Multi-line metadata should be supported - as well as inline markup. - - diff --git a/pelican/tests/content/article_with_metadata_explicit_date_implicit_modified.html b/pelican/tests/content/article_with_metadata_explicit_date_implicit_modified.html deleted file mode 100644 index b501ea29..00000000 --- a/pelican/tests/content/article_with_metadata_explicit_date_implicit_modified.html +++ /dev/null @@ -1,15 +0,0 @@ - - - This is a super article ! - - - - - - - - - Multi-line metadata should be supported - as well as inline markup. - - diff --git a/pelican/tests/content/article_with_metadata_explicit_dates.html b/pelican/tests/content/article_with_metadata_explicit_dates.html deleted file mode 100644 index 1c74f40e..00000000 --- a/pelican/tests/content/article_with_metadata_explicit_dates.html +++ /dev/null @@ -1,16 +0,0 @@ - - - This is a super article ! - - - - - - - - - - Multi-line metadata should be supported - as well as inline markup. - - diff --git a/pelican/tests/content/article_with_metadata_implicit_date_explicit_modified.html b/pelican/tests/content/article_with_metadata_implicit_date_explicit_modified.html deleted file mode 100644 index 8cd2885b..00000000 --- a/pelican/tests/content/article_with_metadata_implicit_date_explicit_modified.html +++ /dev/null @@ -1,15 +0,0 @@ - - - This is a super article ! - - - - - - - - - Multi-line metadata should be supported - as well as inline markup. - - diff --git a/pelican/tests/content/article_with_metadata_implicit_dates.html b/pelican/tests/content/article_with_metadata_implicit_dates.html deleted file mode 100644 index 14d7e1e0..00000000 --- a/pelican/tests/content/article_with_metadata_implicit_dates.html +++ /dev/null @@ -1,14 +0,0 @@ - - - This is a super article ! - - - - - - - - Multi-line metadata should be supported - as well as inline markup. - - diff --git a/pelican/tests/content/article_with_mkd_extension.mkd b/pelican/tests/content/article_with_mkd_extension.mkd deleted file mode 100644 index c946cb87..00000000 --- a/pelican/tests/content/article_with_mkd_extension.mkd +++ /dev/null @@ -1,10 +0,0 @@ -title: Test mkd File -category: test - -Test Markdown File Header -========================= - -Used for pelican test ---------------------- - -This is another markdown test file. Uses the mkd extension. diff --git a/pelican/tests/content/article_with_multiple_authors.html b/pelican/tests/content/article_with_multiple_authors.html deleted file mode 100644 index a74442c9..00000000 --- a/pelican/tests/content/article_with_multiple_authors.html +++ /dev/null @@ -1,6 +0,0 @@ - - - This is an article with multiple authors! - - - diff --git a/pelican/tests/content/article_with_multiple_authors.rst b/pelican/tests/content/article_with_multiple_authors.rst deleted file mode 100644 index 04af017c..00000000 --- a/pelican/tests/content/article_with_multiple_authors.rst +++ /dev/null @@ -1,6 +0,0 @@ -This is an article with multiple authors! -######################################### - -:date: 2014-02-09 02:20 -:modified: 2014-02-09 02:20 -:authors: First Author, Second Author diff --git a/pelican/tests/content/article_with_multiple_authors_list.rst b/pelican/tests/content/article_with_multiple_authors_list.rst deleted file mode 100644 index 7da5fae2..00000000 --- a/pelican/tests/content/article_with_multiple_authors_list.rst +++ /dev/null @@ -1,10 +0,0 @@ -This is an article with multiple authors in list format! -######################################################## - -:date: 2014-02-09 02:20 -:modified: 2014-02-09 02:20 -:authors: - Author, First - - Author, Second - -The author names are in last,first form to verify that -they are not just getting split on commas. diff --git a/pelican/tests/content/article_with_multiple_authors_semicolon.rst b/pelican/tests/content/article_with_multiple_authors_semicolon.rst deleted file mode 100644 index fa76ac4e..00000000 --- a/pelican/tests/content/article_with_multiple_authors_semicolon.rst +++ /dev/null @@ -1,6 +0,0 @@ -This is an article with multiple authors in lastname, firstname format! -####################################################################### - -:date: 2014-02-09 02:20 -:modified: 2014-02-09 02:20 -:authors: Author, First; Author, Second diff --git a/pelican/tests/content/article_with_multiple_metadata_tags.html b/pelican/tests/content/article_with_multiple_metadata_tags.html deleted file mode 100644 index b52fbcf7..00000000 --- a/pelican/tests/content/article_with_multiple_metadata_tags.html +++ /dev/null @@ -1,11 +0,0 @@ - - - Metadata tags as list! - - - - - When custom metadata tags are specified more than once - they are collected into a list! - - diff --git a/pelican/tests/content/article_with_nonconformant_meta_tags.html b/pelican/tests/content/article_with_nonconformant_meta_tags.html deleted file mode 100644 index b8ef1723..00000000 --- a/pelican/tests/content/article_with_nonconformant_meta_tags.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Article with Nonconformant HTML meta tags - - - - Multi-line metadata should be supported - as well as inline markup. - - diff --git a/pelican/tests/content/article_with_null_attributes.html b/pelican/tests/content/article_with_null_attributes.html deleted file mode 100644 index 68da704c..00000000 --- a/pelican/tests/content/article_with_null_attributes.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - Ensure that empty attributes are copied properly. - - - diff --git a/pelican/tests/content/article_with_template.rst b/pelican/tests/content/article_with_template.rst deleted file mode 100644 index eb55738c..00000000 --- a/pelican/tests/content/article_with_template.rst +++ /dev/null @@ -1,8 +0,0 @@ -Article with template -##################### - -:template: custom - -This article has a custom template to be called when rendered - -This is some content. With some stuff to "typogrify". diff --git a/pelican/tests/content/article_with_typogrify_dashes.md b/pelican/tests/content/article_with_typogrify_dashes.md deleted file mode 100644 index 2914b2df..00000000 --- a/pelican/tests/content/article_with_typogrify_dashes.md +++ /dev/null @@ -1,3 +0,0 @@ -Title: One -, two --, three --- dashes! - -One: -; Two: --; Three: --- diff --git a/pelican/tests/content/article_with_typogrify_dashes.rst b/pelican/tests/content/article_with_typogrify_dashes.rst deleted file mode 100644 index 90064c5d..00000000 --- a/pelican/tests/content/article_with_typogrify_dashes.rst +++ /dev/null @@ -1,4 +0,0 @@ -One -, two --, three --- dashes! -################################ - -One: -; Two: --; Three: --- diff --git a/pelican/tests/content/article_with_uppercase_metadata.html b/pelican/tests/content/article_with_uppercase_metadata.html deleted file mode 100644 index b4cedf39..00000000 --- a/pelican/tests/content/article_with_uppercase_metadata.html +++ /dev/null @@ -1,6 +0,0 @@ - - - This is a super article ! - - - diff --git a/pelican/tests/content/article_with_uppercase_metadata.rst b/pelican/tests/content/article_with_uppercase_metadata.rst deleted file mode 100644 index ee79f55a..00000000 --- a/pelican/tests/content/article_with_uppercase_metadata.rst +++ /dev/null @@ -1,5 +0,0 @@ - -This is a super article ! -######################### - -:Category: Yeah diff --git a/pelican/tests/content/article_without_category.rst b/pelican/tests/content/article_without_category.rst deleted file mode 100644 index 1cfcba71..00000000 --- a/pelican/tests/content/article_without_category.rst +++ /dev/null @@ -1,5 +0,0 @@ - -This is an article without category ! -##################################### - -This article should be in the DEFAULT_CATEGORY. diff --git a/pelican/tests/content/bad_extension.mmd b/pelican/tests/content/bad_extension.mmd deleted file mode 100644 index d282a749..00000000 --- a/pelican/tests/content/bad_extension.mmd +++ /dev/null @@ -1,3 +0,0 @@ -Title: Bad Extension - -This file shouldn't be included because its file extension is `.mmd`. diff --git a/pelican/tests/content/bloggerexport.xml b/pelican/tests/content/bloggerexport.xml deleted file mode 100644 index a3b9cdf2..00000000 --- a/pelican/tests/content/bloggerexport.xml +++ /dev/null @@ -1,1067 +0,0 @@ - - - - tag:blogger.com,1999:blog-6303278419262689239.archive - - 2018-08-02T12:38:27.320-07:00 - - Notes of a Young Doctor - - - - - - Mikhail Afanasyevich Bulgakov - - https://www.blogger.com/profile/000082957 - - noreply@blogger.com - - - - Blogger - - - tag:blogger.com,1999:blog-6303278419262689239.layout - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Template: Notes of a Young Doctor - [Over 2000 lines of mostly css that we don't need here.] - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_PUBLISHING_MODE - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Het type publicatie voor deze blog. - PUBLISH_MODE_BLOGSPOT - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_ADMIN_PERMISSION - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - De lijst van e-mails van beheerders voor de blog. - mikhail.afanasyevich.bulgakov@gmail.com - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_ADULT_CONTENT - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of deze blog content voor volwassenen bevat - false - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_ALTERNATE_JSRENDER_ALLOWED - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of alternatieve weergaven in JavaScript zijn toegestaan - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_ANALYTICS_ACCOUNT_NUMBER - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Google Analytics-accountnummer voor een blog - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_ARCHIVE_DATE_FORMAT - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Het getal van de datumnotatie voor de archiefindex - 9 - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_ARCHIVE_FREQUENCY - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hoe vaak deze blog moet worden gearchiveerd - MONTHLY - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_AUTHOR_PERMISSION - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - De lijst van e-mails van auteurs die toestemming hebben om te publiceren. - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_BACKLINKS_ALLOWED - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of reactiebacklinks op de blog moeten worden getoond - false - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_BY_POST_ARCHIVING - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of iedere post moet worden voorzien van een archiefpagina - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENT_ACCESS - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Wie kan reacties achterlaten - BLOGGERS - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENT_CAPTCHA - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of personen die reacties geven, een Captcha (woordverificatie) moeten invullen - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENT_EMAIL - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Lijst met e-mailadressen om meldingen van nieuwe reacties naar te sturen - mikhail.afanasyevich.bulgakov@gmail.com - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENT_FEED - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Het type feed dat voor blogreacties moet worden gegeven - FULL - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENT_FORM_LOCATION - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Locatie van formulier voor blogreacties - EMBEDDED_IFRAME - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENT_MESSAGE - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Bericht bij blogreactie - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENT_MODERATION - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of het modereren van reacties moet worden ingeschakeld - DISABLED - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENT_MODERATION_DELAY - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Aantal dagen waarna nieuwe reacties in aanmerking komen voor moderaten - 14 - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENT_MODERATION_EMAIL - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - E-mailadres waar meldingen binnenkomen over welke nieuwe reacties bewerkt of verwijderd moeten worden - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENT_PROFILE_IMAGES - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of profielafbeeldingen in reacties moeten worden getoond - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENTS_ALLOWED - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of er reacties moeten worden weergegeven - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_COMMENTS_TIME_STAMP_FORMAT - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Getal van de tijdstempelnotatie voor reacties - 29 - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_CONVERT_LINE_BREAKS - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of de regelscheidingen moeten worden omgezet in <br />-tags in de posteditor - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_CUSTOM_ADS_TXT - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - De aangepaste ads.txt-content van de blog die aan advertentiezoekmachines wordt getoond. - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_CUSTOM_ADS_TXT_ENABLED - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Bepaalt of deze blog aangepaste ads.txt-content aan advertentiezoekmachines toont. - false - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_CUSTOM_PAGE_NOT_FOUND - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - De content die wordt weergegeven wanneer een post of pagina niet is gevonden. - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_CUSTOM_ROBOTS_TXT - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - De aangepaste robots.txt-content van de blog wordt aan zoekmachines getoond. - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_CUSTOM_ROBOTS_TXT_ENABLED - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Bepaalt of deze blog aangepaste robots.txt-content aan zoekmachines toont. - false - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_DATE_FORMAT - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Het getal van de datumnotatie voor koppen - 26 - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_DEFAULT_BACKLINKS_MODE - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Standaardbacklinks voor posts - DEFAULT_HAVE_BACKLINKS - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_DEFAULT_COMMENTS_MODE - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Standaardreactie voor posts - DEFAULT_HAVE_COMMENTS - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_DESCRIPTION - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Een beschrijving van de blog - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_EMAIL_POST_LINKS - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of er een link moet worden weergegeven waarmee gebruikers posts kunnen e-mailen - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_FEED_REDIRECT_URL - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - URL waar verzoeken om postfeed naartoe worden geleid - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_FLOAT_ALIGNMENT - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of zwevende uitlijning is ingeschakeld voor de blog - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_LOCALE - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Taal voor deze blog - nl - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_M2B_WHITELIST_EMAIL - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Lijst met e-mailadressen die via e-mail posts op de blog kunnen plaatsen. - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_MAX_NUM - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Maximaal aantal items voor weergave op de hoofdpagina" - 100 - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_MAX_UNIT - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Eenheid van items voor weergave op de hoofdpagina - POSTS - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_META_DESCRIPTION - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - De metabeschrijving van de blog die wordt gebruikt door zoekmachines. - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_META_DESCRIPTION_ENABLED - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Of deze blog wordt weergegeven met metabeschrijvingen. - false - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_NAME - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - De naam van de blog - Notes of a Young Doctor - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_PER_POST_FEED - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Het type feed dat voor reacties op afzonderlijke posts moet worden gegeven - FULL - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_POST_FEED - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Het type feed dat voor blogposts moet worden gegeven - FULL - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_POST_FEED_FOOTER - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Voettekst om aan het einde van iedere vermelding in de postfeed toe te voegen - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_POST_TEMPLATE - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - De template voor blogposts - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_PROMOTED - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of deze blog op Blogger kan worden aangeprezen - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_QUICK_EDITING - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of Snel bewerken is ingeschakeld - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_READ_ACCESS_MODE - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Het type toegang voor de lezers van de blog. - PUBLIC - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_READER_PERMISSION - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - De e-maillijst voor gebruikers die toestemming hebben om de blog te lezen. - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_SEARCHABLE - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of deze blog door zoekmachines moet worden geïndexeerd - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_SEND_EMAIL - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Door komma's gescheiden lijst met e-mailadressen om nieuwe blogposts naar te sturen - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_SHOW_TITLE - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of het titelveld moet worden weergegeven - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_SHOW_URL - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Hier wordt aangegeven of er een verwante link in de postopsteller moet worden weergegeven - false - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_SUBDOMAIN - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Het subdomein van BlogSpot om je blog op te publiceren - youngdoctornotes - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_TIME_STAMP_FORMAT - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Het getal van de tijdstempelnotatie - 27 - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_TIME_ZONE - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - De tijdzone voor deze blog - America/Los_Angeles - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.settings.BLOG_USE_LIGHTBOX - 2010-11-27T07:08:20.877-08:00 - 2018-08-02T12:38:27.320-07:00 - - Of afbeeldingen worden weergegeven in de lightbox wanneer erop wordt geklikt - true - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.post-1276418104709695660 - 2010-11-27T08:21:00.000-08:00 - 2018-08-02T12:22:48.286-07:00 - - yes - - - - - Black as Egypt's Night - Write next story here - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - 0 - - - tag:blogger.com,1999:blog-6303278419262689239.post-1858599377741856733 - 2010-11-27T07:12:00.000-08:00 - 2010-11-27T07:56:43.964-08:00 - - The Steel Windpipe - It was a cold Winter's night.<br /><br /><ul><li>Very cold indeed.</li><br /><li>Note to self: pad out ending</li></ul> - - - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - 1 - - - tag:blogger.com,1999:blog-6303278419262689239.page-4386962582497458967 - 2018-08-02T12:38:00.001-07:00 - 2018-08-02T12:38:27.171-07:00 - - yes - - - Test page 2 - <div dir="ltr" style="text-align: left;" trbidi="on">This is a second test</div> - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.page-1406163839769953231 - 2018-08-02T12:37:00.004-07:00 - 2018-08-02T12:37:47.424-07:00 - - Test page - <div dir="ltr" style="text-align: left;" trbidi="on">This is a test.</div> - - - - - Mikhail Afanasyevich Bulgakov - https://www.blogger.com/profile/000082957 - noreply@blogger.com - - - - - tag:blogger.com,1999:blog-6303278419262689239.post-5590533389087749201 - 2010-11-29T12:35:44.027-08:00 - 2010-11-29T12:35:44.027-08:00 - - Mishka, always a pleasure to read your adventures!... - Mishka, always a pleasure to read your adventures!<br /><br />It's a shame you don't get more time for writing. - - - - - Thomas Isidore Noël Sankara - https://www.blogger.com/profile/0617349827 - noreply@blogger.com - - - - - - - diff --git a/pelican/tests/content/empty.md b/pelican/tests/content/empty.md deleted file mode 100644 index e69de29b..00000000 diff --git a/pelican/tests/content/empty_with_bom.md b/pelican/tests/content/empty_with_bom.md deleted file mode 100644 index e02abfc9..00000000 --- a/pelican/tests/content/empty_with_bom.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/pelican/tests/content/medium_post_content.txt b/pelican/tests/content/medium_post_content.txt deleted file mode 100644 index 5e21881c..00000000 --- a/pelican/tests/content/medium_post_content.txt +++ /dev/null @@ -1,4 +0,0 @@ - -

Title header

A paragraph of content.

Paragraph number two.

A list:

  1. One.
  2. Two.
  3. Three.

A link: link text.

Header 2

A block quote:

quote words strong words

after blockquote

A figure caption.

A final note: Cross-Validated has sometimes been helpful.


Next: Next post -

-

By User Name on .

Canonical link

Exported from Medium on December 1, 2023.

diff --git a/pelican/tests/content/medium_posts/2017-04-21_-medium-post--d1bf01d62ba3.html b/pelican/tests/content/medium_posts/2017-04-21_-medium-post--d1bf01d62ba3.html deleted file mode 100644 index 6d28f1a2..00000000 --- a/pelican/tests/content/medium_posts/2017-04-21_-medium-post--d1bf01d62ba3.html +++ /dev/null @@ -1,72 +0,0 @@ -A title diff --git a/pelican/tests/content/wordpress_content_decoded b/pelican/tests/content/wordpress_content_decoded deleted file mode 100644 index 6e91338c..00000000 --- a/pelican/tests/content/wordpress_content_decoded +++ /dev/null @@ -1,48 +0,0 @@ -

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

-

-

-Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

-

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

-
    -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • -
-
-
-  a = [1, 2, 3]
-  b = [4, 5, 6]
-  for i in zip(a, b):
-    print i
-
-
-

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

diff --git a/pelican/tests/content/wordpress_content_encoded b/pelican/tests/content/wordpress_content_encoded deleted file mode 100644 index eefff1e9..00000000 --- a/pelican/tests/content/wordpress_content_encoded +++ /dev/null @@ -1,54 +0,0 @@ -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum. - - - -
-Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum. - -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -
-
    -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • -
- -
-
-  a = [1, 2, 3]
-  b = [4, 5, 6]
-  for i in zip(a, b):
-    print i
-
-
- -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum. diff --git a/pelican/tests/content/wordpressexport.xml b/pelican/tests/content/wordpressexport.xml deleted file mode 100644 index 81ed7ea3..00000000 --- a/pelican/tests/content/wordpressexport.xml +++ /dev/null @@ -1,1002 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - Pelican test channel - http://thisisa.test - Not a real feed, just for test - Sun, 13 May 2012 01:13:52 +0000 - en - 1.1 - http://thisisa.test - http://thisisa.test - - 2Bobbob@thisisa.test - 3Jonhjonh@thisisa.test - - 7categ-1 - 11categ-2 - 1uncategorized - 15categ-3 - 25tag-1 - 122tag2 - 68tag-3 - - http://wordpress.org/?v=3.3.1 - - - Empty post - http://thisisa.test/?attachment_id=24 - Sat, 04 Feb 2012 03:17:33 +0000 - bob - https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Pelican_lakes_entrance02.jpg/240px-Pelican_lakes_entrance02.jpg - - - - 24 - 2012-02-04 03:17:33 - 2012-02-04 03:17:33 - open - open - empty-post - inherit - 0 - 0 - attachment - - 0 - https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Pelican_lakes_entrance02.jpg/240px-Pelican_lakes_entrance02.jpg - - _wp_attachment_metadata - - - - _wp_attached_file - - - - _wp_attachment_image_alt - - - - - - http://thisisa.test/?p=168 - Thu, 01 Jan 1970 00:00:00 +0000 - bob - http://thisisa.test/?p=168 - - - - 168 - 2012-02-15 21:23:57 - 0000-00-00 00:00:00 - open - open - - draft - 0 - 0 - post - - 0 - - - _edit_last - - - - - A normal post - http://thisisa.test/?p=174 - Thu, 01 Jan 1970 00:00:00 +0000 - bob - http://thisisa.test/?p=174 - - -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • - - -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    - - 174 - 2012-02-16 15:52:55 - 0000-00-00 00:00:00 - open - open - - draft - 0 - 0 - post - - 0 - - - _edit_last - - -
    - - Complete draft - http://thisisa.test/?p=176 - Thu, 01 Jan 1970 00:00:00 +0000 - bob - http://thisisa.test/?p=176 - - - - 176 - 2012-02-17 15:11:55 - 0000-00-00 00:00:00 - open - open - - draft - 0 - 0 - post - - 0 - - - _edit_last - - - - - Page - http://thisisa.test/contact/ - Wed, 11 Apr 2012 11:38:08 +0000 - bob - http://thisisa.test/?page_id=334 - - - - 334 - 2012-04-11 06:38:08 - 2012-04-11 11:38:08 - open - open - contact - publish - 0 - 0 - page - - 0 - - sharing_disabled - - - - _wp_page_template - - - - _edit_last - - - - - Empty Page - http://thisisa.test/empty/ - Wed, 11 Apr 2012 11:38:08 +0000 - bob - http://thisisa.test/?page_id=334 - - - - 334 - 2012-04-11 06:38:08 - 2012-04-11 11:38:08 - open - open - empty - publish - 0 - 0 - page - - 0 - - sharing_disabled - - - - _wp_page_template - - - - _edit_last - - - - - Special chars: l'é - http://thisisa.test/?p=471 - Thu, 01 Jan 1970 00:00:00 +0000 - bob - http://thisisa.test/?p=471 - - - - 471 - 2012-04-29 09:44:27 - 0000-00-00 00:00:00 - open - open - - draft - 0 - 0 - post - - 0 - - - _edit_last - - - - - - With excerpt - http://thisisa.test/with-excerpt/ - Sat, 04 Feb 2012 02:03:06 +0000 - bob - http://thisisa.test/?p=8 - - - - 8 - 2012-02-04 02:03:06 - 2012-02-04 02:03:06 - open - open - with-excerpt - publish - 0 - 0 - post - - 0 - - - - - _edit_last - - - - et_bigpost - - - - _thumbnail_id - - - - - With tags - http://thisisa.test/tags/ - Sat, 04 Feb 2012 21:05:25 +0000 - bob - http://thisisa.test/?p=25 - - - - 25 - 2012-02-04 21:05:25 - 2012-02-04 21:05:25 - open - open - with-tags - publish - 0 - 0 - post - - 0 - - - - - - _edit_last - - - - et_bigpost - - - - _thumbnail_id - - - - - With comments - http://thisisa.test/with-comments/ - Wed, 18 Apr 2012 08:36:26 +0000 - john - http://thisisa.test/?p=422 - - - - 422 - 2012-04-18 03:36:26 - 2012-04-18 08:36:26 - open - open - with-comments - publish - 0 - 0 - post - - 0 - - - _edit_last - - - - _thumbnail_id - - - - 116 - - User2@mail.test - - 127.0.0.1 - 2012-05-06 15:46:06 - 2012-05-06 20:46:06 - - 1 - - 0 - 0 - - akismet_result - - - - akismet_history - - - - akismet_as_submitted - - - - - 117 - - bob@thisisa.test - - 127.0.0.1 - 2012-05-06 17:44:06 - 2012-05-06 22:44:06 - - 1 - - 116 - 3 - - akismet_result - - - - akismet_history - - - - akismet_as_submitted - - - - - 156 - - - http://thisisa.test/to-article-you-ping-back/ - 127.0.0.1 - 2012-05-09 19:30:19 - 2012-05-10 00:30:19 - - trash - pingback - 0 - 0 - - akismet_history - - - - _wp_trash_meta_status - - - - _wp_trash_meta_time - - - - - 122 - - bob@thisisa.test - - 127.0.0.1 - 2012-05-07 14:11:34 - 2012-05-07 19:11:34 - - 1 - - 121 - 3 - - akismet_result - - - - akismet_history - - - - akismet_as_submitted - - - - - - Post with raw data - http://thisisa.test/?p=173 - Thu, 01 Jan 1970 00:00:00 +0000 - bob - http://thisisa.test/?p=173 - - Pelicans are scary - -Pelicans are supposed to eat fish, damn it! - - - -Bottom line: don't mess up with birds - -"That's a 'wonderful' shoe." - -“That’s a ‘magic’ sock.”]]> - - 173 - 2012-02-16 15:52:55 - 0000-00-00 00:00:00 - open - open - post-with-raw-data - publish - 0 - 0 - post - - 0 - - - _edit_last - - - - - A normal post with some <html> entities in the title. You can't miss them. - http://thisisa.test/?p=175 - Thu, 01 Jan 1970 00:00:00 +0000 - bob - http://thisisa.test/?p=175 - - -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • - - -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    - - 175 - 2012-02-16 15:52:55 - 0000-00-00 00:00:00 - open - open - html-entity-test - publish - 0 - 0 - post - - 0 - - - _edit_last - - -
    - - Code in List - http://thisisa.test/?p=175 - Thu, 01 Jan 1970 00:00:00 +0000 - bob - http://thisisa.test/?p=175 - - -
  • List Item One!
  • -
  • List Item Two!
  • -
  • This is a code sample -
    -
    -  a = [1, 2, 3]
    -  b = [4, 5, 6]
    -  for i in zip(a, b):
    -    print i
    -
    -
  • -
  • List Item Four!
  • - - -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    - - 175 - 2012-02-16 15:52:55 - 0000-00-00 00:00:00 - open - open - code-in-list-test - publish - 0 - 0 - post - - 0 - - - _edit_last - - -
    - - Caption on image - http://thisisa.test/?p=176 - Thu, 01 Jan 1970 00:00:00 +0000 - bob - http://thisisa.test/?p=176 - - [/caption] - -[caption attachment_id="43" align="aligncenter" width="300"] This also a pelican[/caption] - -[caption attachment_id="44" align="aligncenter" width="300"] Yet another pelican[/caption] - -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]> - - 176 - 2012-02-16 15:52:55 - 0000-00-00 00:00:00 - open - open - caption-on-image - publish - 0 - 0 - post - - 0 - - - _edit_last - - - - - A custom post in category 4 - http://thisisa.test/?p=175 - Thu, 01 Jan 1970 00:00:00 +0000 - bob - http://thisisa.test/?p=175 - - -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • - - -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    - - 175 - 2012-02-16 15:52:55 - 0000-00-00 00:00:00 - open - open - custpost1cat4 - publish - 0 - 0 - custom1 - - 0 - - - _edit_last - - -
    - - A custom post in category 5 - http://thisisa.test/?p=176 - Thu, 01 Jan 1970 00:00:00 +0000 - bob - http://thisisa.test/?p=176 - - -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • - - -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    - - 176 - 2012-02-16 15:52:55 - 0000-00-00 00:00:00 - open - open - custpost1cat5 - publish - 0 - 0 - custom1 - - 0 - - - _edit_last - - -
    - - A 2nd custom post type also in category 5 - http://thisisa.test/?p=177 - Thu, 01 Jan 1970 00:00:00 +0000 - bob - http://thisisa.test/?p=177 - - -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • -
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • - - -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    - - 177 - 2012-02-16 15:52:55 - 0000-00-00 00:00:00 - open - open - custpost2cat5 - publish - 0 - 0 - custom2 - - 0 - - - _edit_last - - -
    - - Attachment with a parent - http://thisisa.test/?attachment_id=24 - Sat, 04 Feb 2012 03:17:33 +0000 - bob - http://thisurlisinvalid.notarealdomain/not_an_image.jpg - - - - 25 - 2012-02-04 03:17:33 - 2012-02-04 03:17:33 - open - open - attachment-with-a-parent - inherit - 8 - 0 - attachment - - 0 - http://thisurlisinvalid.notarealdomain/not_an_image.jpg - - _wp_attachment_metadata - - - - _wp_attached_file - - - - _wp_attachment_image_alt - - - - - 2nd Attachment to same parent - http://thisisa.test/?attachment_id=25 - Sat, 04 Feb 2012 03:17:33 +0000 - bob - http://en.wikipedia.org/wiki/File:Pelikan_Walvis_Bay.jpg - - - - 25 - 2012-02-04 03:17:33 - 2012-02-04 03:17:33 - open - open - 2nd[attachment-to-same-parent - inherit - 8 - 0 - attachment - - 0 - http://en.wikipedia.org/wiki/File:Pelikan_Walvis_Bay.jpg - - _wp_attachment_metadata - - - - _wp_attached_file - - - - _wp_attachment_image_alt - - - - - Attachment with a different parent - http://thisisa.test/?attachment_id=26 - Sat, 04 Feb 2012 03:17:33 +0000 - bob - http://thisurlisinvalid.notarealdomain - - - - 25 - 2012-02-04 03:17:33 - 2012-02-04 03:17:33 - open - open - attachment-with-a-different-parent - inherit - 25 - 0 - attachment - - 0 - http://thisurlisinvalid.notarealdomain - - _wp_attachment_metadata - - - - _wp_attached_file - - - - _wp_attachment_image_alt - - - -
    -
    diff --git a/pelican/tests/cyclic_intersite_links/first-article.rst b/pelican/tests/cyclic_intersite_links/first-article.rst deleted file mode 100644 index b9eb3f93..00000000 --- a/pelican/tests/cyclic_intersite_links/first-article.rst +++ /dev/null @@ -1,7 +0,0 @@ -First article -############# - -:date: 2018-11-10 -:summary: Here's the `second <{filename}/second-article.rst>`_, - `third <{filename}/third-article.rst>`_ and a - `nonexistent article <{filename}/nonexistent.rst>`_. diff --git a/pelican/tests/cyclic_intersite_links/second-article.rst b/pelican/tests/cyclic_intersite_links/second-article.rst deleted file mode 100644 index acb87d47..00000000 --- a/pelican/tests/cyclic_intersite_links/second-article.rst +++ /dev/null @@ -1,7 +0,0 @@ -Second article -############## - -:date: 2018-11-10 -:summary: Here's the `first <{filename}/first-article.rst>`_, - `third <{filename}/third-article.rst>`_ and a - `nonexistent article <{filename}/nonexistent.rst>`_. diff --git a/pelican/tests/cyclic_intersite_links/third-article.rst b/pelican/tests/cyclic_intersite_links/third-article.rst deleted file mode 100644 index 4c7c1b76..00000000 --- a/pelican/tests/cyclic_intersite_links/third-article.rst +++ /dev/null @@ -1,7 +0,0 @@ -Third article -############# - -:date: 2018-11-10 -:summary: Here's the `first <{filename}/first-article.rst>`_, - `second <{filename}/second-article.rst>`_ and a - `nonexistent article <{filename}/nonexistent.rst>`_. diff --git a/pelican/tests/default_conf.py b/pelican/tests/default_conf.py deleted file mode 100644 index 583c3253..00000000 --- a/pelican/tests/default_conf.py +++ /dev/null @@ -1,48 +0,0 @@ -AUTHOR = "Alexis Métaireau" -SITENAME = "Alexis' log" -SITEURL = "http://blog.notmyidea.org" -TIMEZONE = "UTC" - -GITHUB_URL = "http://github.com/ametaireau/" -DISQUS_SITENAME = "blog-notmyidea" -PDF_GENERATOR = False -REVERSE_CATEGORY_ORDER = True -DEFAULT_PAGINATION = 2 - -FEED_RSS = "feeds/all.rss.xml" -CATEGORY_FEED_RSS = "feeds/{slug}.rss.xml" - -LINKS = ( - ("Biologeek", "http://biologeek.org"), - ("Filyb", "http://filyb.info/"), - ("Libert-fr", "http://www.libert-fr.com"), - ("N1k0", "http://prendreuncafe.com/blog/"), - ("Tarek Ziadé", "http://ziade.org/blog"), - ("Zubin Mithra", "http://zubin71.wordpress.com/"), -) - -SOCIAL = ( - ("twitter", "http://twitter.com/ametaireau"), - ("lastfm", "http://lastfm.com/user/akounet"), - ("github", "http://github.com/ametaireau"), -) - -# global metadata to all the contents -DEFAULT_METADATA = {"yeah": "it is"} - -# path-specific metadata -EXTRA_PATH_METADATA = { - "extra/robots.txt": {"path": "robots.txt"}, -} - -# static paths will be copied without parsing their contents -STATIC_PATHS = [ - "pictures", - "extra/robots.txt", -] - -FORMATTED_FIELDS = ["summary", "custom_formatted_field"] - -# foobar will not be used, because it's not in caps. All configuration keys -# have to be in caps -foobar = "barbaz" diff --git a/pelican/tests/dummy_plugins/namespace_plugin/pelican/plugins/ns_plugin/__init__.py b/pelican/tests/dummy_plugins/namespace_plugin/pelican/plugins/ns_plugin/__init__.py deleted file mode 100644 index 1979cf09..00000000 --- a/pelican/tests/dummy_plugins/namespace_plugin/pelican/plugins/ns_plugin/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -NAME = "namespace plugin" - - -def register(): - pass diff --git a/pelican/tests/dummy_plugins/normal_plugin/normal_plugin/__init__.py b/pelican/tests/dummy_plugins/normal_plugin/normal_plugin/__init__.py deleted file mode 100644 index e714c7a6..00000000 --- a/pelican/tests/dummy_plugins/normal_plugin/normal_plugin/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .submodule import noop # noqa: F401 - - -def register(): - pass diff --git a/pelican/tests/dummy_plugins/normal_plugin/normal_plugin/submodule.py b/pelican/tests/dummy_plugins/normal_plugin/normal_plugin/submodule.py deleted file mode 100644 index ba9c8f94..00000000 --- a/pelican/tests/dummy_plugins/normal_plugin/normal_plugin/submodule.py +++ /dev/null @@ -1,2 +0,0 @@ -def noop(): - pass diff --git a/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/__init__.py b/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subpackage/__init__.py b/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subpackage/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subpackage/subpackage.py b/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subpackage/subpackage.py deleted file mode 100644 index 9e12b19f..00000000 --- a/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subpackage/subpackage.py +++ /dev/null @@ -1,2 +0,0 @@ -def register(): - pass diff --git a/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subplugin.py b/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subplugin.py deleted file mode 100644 index 9e12b19f..00000000 --- a/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subplugin.py +++ /dev/null @@ -1,2 +0,0 @@ -def register(): - pass diff --git a/pelican/tests/mixed_content/fake_image.jpg b/pelican/tests/mixed_content/fake_image.jpg deleted file mode 100644 index e69de29b..00000000 diff --git a/pelican/tests/mixed_content/short_page.md b/pelican/tests/mixed_content/short_page.md deleted file mode 100644 index 46ca45ac..00000000 --- a/pelican/tests/mixed_content/short_page.md +++ /dev/null @@ -1,3 +0,0 @@ -Title: Short Page - -This is a page with little text. diff --git a/pelican/tests/mixed_content/subdir/subdir_fake_image.jpg b/pelican/tests/mixed_content/subdir/subdir_fake_image.jpg deleted file mode 100644 index e69de29b..00000000 diff --git a/pelican/tests/nested_content/maindir/maindir.md b/pelican/tests/nested_content/maindir/maindir.md deleted file mode 100644 index 443e1827..00000000 --- a/pelican/tests/nested_content/maindir/maindir.md +++ /dev/null @@ -1,3 +0,0 @@ -Title: Main Dir Page - -This page lives in maindir. diff --git a/pelican/tests/nested_content/maindir/subdir/subdir.md b/pelican/tests/nested_content/maindir/subdir/subdir.md deleted file mode 100644 index 32e73617..00000000 --- a/pelican/tests/nested_content/maindir/subdir/subdir.md +++ /dev/null @@ -1,3 +0,0 @@ -Title: Subdir Page - -This page lives in maindir/subdir. diff --git a/pelican/tests/output/basic/a-markdown-powered-article.html b/pelican/tests/output/basic/a-markdown-powered-article.html deleted file mode 100644 index 66136d87..00000000 --- a/pelican/tests/output/basic/a-markdown-powered-article.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - A markdown powered article - - - - - - - -
    - -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/archives.html b/pelican/tests/output/basic/archives.html deleted file mode 100644 index 7aa6b263..00000000 --- a/pelican/tests/output/basic/archives.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - A Pelican Blog - - - - - - -
    -

    Archives for A Pelican Blog

    - -
    -
    Fri 30 November 2012
    -
    FILENAME_METADATA example
    -
    Wed 29 February 2012
    -
    Second article
    -
    Wed 20 April 2011
    -
    A markdown powered article
    -
    Thu 17 February 2011
    -
    Article 1
    -
    Thu 17 February 2011
    -
    Article 2
    -
    Thu 17 February 2011
    -
    Article 3
    -
    Thu 02 December 2010
    -
    This is a super article !
    -
    Wed 20 October 2010
    -
    Oh yeah !
    -
    Fri 15 October 2010
    -
    Unbelievable !
    -
    Sun 14 March 2010
    -
    The baz tag
    -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/article-1.html b/pelican/tests/output/basic/article-1.html deleted file mode 100644 index 4ec2a0e1..00000000 --- a/pelican/tests/output/basic/article-1.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - Article 1 - - - - - - - -
    -
    -
    -

    - Article 1

    -
    - -
    -
    - - Published: Thu 17 February 2011 - - -

    In cat1.

    - -

    Article 1

    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/article-2.html b/pelican/tests/output/basic/article-2.html deleted file mode 100644 index 99819902..00000000 --- a/pelican/tests/output/basic/article-2.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - Article 2 - - - - - - - -
    -
    -
    -

    - Article 2

    -
    - -
    -
    - - Published: Thu 17 February 2011 - - -

    In cat1.

    - -

    Article 2

    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/article-3.html b/pelican/tests/output/basic/article-3.html deleted file mode 100644 index 596db91f..00000000 --- a/pelican/tests/output/basic/article-3.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - Article 3 - - - - - - - -
    -
    -
    -

    - Article 3

    -
    - -
    -
    - - Published: Thu 17 February 2011 - - -

    In cat1.

    - -

    Article 3

    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/author/alexis-metaireau.html b/pelican/tests/output/basic/author/alexis-metaireau.html deleted file mode 100644 index e4bde41d..00000000 --- a/pelican/tests/output/basic/author/alexis-metaireau.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - A Pelican Blog - Alexis Métaireau - - - - - - - - -
    -

    Other articles

    -
    -
      - -
    1. -
      -

      Oh yeah !

      -
      - -
      -
      -

      Why not ?

      -

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

      - alternate text -
      - - read more -
      -
    2. -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/authors.html b/pelican/tests/output/basic/authors.html deleted file mode 100644 index 27d10c2f..00000000 --- a/pelican/tests/output/basic/authors.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - A Pelican Blog - Authors - - - - - - - -
    -

    Authors on A Pelican Blog

    - -
    - -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/categories.html b/pelican/tests/output/basic/categories.html deleted file mode 100644 index 5c85b20e..00000000 --- a/pelican/tests/output/basic/categories.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - A Pelican Blog - Categories - - - - - - - -
    -

    Categories for A Pelican Blog

    - -
    - -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/category/bar.html b/pelican/tests/output/basic/category/bar.html deleted file mode 100644 index e89375bf..00000000 --- a/pelican/tests/output/basic/category/bar.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - A Pelican Blog - bar - - - - - - - - -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/category/cat1.html b/pelican/tests/output/basic/category/cat1.html deleted file mode 100644 index 6c0cd64c..00000000 --- a/pelican/tests/output/basic/category/cat1.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - A Pelican Blog - cat1 - - - - - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. - -
    3. -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/category/misc.html b/pelican/tests/output/basic/category/misc.html deleted file mode 100644 index fa9eb563..00000000 --- a/pelican/tests/output/basic/category/misc.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - A Pelican Blog - misc - - - - - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. - -
    3. -
      -

      The baz tag

      -
      - -
      -
      - - Published: Sun 14 March 2010 - - -

      In misc.

      - -

      This article overrides the listening of the articles under the baz tag.

      - - read more -
      -
    4. -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/category/yeah.html b/pelican/tests/output/basic/category/yeah.html deleted file mode 100644 index ab08cc58..00000000 --- a/pelican/tests/output/basic/category/yeah.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - A Pelican Blog - yeah - - - - - - - - -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/drafts/a-draft-article-without-date.html b/pelican/tests/output/basic/drafts/a-draft-article-without-date.html deleted file mode 100644 index 50b72e72..00000000 --- a/pelican/tests/output/basic/drafts/a-draft-article-without-date.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - A draft article without date - - - - - - - -
    -
    -
    -

    - A draft article without date

    -
    - -
    -
    - - Published: - - -

    In misc.

    - -

    This is a draft article, it should live under the /drafts/ folder and not be - listed anywhere else.

    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/drafts/a-draft-article.html b/pelican/tests/output/basic/drafts/a-draft-article.html deleted file mode 100644 index b9125549..00000000 --- a/pelican/tests/output/basic/drafts/a-draft-article.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - A draft article - - - - - - - -
    -
    -
    -

    - A draft article

    -
    - -
    -
    - - Published: Sun 08 May 2011 - - -

    In misc.

    - -

    This is a draft article, it should live under the /drafts/ folder and not be - listed anywhere else.

    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/feeds/alexis-metaireau.atom.xml b/pelican/tests/output/basic/feeds/alexis-metaireau.atom.xml deleted file mode 100644 index a0306a0b..00000000 --- a/pelican/tests/output/basic/feeds/alexis-metaireau.atom.xml +++ /dev/null @@ -1,22 +0,0 @@ - -A Pelican Blog - Alexis Métaireau/2013-11-17T23:29:00+00:00This is a super article !2010-12-02T10:14:00+00:002013-11-17T23:29:00+00:00Alexis Métaireautag:None,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> -Oh yeah !2010-10-20T10:14:00+00:002010-10-20T10:14:00+00:00Alexis Métaireautag:None,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> - diff --git a/pelican/tests/output/basic/feeds/alexis-metaireau.rss.xml b/pelican/tests/output/basic/feeds/alexis-metaireau.rss.xml deleted file mode 100644 index d4989286..00000000 --- a/pelican/tests/output/basic/feeds/alexis-metaireau.rss.xml +++ /dev/null @@ -1,10 +0,0 @@ - -A Pelican Blog - Alexis Métaireau/Sun, 17 Nov 2013 23:29:00 +0000This is a super article !/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0000tag:None,2010-12-02:/this-is-a-super-article.htmlyeahfoobarfoobarOh yeah !/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0000tag:None,2010-10-20:/oh-yeah.htmlbarohbaryeah diff --git a/pelican/tests/output/basic/feeds/all-en.atom.xml b/pelican/tests/output/basic/feeds/all-en.atom.xml deleted file mode 100644 index 49c76c62..00000000 --- a/pelican/tests/output/basic/feeds/all-en.atom.xml +++ /dev/null @@ -1,74 +0,0 @@ - -A Pelican Blog/2013-11-17T23:29:00+00:00FILENAME_METADATA example2012-11-30T00:00:00+00:002012-11-30T00:00:00+00:00tag:None,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> -Second article2012-02-29T00:00:00+00:002012-02-29T00:00:00+00:00tag:None,2012-02-29:/second-article.html<p>This is some article, in english</p> -A markdown powered article2011-04-20T00:00:00+00:002011-04-20T00:00:00+00:00tag:None,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> -<p><a href="/unbelievable.html">a root-relative link to unbelievable</a> -<a href="/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-1.html<p>Article 1</p> -Article 22011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-2.html<p>Article 2</p> -Article 32011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-3.html<p>Article 3</p> -This is a super article !2010-12-02T10:14:00+00:002013-11-17T23:29:00+00:00Alexis Métaireautag:None,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> -Oh yeah !2010-10-20T10:14:00+00:002010-10-20T10:14:00+00:00Alexis Métaireautag:None,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Unbelievable !2010-10-15T20:30:00+00:002010-10-15T20:30:00+00:00tag:None,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will have nothing in default.</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-more-sourcecode-directives"> -<h2>Testing more sourcecode directives</h2> -<div class="highlight"><pre><span></span><span id="foo-8"><a id="foo-8" name="foo-8"></a><a href="#foo-8"><span class="linenos special"> 8</span></a><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a id="foo-9" name="foo-9"></a><a href="#foo-9"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a id="foo-10" name="foo-10"></a><a href="#foo-10"><span class="linenos special">10</span></a> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a id="foo-11" name="foo-11"></a><a href="#foo-11"><span class="linenos"> </span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a id="foo-12" name="foo-12"></a><a href="#foo-12"><span class="linenos special">12</span></a> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a id="foo-13" name="foo-13"></a><a href="#foo-13"><span class="linenos"> </span></a> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a id="foo-14" name="foo-14"></a><a href="#foo-14"><span class="linenos special">14</span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a id="foo-15" name="foo-15"></a><a href="#foo-15"><span class="linenos"> </span></a><br></span><span id="foo-16"><a id="foo-16" name="foo-16"></a><a href="#foo-16"><span class="linenos special">16</span></a> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a id="foo-17" name="foo-17"></a><a href="#foo-17"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a id="foo-18" name="foo-18"></a><a href="#foo-18"><span class="linenos special">18</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a id="foo-19" name="foo-19"></a><a href="#foo-19"><span class="linenos"> </span></a><br></span><span id="foo-20"><a id="foo-20" name="foo-20"></a><a href="#foo-20"><span class="linenos special">20</span></a> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a id="foo-21" name="foo-21"></a><a href="#foo-21"><span class="linenos"> </span></a> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a id="foo-22" name="foo-22"></a><a href="#foo-22"><span class="linenos special">22</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingkc">True</span><br></span><span id="foo-23"><a id="foo-23" name="foo-23"></a><a href="#foo-23"><span class="linenos"> </span></a><br></span><span id="foo-24"><a id="foo-24" name="foo-24"></a><a href="#foo-24"><span class="linenos special">24</span></a> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a id="foo-25" name="foo-25"></a><a href="#foo-25"><span class="linenos"> </span></a> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingkc">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a id="foo-26" name="foo-26"></a><a href="#foo-26"><span class="linenos special">26</span></a> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a id="foo-27" name="foo-27"></a><a href="#foo-27"><span class="linenos"> </span></a> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingnb">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-even-more-sourcecode-directives"> -<h2>Testing even more sourcecode directives</h2> -<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -<p>Lovely.</p> -</div> -<div class="section" id="testing-overriding-config-defaults"> -<h2>Testing overriding config defaults</h2> -<p>Even if the default is line numbers, we can override it here</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -The baz tag2010-03-14T00:00:00+00:002010-03-14T00:00:00+00:00tag:None,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> - diff --git a/pelican/tests/output/basic/feeds/all-fr.atom.xml b/pelican/tests/output/basic/feeds/all-fr.atom.xml deleted file mode 100644 index bca3d2cb..00000000 --- a/pelican/tests/output/basic/feeds/all-fr.atom.xml +++ /dev/null @@ -1,4 +0,0 @@ - -A Pelican Blog/2012-02-29T00:00:00+00:00Deuxième article2012-02-29T00:00:00+00:002012-02-29T00:00:00+00:00tag:None,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> -Trop bien !2010-10-20T10:14:00+00:002010-10-20T10:14:00+00:00tag:None,2010-10-20:/oh-yeah-fr.html<p>Et voila du contenu en français</p> - diff --git a/pelican/tests/output/basic/feeds/all.atom.xml b/pelican/tests/output/basic/feeds/all.atom.xml deleted file mode 100644 index b2399afe..00000000 --- a/pelican/tests/output/basic/feeds/all.atom.xml +++ /dev/null @@ -1,76 +0,0 @@ - -A Pelican Blog/2013-11-17T23:29:00+00:00FILENAME_METADATA example2012-11-30T00:00:00+00:002012-11-30T00:00:00+00:00tag:None,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> -Second article2012-02-29T00:00:00+00:002012-02-29T00:00:00+00:00tag:None,2012-02-29:/second-article.html<p>This is some article, in english</p> -Deuxième article2012-02-29T00:00:00+00:002012-02-29T00:00:00+00:00tag:None,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> -A markdown powered article2011-04-20T00:00:00+00:002011-04-20T00:00:00+00:00tag:None,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> -<p><a href="/unbelievable.html">a root-relative link to unbelievable</a> -<a href="/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-1.html<p>Article 1</p> -Article 22011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-2.html<p>Article 2</p> -Article 32011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-3.html<p>Article 3</p> -This is a super article !2010-12-02T10:14:00+00:002013-11-17T23:29:00+00:00Alexis Métaireautag:None,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> -Oh yeah !2010-10-20T10:14:00+00:002010-10-20T10:14:00+00:00Alexis Métaireautag:None,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Trop bien !2010-10-20T10:14:00+00:002010-10-20T10:14:00+00:00tag:None,2010-10-20:/oh-yeah-fr.html<p>Et voila du contenu en français</p> -Unbelievable !2010-10-15T20:30:00+00:002010-10-15T20:30:00+00:00tag:None,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will have nothing in default.</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-more-sourcecode-directives"> -<h2>Testing more sourcecode directives</h2> -<div class="highlight"><pre><span></span><span id="foo-8"><a id="foo-8" name="foo-8"></a><a href="#foo-8"><span class="linenos special"> 8</span></a><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a id="foo-9" name="foo-9"></a><a href="#foo-9"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a id="foo-10" name="foo-10"></a><a href="#foo-10"><span class="linenos special">10</span></a> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a id="foo-11" name="foo-11"></a><a href="#foo-11"><span class="linenos"> </span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a id="foo-12" name="foo-12"></a><a href="#foo-12"><span class="linenos special">12</span></a> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a id="foo-13" name="foo-13"></a><a href="#foo-13"><span class="linenos"> </span></a> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a id="foo-14" name="foo-14"></a><a href="#foo-14"><span class="linenos special">14</span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a id="foo-15" name="foo-15"></a><a href="#foo-15"><span class="linenos"> </span></a><br></span><span id="foo-16"><a id="foo-16" name="foo-16"></a><a href="#foo-16"><span class="linenos special">16</span></a> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a id="foo-17" name="foo-17"></a><a href="#foo-17"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a id="foo-18" name="foo-18"></a><a href="#foo-18"><span class="linenos special">18</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a id="foo-19" name="foo-19"></a><a href="#foo-19"><span class="linenos"> </span></a><br></span><span id="foo-20"><a id="foo-20" name="foo-20"></a><a href="#foo-20"><span class="linenos special">20</span></a> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a id="foo-21" name="foo-21"></a><a href="#foo-21"><span class="linenos"> </span></a> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a id="foo-22" name="foo-22"></a><a href="#foo-22"><span class="linenos special">22</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingkc">True</span><br></span><span id="foo-23"><a id="foo-23" name="foo-23"></a><a href="#foo-23"><span class="linenos"> </span></a><br></span><span id="foo-24"><a id="foo-24" name="foo-24"></a><a href="#foo-24"><span class="linenos special">24</span></a> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a id="foo-25" name="foo-25"></a><a href="#foo-25"><span class="linenos"> </span></a> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingkc">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a id="foo-26" name="foo-26"></a><a href="#foo-26"><span class="linenos special">26</span></a> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a id="foo-27" name="foo-27"></a><a href="#foo-27"><span class="linenos"> </span></a> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingnb">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-even-more-sourcecode-directives"> -<h2>Testing even more sourcecode directives</h2> -<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -<p>Lovely.</p> -</div> -<div class="section" id="testing-overriding-config-defaults"> -<h2>Testing overriding config defaults</h2> -<p>Even if the default is line numbers, we can override it here</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -The baz tag2010-03-14T00:00:00+00:002010-03-14T00:00:00+00:00tag:None,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> - diff --git a/pelican/tests/output/basic/feeds/bar.atom.xml b/pelican/tests/output/basic/feeds/bar.atom.xml deleted file mode 100644 index 93fff29c..00000000 --- a/pelican/tests/output/basic/feeds/bar.atom.xml +++ /dev/null @@ -1,8 +0,0 @@ - -A Pelican Blog - bar/2010-10-20T10:14:00+00:00Oh yeah !2010-10-20T10:14:00+00:002010-10-20T10:14:00+00:00Alexis Métaireautag:None,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> - diff --git a/pelican/tests/output/basic/feeds/cat1.atom.xml b/pelican/tests/output/basic/feeds/cat1.atom.xml deleted file mode 100644 index 2f054a1c..00000000 --- a/pelican/tests/output/basic/feeds/cat1.atom.xml +++ /dev/null @@ -1,7 +0,0 @@ - -A Pelican Blog - cat1/2011-04-20T00:00:00+00:00A markdown powered article2011-04-20T00:00:00+00:002011-04-20T00:00:00+00:00tag:None,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> -<p><a href="/unbelievable.html">a root-relative link to unbelievable</a> -<a href="/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-1.html<p>Article 1</p> -Article 22011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-2.html<p>Article 2</p> -Article 32011-02-17T00:00:00+00:002011-02-17T00:00:00+00:00tag:None,2011-02-17:/article-3.html<p>Article 3</p> - diff --git a/pelican/tests/output/basic/feeds/misc.atom.xml b/pelican/tests/output/basic/feeds/misc.atom.xml deleted file mode 100644 index 9127b2a5..00000000 --- a/pelican/tests/output/basic/feeds/misc.atom.xml +++ /dev/null @@ -1,49 +0,0 @@ - -A Pelican Blog - misc/2012-11-30T00:00:00+00:00FILENAME_METADATA example2012-11-30T00:00:00+00:002012-11-30T00:00:00+00:00tag:None,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> -Second article2012-02-29T00:00:00+00:002012-02-29T00:00:00+00:00tag:None,2012-02-29:/second-article.html<p>This is some article, in english</p> -Unbelievable !2010-10-15T20:30:00+00:002010-10-15T20:30:00+00:00tag:None,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will have nothing in default.</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-more-sourcecode-directives"> -<h2>Testing more sourcecode directives</h2> -<div class="highlight"><pre><span></span><span id="foo-8"><a id="foo-8" name="foo-8"></a><a href="#foo-8"><span class="linenos special"> 8</span></a><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a id="foo-9" name="foo-9"></a><a href="#foo-9"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a id="foo-10" name="foo-10"></a><a href="#foo-10"><span class="linenos special">10</span></a> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a id="foo-11" name="foo-11"></a><a href="#foo-11"><span class="linenos"> </span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a id="foo-12" name="foo-12"></a><a href="#foo-12"><span class="linenos special">12</span></a> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a id="foo-13" name="foo-13"></a><a href="#foo-13"><span class="linenos"> </span></a> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a id="foo-14" name="foo-14"></a><a href="#foo-14"><span class="linenos special">14</span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a id="foo-15" name="foo-15"></a><a href="#foo-15"><span class="linenos"> </span></a><br></span><span id="foo-16"><a id="foo-16" name="foo-16"></a><a href="#foo-16"><span class="linenos special">16</span></a> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a id="foo-17" name="foo-17"></a><a href="#foo-17"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a id="foo-18" name="foo-18"></a><a href="#foo-18"><span class="linenos special">18</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a id="foo-19" name="foo-19"></a><a href="#foo-19"><span class="linenos"> </span></a><br></span><span id="foo-20"><a id="foo-20" name="foo-20"></a><a href="#foo-20"><span class="linenos special">20</span></a> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a id="foo-21" name="foo-21"></a><a href="#foo-21"><span class="linenos"> </span></a> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a id="foo-22" name="foo-22"></a><a href="#foo-22"><span class="linenos special">22</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingkc">True</span><br></span><span id="foo-23"><a id="foo-23" name="foo-23"></a><a href="#foo-23"><span class="linenos"> </span></a><br></span><span id="foo-24"><a id="foo-24" name="foo-24"></a><a href="#foo-24"><span class="linenos special">24</span></a> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a id="foo-25" name="foo-25"></a><a href="#foo-25"><span class="linenos"> </span></a> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingkc">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a id="foo-26" name="foo-26"></a><a href="#foo-26"><span class="linenos special">26</span></a> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a id="foo-27" name="foo-27"></a><a href="#foo-27"><span class="linenos"> </span></a> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingnb">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-even-more-sourcecode-directives"> -<h2>Testing even more sourcecode directives</h2> -<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -<p>Lovely.</p> -</div> -<div class="section" id="testing-overriding-config-defaults"> -<h2>Testing overriding config defaults</h2> -<p>Even if the default is line numbers, we can override it here</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -The baz tag2010-03-14T00:00:00+00:002010-03-14T00:00:00+00:00tag:None,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> - diff --git a/pelican/tests/output/basic/feeds/yeah.atom.xml b/pelican/tests/output/basic/feeds/yeah.atom.xml deleted file mode 100644 index 6411bf6d..00000000 --- a/pelican/tests/output/basic/feeds/yeah.atom.xml +++ /dev/null @@ -1,16 +0,0 @@ - -A Pelican Blog - yeah/2013-11-17T23:29:00+00:00This is a super article !2010-12-02T10:14:00+00:002013-11-17T23:29:00+00:00Alexis Métaireautag:None,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> - diff --git a/pelican/tests/output/basic/filename_metadata-example.html b/pelican/tests/output/basic/filename_metadata-example.html deleted file mode 100644 index d66c30fc..00000000 --- a/pelican/tests/output/basic/filename_metadata-example.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - FILENAME_METADATA example - - - - - - - -
    - -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/index.html b/pelican/tests/output/basic/index.html deleted file mode 100644 index 0436d17b..00000000 --- a/pelican/tests/output/basic/index.html +++ /dev/null @@ -1,275 +0,0 @@ - - - - - - - A Pelican Blog - - - - - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. - -
    3. - -
    4. - -
    5. - -
    6. - -
    7. -
      -

      Oh yeah !

      -
      - -
      -
      -

      Why not ?

      -

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

      - alternate text -
      - - read more -
      -
    8. - -
    9. - -
    10. -
      -

      The baz tag

      -
      - -
      -
      - - Published: Sun 14 March 2010 - - -

      In misc.

      - -

      This article overrides the listening of the articles under the baz tag.

      - - read more -
      -
    11. -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/oh-yeah-fr.html b/pelican/tests/output/basic/oh-yeah-fr.html deleted file mode 100644 index 1fbf47c5..00000000 --- a/pelican/tests/output/basic/oh-yeah-fr.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - Trop bien ! - - - - - - - - - -
    -
    -
    -

    - Trop bien !

    -
    - -
    -
    - - Published: Wed 20 October 2010 - - -

    In misc.

    - Translations: - en - -

    Et voila du contenu en français

    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/oh-yeah.html b/pelican/tests/output/basic/oh-yeah.html deleted file mode 100644 index bcea5a93..00000000 --- a/pelican/tests/output/basic/oh-yeah.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - Oh yeah ! - - - - - - - - - -
    -
    -
    -

    - Oh yeah !

    -
    - -
    -
    -

    Why not ?

    -

    After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

    - alternate text -
    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/override/index.html b/pelican/tests/output/basic/override/index.html deleted file mode 100644 index 68e97792..00000000 --- a/pelican/tests/output/basic/override/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - Override url/save_as - - - - - - -
    -

    Override url/save_as

    - -

    Test page which overrides save_as and url so that this page will be generated - at a custom location.

    - -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/pages/this-is-a-test-hidden-page.html b/pelican/tests/output/basic/pages/this-is-a-test-hidden-page.html deleted file mode 100644 index b96b722c..00000000 --- a/pelican/tests/output/basic/pages/this-is-a-test-hidden-page.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - This is a test hidden page - - - - - - -
    -

    This is a test hidden page

    - -

    This is great for things like error(404) pages - Anyone can see this page but it's not linked to anywhere!

    - -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/pages/this-is-a-test-page.html b/pelican/tests/output/basic/pages/this-is-a-test-page.html deleted file mode 100644 index e6e7ead4..00000000 --- a/pelican/tests/output/basic/pages/this-is-a-test-page.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - This is a test page - - - - - - -
    -

    This is a test page

    - -

    Just an image.

    - alternate text - wrong path since 'images' folder does not exist - -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/pictures/Fat_Cat.jpg b/pelican/tests/output/basic/pictures/Fat_Cat.jpg deleted file mode 100644 index d8a96d35..00000000 Binary files a/pelican/tests/output/basic/pictures/Fat_Cat.jpg and /dev/null differ diff --git a/pelican/tests/output/basic/pictures/Sushi.jpg b/pelican/tests/output/basic/pictures/Sushi.jpg deleted file mode 100644 index e49e5f0a..00000000 Binary files a/pelican/tests/output/basic/pictures/Sushi.jpg and /dev/null differ diff --git a/pelican/tests/output/basic/pictures/Sushi_Macro.jpg b/pelican/tests/output/basic/pictures/Sushi_Macro.jpg deleted file mode 100644 index 21f935a1..00000000 Binary files a/pelican/tests/output/basic/pictures/Sushi_Macro.jpg and /dev/null differ diff --git a/pelican/tests/output/basic/second-article-fr.html b/pelican/tests/output/basic/second-article-fr.html deleted file mode 100644 index f0711c64..00000000 --- a/pelican/tests/output/basic/second-article-fr.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - Deuxième article - - - - - - - - - -
    -
    -
    -

    - Deuxième article

    -
    - -
    -
    - - Published: Wed 29 February 2012 - - -

    In misc.

    -

    tags: foo bar baz

    Translations: - en - -

    Ceci est un article, en français.

    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/second-article.html b/pelican/tests/output/basic/second-article.html deleted file mode 100644 index da4699a5..00000000 --- a/pelican/tests/output/basic/second-article.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - Second article - - - - - - - - - -
    -
    -
    -

    - Second article

    -
    - -
    -
    - - Published: Wed 29 February 2012 - - -

    In misc.

    -

    tags: foo bar baz

    Translations: - fr - -

    This is some article, in english

    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/tag/bar.html b/pelican/tests/output/basic/tag/bar.html deleted file mode 100644 index 0a1c7575..00000000 --- a/pelican/tests/output/basic/tag/bar.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - A Pelican Blog - bar - - - - - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. -
      -

      Oh yeah !

      -
      - -
      -
      -

      Why not ?

      -

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

      - alternate text -
      - - read more -
      -
    3. -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/tag/baz.html b/pelican/tests/output/basic/tag/baz.html deleted file mode 100644 index c4b68a5e..00000000 --- a/pelican/tests/output/basic/tag/baz.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - The baz tag - - - - - - - -
    -
    -
    -

    - The baz tag

    -
    - -
    -
    - - Published: Sun 14 March 2010 - - -

    In misc.

    - -

    This article overrides the listening of the articles under the baz tag.

    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/tag/foo.html b/pelican/tests/output/basic/tag/foo.html deleted file mode 100644 index f310efee..00000000 --- a/pelican/tests/output/basic/tag/foo.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - A Pelican Blog - foo - - - - - - - - -
    -

    Other articles

    -
    -
      - -
    1. -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/tag/foobar.html b/pelican/tests/output/basic/tag/foobar.html deleted file mode 100644 index edc1ed9a..00000000 --- a/pelican/tests/output/basic/tag/foobar.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - A Pelican Blog - foobar - - - - - - - - -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/tag/oh.html b/pelican/tests/output/basic/tag/oh.html deleted file mode 100644 index 26dde5e6..00000000 --- a/pelican/tests/output/basic/tag/oh.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - Oh Oh Oh - - - - - - -
    -

    Oh Oh Oh

    - -

    This page overrides the listening of the articles under the oh tag.

    - -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/tag/yeah.html b/pelican/tests/output/basic/tag/yeah.html deleted file mode 100644 index 2e1c4188..00000000 --- a/pelican/tests/output/basic/tag/yeah.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - A Pelican Blog - yeah - - - - - - - - -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/tags.html b/pelican/tests/output/basic/tags.html deleted file mode 100644 index 2bf06525..00000000 --- a/pelican/tests/output/basic/tags.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - A Pelican Blog - Tags - - - - - - - -
    -

    Tags for A Pelican Blog

    - -
    - -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/theme/css/fonts.css b/pelican/tests/output/basic/theme/css/fonts.css deleted file mode 100644 index 7c69215e..00000000 --- a/pelican/tests/output/basic/theme/css/fonts.css +++ /dev/null @@ -1,12 +0,0 @@ -@font-face { - font-family: 'Yanone Kaffeesatz'; - font-style: normal; - font-weight: 400; - src: - local('Yanone Kaffeesatz Regular'), - local('YanoneKaffeesatz-Regular'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff */ - url('../fonts/Yanone_Kaffeesatz_400.woff') format('woff'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLfGwxTS8d1Q9KiDNCMKLFUM.woff2 */ - url('../fonts/Yanone_Kaffeesatz_400.woff2') format('woff2'); -} diff --git a/pelican/tests/output/basic/theme/css/main.css b/pelican/tests/output/basic/theme/css/main.css deleted file mode 100644 index c1d86950..00000000 --- a/pelican/tests/output/basic/theme/css/main.css +++ /dev/null @@ -1,439 +0,0 @@ -/* - Name: Smashing HTML5 - Date: July 2009 - Description: Sample layout for HTML5 and CSS3 goodness. - Version: 1.0 - License: MIT - Licensed by: Smashing Media GmbH - Original author: Enrique Ramírez -*/ - -/* Imports */ -@import url("reset.css"); -@import url("pygment.css"); -@import url("typogrify.css"); -@import url("fonts.css"); - -/***** Global *****/ -/* Body */ -body { - background: #F5F4EF; - color: #000305; - font-size: 87.5%; /* Base font size: 14px */ - font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; - line-height: 1.429; - margin: 0; - padding: 0; - text-align: left; -} - -/* Headings */ -h1 {font-size: 2em } -h2 {font-size: 1.571em} /* 22px */ -h3 {font-size: 1.429em} /* 20px */ -h4 {font-size: 1.286em} /* 18px */ -h5 {font-size: 1.143em} /* 16px */ -h6 {font-size: 1em} /* 14px */ - -h1, h2, h3, h4, h5, h6 { - font-weight: 400; - line-height: 1.1; - margin-bottom: .8em; - font-family: 'Yanone Kaffeesatz', arial, serif; -} - -h3, h4, h5, h6 { margin-top: .8em; } - -hr { border: 2px solid #EEEEEE; } - -/* Anchors */ -a {outline: 0;} -a img {border: 0px; text-decoration: none;} -a:link, a:visited { - color: #C74350; - padding: 0 1px; - text-decoration: underline; -} -a:hover, a:active { - background-color: #C74350; - color: #fff; - text-decoration: none; - text-shadow: 1px 1px 1px #333; -} - -h1 a:hover { - background-color: inherit -} - -/* Paragraphs */ -div.line-block, -p { margin-top: 1em; - margin-bottom: 1em;} - -strong, b {font-weight: bold;} -em, i {font-style: italic;} - -/* Lists */ -ul { - list-style: outside disc; - margin: 0em 0 0 1.5em; -} - -ol { - list-style: outside decimal; - margin: 0em 0 0 1.5em; -} - -li { margin-top: 0.5em; - margin-bottom: 1em; } - -.post-info { - float:right; - margin:10px; - padding:5px; -} - -.post-info p{ - margin-top: 1px; - margin-bottom: 1px; -} - -.readmore { float: right } - -dl {margin: 0 0 1.5em 0;} -dt {font-weight: bold;} -dd {margin-left: 1.5em;} - -pre{background-color: rgb(238, 238, 238); padding: 10px; margin: 10px; overflow: auto;} - -/* Quotes */ -blockquote { - margin: 20px; - font-style: italic; -} -cite {} - -q {} - -div.note { - float: right; - margin: 5px; - font-size: 85%; - max-width: 300px; -} - -/* Tables */ -table {margin: .5em auto 1.5em auto; width: 98%;} - - /* Thead */ -thead th {padding: .5em .4em; text-align: left;} -thead td {} - - /* Tbody */ -tbody td {padding: .5em .4em;} -tbody th {} - -tbody .alt td {} -tbody .alt th {} - - /* Tfoot */ -tfoot th {} -tfoot td {} - -/* HTML5 tags */ -header, section, footer, -aside, nav, article, figure { - display: block; -} - -/***** Layout *****/ -.body {clear: both; margin: 0 auto; max-width: 800px;} -img { max-width: 100%; } -img.right, figure.right, div.figure.align-right { - float: right; - margin: 0 0 2em 2em; -} -img.left, figure.left, div.figure.align-left { - float: left; - margin: 0 2em 2em 0; -} - -/* .rst support */ -div.figure img, figure img { /* to fill figure exactly */ - max-width: 100%; -} -div.figure p.caption, figure p.caption { /* margin provided by figure */ - margin-top: 0; - margin-bottom: 0; -} - -/* - Header -*****************/ -#banner { - margin: 0 auto; - padding: 0.8em 0 0 0; -} - - /* Banner */ -#banner h1 { - font-size: 3.571em; - line-height: 1.0; - margin-bottom: .3em; -} - -#banner h1 a:link, #banner h1 a:visited { - color: #000305; - display: block; - font-weight: bold; - margin: 0 0 0 .2em; - text-decoration: none; -} -#banner h1 a:hover, #banner h1 a:active { - background: none; - color: #C74350; - text-shadow: none; -} - -#banner h1 strong {font-size: 0.36em; font-weight: normal;} - - /* Main Nav */ -#banner nav { - background: #000305; - font-size: 1.143em; - overflow: auto; - line-height: 30px; - margin: 0 auto 2em auto; - padding: 0; - text-align: center; - max-width: 800px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} - -#banner nav ul {list-style: none; margin: 0 auto; max-width: 800px;} -#banner nav li {float: left; display: inline; margin: 0;} - -#banner nav a:link, #banner nav a:visited { - color: #fff; - display: inline-block; - height: 30px; - padding: 5px 1.5em; - text-decoration: none; -} -#banner nav a:hover, #banner nav a:active, -#banner nav .active a:link, #banner nav .active a:visited { - background: #C74451; - color: #fff; - text-shadow: none !important; -} - -#banner nav li:first-child a { - border-top-left-radius: 5px; - -moz-border-radius-topleft: 5px; - -webkit-border-top-left-radius: 5px; - - border-bottom-left-radius: 5px; - -moz-border-radius-bottomleft: 5px; - -webkit-border-bottom-left-radius: 5px; -} - -/* - Featured -*****************/ -#featured { - background: #fff; - margin-bottom: 2em; - overflow: hidden; - padding: 20px; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -#featured figure { - border: 2px solid #eee; - float: right; - margin: 0.786em 2em 0 5em; - max-width: 248px; -} -#featured figure img {display: block; float: right;} - -#featured h2 {color: #C74451; font-size: 1.714em; margin-bottom: 0.333em;} -#featured h3 {font-size: 1.429em; margin-bottom: .5em;} - -#featured h3 a:link, #featured h3 a:visited {color: #000305; text-decoration: none;} -#featured h3 a:hover, #featured h3 a:active {color: #fff;} - -/* - Body -*****************/ -#content { - background: #fff; - margin-bottom: 2em; - overflow: hidden; - padding: 20px 20px; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -/* - Extras -*****************/ -#extras {margin: 0 auto 3em auto; overflow: hidden;} - -#extras ul {list-style: none; margin: 0;} -#extras li {border-bottom: 1px solid #fff;} -#extras h2 { - color: #C74350; - font-size: 1.429em; - margin-bottom: .25em; - padding: 0 3px; -} - -#extras a:link, #extras a:visited { - color: #444; - display: block; - border-bottom: 1px solid #F4E3E3; - text-decoration: none; - padding: .3em .25em; -} - -#extras a:hover, #extras a:active {color: #fff;} - - /* Blogroll */ -#extras .blogroll { - float: left; - max-width: 615px; -} - -#extras .blogroll li {float: left; margin: 0 20px 0 0; max-width: 185px;} - - /* Social */ -#extras .social { - float: right; - max-width: 175px; -} - -/* - About -*****************/ -#about { - background: #fff; - font-style: normal; - margin-bottom: 2em; - overflow: hidden; - padding: 20px; - text-align: left; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -#about .primary {float: left; max-width: 165px;} -#about .primary strong {color: #C64350; display: block; font-size: 1.286em;} -#about .photo {float: left; margin: 5px 20px;} - -#about .url:link, #about .url:visited {text-decoration: none;} - -#about .bio {float: right; max-width: 500px;} - -/* - Footer -*****************/ -#contentinfo {padding-bottom: 2em; text-align: right;} - -/***** Sections *****/ -/* Blog */ -.hentry { - display: block; - clear: both; - border-top: 1px solid #eee; - padding: 1.5em 0; -} -li:first-child .hentry, #content > .hentry {border: 0; margin: 0;} -#content > .hentry {padding: 1em 0;} -.hentry img{display : none ;} -.entry-title {font-size: 3em; margin-bottom: 10px; margin-top: 0;} -.entry-title a:link, .entry-title a:visited {text-decoration: none; color: #333;} -.entry-title a:visited {background-color: #fff;} - -.hentry .post-info * {font-style: normal;} - - /* Content */ -.hentry footer {margin-bottom: 2em;} -.hentry footer address {display: inline;} -#posts-list footer address {display: block;} - - /* Blog Index */ -#posts-list {list-style: none; margin: 0;} -#posts-list .hentry {padding-left: 10px; position: relative;} - -#posts-list footer { - left: 10px; - position: relative; - float: left; - top: 0.5em; - max-width: 190px; -} - - /* About the Author */ -#about-author { - background: #f9f9f9; - clear: both; - font-style: normal; - margin: 2em 0; - padding: 10px 20px 15px 20px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} - -#about-author strong { - color: #C64350; - clear: both; - display: block; - font-size: 1.429em; -} - -#about-author .photo {border: 1px solid #ddd; float: left; margin: 5px 1em 0 0;} - - /* Comments */ -#comments-list {list-style: none; margin: 0 1em;} -#comments-list blockquote { - background: #f8f8f8; - clear: both; - font-style: normal; - margin: 0; - padding: 15px 20px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} -#comments-list footer {color: #888; padding: .5em 1em 0 0; text-align: right;} - -#comments-list li:nth-child(2n) blockquote {background: #F5f5f5;} - - /* Add a Comment */ -#add-comment label {clear: left; float: left; text-align: left; max-width: 150px;} -#add-comment input[type='text'], -#add-comment input[type='email'], -#add-comment input[type='url'] {float: left; max-width: 200px;} - -#add-comment textarea {float: left; height: 150px; max-width: 495px;} - -#add-comment p.req {clear: both; margin: 0 .5em 1em 0; text-align: right;} - -#add-comment input[type='submit'] {float: right; margin: 0 .5em;} -#add-comment * {margin-bottom: .5em;} diff --git a/pelican/tests/output/basic/theme/css/pygment.css b/pelican/tests/output/basic/theme/css/pygment.css deleted file mode 100644 index a3877a83..00000000 --- a/pelican/tests/output/basic/theme/css/pygment.css +++ /dev/null @@ -1,205 +0,0 @@ -.hll { - background-color:#eee; -} -.c { - color:#408090; - font-style:italic; -} -.err { - border:1px solid #FF0000; -} -.k { - color:#007020; - font-weight:bold; -} -.o { - color:#666666; -} -.cm { - color:#408090; - font-style:italic; -} -.cp { - color:#007020; -} -.c1 { - color:#408090; - font-style:italic; -} -.cs { - background-color:#FFF0F0; - color:#408090; -} -.gd { - color:#A00000; -} -.ge { - font-style:italic; -} -.gr { - color:#FF0000; -} -.gh { - color:#000080; - font-weight:bold; -} -.gi { - color:#00A000; -} -.go { - color:#303030; -} -.gp { - color:#C65D09; - font-weight:bold; -} -.gs { - font-weight:bold; -} -.gu { - color:#800080; - font-weight:bold; -} -.gt { - color:#0040D0; -} -.kc { - color:#007020; - font-weight:bold; -} -.kd { - color:#007020; - font-weight:bold; -} -.kn { - color:#007020; - font-weight:bold; -} -.kp { - color:#007020; -} -.kr { - color:#007020; - font-weight:bold; -} -.kt { - color:#902000; -} -.m { - color:#208050; -} -.s { - color:#4070A0; -} -.na { - color:#4070A0; -} -.nb { - color:#007020; -} -.nc { - color:#0E84B5; - font-weight:bold; -} -.no { - color:#60ADD5; -} -.nd { - color:#555555; - font-weight:bold; -} -.ni { - color:#D55537; - font-weight:bold; -} -.ne { - color:#007020; -} -.nf { - color:#06287E; -} -.nl { - color:#002070; - font-weight:bold; -} -.nn { - color:#0E84B5; - font-weight:bold; -} -.nt { - color:#062873; - font-weight:bold; -} -.nv { - color:#BB60D5; -} -.ow { - color:#007020; - font-weight:bold; -} -.w { - color:#BBBBBB; -} -.mf { - color:#208050; -} -.mh { - color:#208050; -} -.mi { - color:#208050; -} -.mo { - color:#208050; -} -.sb { - color:#4070A0; -} -.sc { - color:#4070A0; -} -.sd { - color:#4070A0; - font-style:italic; -} -.s2 { - color:#4070A0; -} -.se { - color:#4070A0; - font-weight:bold; -} -.sh { - color:#4070A0; -} -.si { - color:#70A0D0; - font-style:italic; -} -.sx { - color:#C65D09; -} -.sr { - color:#235388; -} -.s1 { - color:#4070A0; -} -.ss { - color:#517918; -} -.bp { - color:#007020; -} -.vc { - color:#BB60D5; -} -.vg { - color:#BB60D5; -} -.vi { - color:#BB60D5; -} -.il { - color:#208050; -} diff --git a/pelican/tests/output/basic/theme/css/reset.css b/pelican/tests/output/basic/theme/css/reset.css deleted file mode 100644 index 10b3fde2..00000000 --- a/pelican/tests/output/basic/theme/css/reset.css +++ /dev/null @@ -1,52 +0,0 @@ -/* - Name: Reset Stylesheet - Description: Resets browser's default CSS - Author: Eric Meyer - Author URI: https://meyerweb.com/eric/tools/css/reset/ -*/ - -/* v1.0 | 20080212 */ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, font, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td { - background: transparent; - border: 0; - font-size: 100%; - margin: 0; - outline: 0; - padding: 0; - vertical-align: baseline; -} - -body {line-height: 1;} - -ol, ul {list-style: none;} - -blockquote, q {quotes: none;} - -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} - -/* remember to define focus styles! */ -:focus { - outline: 0; -} - -/* remember to highlight inserts somehow! */ -ins {text-decoration: none;} -del {text-decoration: line-through;} - -/* tables still need 'cellspacing="0"' in the markup */ -table { - border-collapse: collapse; - border-spacing: 0; -} diff --git a/pelican/tests/output/basic/theme/css/typogrify.css b/pelican/tests/output/basic/theme/css/typogrify.css deleted file mode 100644 index 3bae4976..00000000 --- a/pelican/tests/output/basic/theme/css/typogrify.css +++ /dev/null @@ -1,3 +0,0 @@ -.caps {font-size:.92em;} -.amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;} -.dquo {margin-left:-.38em;} diff --git a/pelican/tests/output/basic/theme/css/wide.css b/pelican/tests/output/basic/theme/css/wide.css deleted file mode 100644 index 88fd59ce..00000000 --- a/pelican/tests/output/basic/theme/css/wide.css +++ /dev/null @@ -1,48 +0,0 @@ -@import url("main.css"); - -body { - font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif; -} - -.post-info{ - display: none; -} - -#banner nav { - display: none; - -moz-border-radius: 0px; - margin-bottom: 20px; - overflow: hidden; - font-size: 1em; - background: #F5F4EF; -} - -#banner nav ul{ - padding-right: 50px; -} - -#banner nav li{ - float: right; - color: #000; -} - -#banner nav li a { - color: #000; -} - -#banner h1 { - margin-bottom: -18px; -} - -#featured, #extras { - padding: 50px; -} - -#featured { - padding-top: 20px; -} - -#extras { - padding-top: 0px; - padding-bottom: 0px; -} diff --git a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.eot b/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.eot deleted file mode 100644 index b3b90dbc..00000000 Binary files a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.eot and /dev/null differ diff --git a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.svg b/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.svg deleted file mode 100644 index a69669b5..00000000 --- a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.svg +++ /dev/null @@ -1,407 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.ttf b/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.ttf deleted file mode 100644 index 6f4feb02..00000000 Binary files a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.ttf and /dev/null differ diff --git a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.woff b/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.woff deleted file mode 100644 index ddccf765..00000000 Binary files a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.woff and /dev/null differ diff --git a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.woff2 b/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.woff2 deleted file mode 100644 index 7b18f7ea..00000000 Binary files a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_400.woff2 and /dev/null differ diff --git a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_LICENSE.txt b/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_LICENSE.txt deleted file mode 100644 index c70bcad3..00000000 --- a/pelican/tests/output/basic/theme/fonts/Yanone_Kaffeesatz_LICENSE.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2010 The Yanone Kaffeesatz Project Authors (https://github.com/alexeiva/yanone-kaffeesatz) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/pelican/tests/output/basic/theme/fonts/font.css b/pelican/tests/output/basic/theme/fonts/font.css deleted file mode 100644 index cf623603..00000000 --- a/pelican/tests/output/basic/theme/fonts/font.css +++ /dev/null @@ -1,12 +0,0 @@ -@font-face { - font-family: 'Yanone Kaffeesatz'; - font-style: normal; - font-weight: 400; - src: - local('Yanone Kaffeesatz Regular'), - local('YanoneKaffeesatz-Regular'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff */ - url('Yanone_Kaffeesatz_400.woff') format('woff'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLfGwxTS8d1Q9KiDNCMKLFUM.woff2 */ - url('Yanone_Kaffeesatz_400.woff2') format('woff2'); -} diff --git a/pelican/tests/output/basic/this-is-a-super-article.html b/pelican/tests/output/basic/this-is-a-super-article.html deleted file mode 100644 index ee5ae26b..00000000 --- a/pelican/tests/output/basic/this-is-a-super-article.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - This is a super article ! - - - - - - - -
    -
    -
    -

    - This is a super article !

    -
    - -
    -

    Some content here !

    -
    -

    This is a simple title

    -

    And here comes the cool stuff.

    - alternate text - alternate text -
    ->>> from ipdb import set_trace
    ->>> set_trace()
    -
    -

    → And now try with some utf8 hell: ééé

    -
    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/basic/unbelievable.html b/pelican/tests/output/basic/unbelievable.html deleted file mode 100644 index 2cd85dcb..00000000 --- a/pelican/tests/output/basic/unbelievable.html +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - Unbelievable ! - - - - - - - -
    -
    -
    -

    - Unbelievable !

    -
    - -
    -
    - - Published: Fri 15 October 2010 - - -

    In misc.

    - -

    Or completely awesome. Depends the needs.

    -

    a root-relative link to markdown-article - a file-relative link to markdown-article

    -
    -

    Testing sourcecode directive

    -
    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    -
    -
    -
    -

    Testing another case

    -

    This will now have a line number in 'custom' since it's the default in - pelican.conf, it will have nothing in default.

    -
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    -
    -

    Lovely.

    -
    -
    -

    Testing more sourcecode directives

    -
     8def run(self):
    self.assert_has_content()
    10 try:
    lexer = get_lexer_by_name(self.arguments[0])
    12 except ValueError:
    # no lexer found - use the text one instead of an exception
    14 lexer = TextLexer()

    16 if ('linenos' in self.options and
    self.options['linenos'] not in ('table', 'inline')):
    18 self.options['linenos'] = 'table'

    20 for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
    if flag in self.options:
    22 self.options[flag] = True

    24 # noclasses should already default to False, but just in case...
    formatter = HtmlFormatter(noclasses=False, **self.options)
    26 parsed = highlight('\n'.join(self.content), lexer, formatter)
    return [nodes.raw('', parsed, format='html')]
    -

    Lovely.

    -
    -
    -

    Testing even more sourcecode directives

    - formatter = self.options and VARIANTS[self.options.keys()[0]] -

    Lovely.

    -
    -
    -

    Testing overriding config defaults

    -

    Even if the default is line numbers, we can override it here

    -
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    -
    -

    Lovely.

    -
    - -
    - -
    -
    -
    - -
    - - - - - diff --git a/pelican/tests/output/custom/a-markdown-powered-article.html b/pelican/tests/output/custom/a-markdown-powered-article.html deleted file mode 100644 index b8359a6d..00000000 --- a/pelican/tests/output/custom/a-markdown-powered-article.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - A markdown powered article - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - A markdown powered article

    -
    - -
    -

    You're mutually oblivious.

    -

    a root-relative link to unbelievable - a file-relative link to unbelievable

    -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/archives.html b/pelican/tests/output/custom/archives.html deleted file mode 100644 index 234fa63a..00000000 --- a/pelican/tests/output/custom/archives.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - Alexis' log - - - - - - - - Fork me on GitHub - - -
    -

    Archives for Alexis' log

    - -
    -
    Fri 30 November 2012
    -
    FILENAME_METADATA example
    -
    Wed 29 February 2012
    -
    Second article
    -
    Wed 20 April 2011
    -
    A markdown powered article
    -
    Thu 17 February 2011
    -
    Article 1
    -
    Thu 17 February 2011
    -
    Article 2
    -
    Thu 17 February 2011
    -
    Article 3
    -
    Thu 02 December 2010
    -
    This is a super article !
    -
    Wed 20 October 2010
    -
    Oh yeah !
    -
    Fri 15 October 2010
    -
    Unbelievable !
    -
    Sun 14 March 2010
    -
    The baz tag
    -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/article-1.html b/pelican/tests/output/custom/article-1.html deleted file mode 100644 index 4b670b16..00000000 --- a/pelican/tests/output/custom/article-1.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - Article 1 - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Article 1

    -
    - -
    -

    Article 1

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/article-2.html b/pelican/tests/output/custom/article-2.html deleted file mode 100644 index ad1e20fb..00000000 --- a/pelican/tests/output/custom/article-2.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - Article 2 - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Article 2

    -
    - -
    -

    Article 2

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/article-3.html b/pelican/tests/output/custom/article-3.html deleted file mode 100644 index 7157c014..00000000 --- a/pelican/tests/output/custom/article-3.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - Article 3 - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Article 3

    -
    - -
    -

    Article 3

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/author/alexis-metaireau.html b/pelican/tests/output/custom/author/alexis-metaireau.html deleted file mode 100644 index b4230aad..00000000 --- a/pelican/tests/output/custom/author/alexis-metaireau.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - Alexis' log - Alexis Métaireau - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. - -
    3. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/author/alexis-metaireau2.html b/pelican/tests/output/custom/author/alexis-metaireau2.html deleted file mode 100644 index 43823162..00000000 --- a/pelican/tests/output/custom/author/alexis-metaireau2.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - Alexis' log - Alexis Métaireau - - - - - - - - Fork me on GitHub - - - -
    -
      -
    1. - -
    2. - -
    3. - -
    4. -
      -

      Oh yeah !

      -
      - -
      -
      -

      Why not ?

      -

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

      - alternate text -
      - - read more -

      There are comments.

      -
    5. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/author/alexis-metaireau3.html b/pelican/tests/output/custom/author/alexis-metaireau3.html deleted file mode 100644 index cf7a6031..00000000 --- a/pelican/tests/output/custom/author/alexis-metaireau3.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - Alexis' log - Alexis Métaireau - - - - - - - - Fork me on GitHub - - - -
    -
      -
    1. -
      -

      Unbelievable !

      -
      - -
      -

      Or completely awesome. Depends the needs.

      -

      a root-relative link to markdown-article - a file-relative link to markdown-article

      -
      -

      Testing sourcecode directive

      -
      1
      formatter = self.options and VARIANTS[self.options.keys()[0]]
      -
      -
      -
      -

      Testing another case

      -

      This will now have a line number in 'custom' since it's the default in - pelican.conf, it will …

      - read more -

      There are comments.

      -
    2. - -
    3. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/authors.html b/pelican/tests/output/custom/authors.html deleted file mode 100644 index 5ba9af8c..00000000 --- a/pelican/tests/output/custom/authors.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - Alexis' log - Authors - - - - - - - - Fork me on GitHub - - - -
    -

    Authors on Alexis' log

    - -
    - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/categories.html b/pelican/tests/output/custom/categories.html deleted file mode 100644 index 2c055fac..00000000 --- a/pelican/tests/output/custom/categories.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - Alexis' log - Categories - - - - - - - - Fork me on GitHub - - - -
    -

    Categories for Alexis' log

    - -
    - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/category/bar.html b/pelican/tests/output/custom/category/bar.html deleted file mode 100644 index 7415f9f4..00000000 --- a/pelican/tests/output/custom/category/bar.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - Alexis' log - bar - - - - - - - - Fork me on GitHub - - - - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/category/cat1.html b/pelican/tests/output/custom/category/cat1.html deleted file mode 100644 index f72f8bc8..00000000 --- a/pelican/tests/output/custom/category/cat1.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - - Alexis' log - cat1 - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. - -
    3. -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/category/misc.html b/pelican/tests/output/custom/category/misc.html deleted file mode 100644 index 895f253e..00000000 --- a/pelican/tests/output/custom/category/misc.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - - Alexis' log - misc - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. -
      -

      Unbelievable !

      -
      - -
      -

      Or completely awesome. Depends the needs.

      -

      a root-relative link to markdown-article - a file-relative link to markdown-article

      -
      -

      Testing sourcecode directive

      -
      1
      formatter = self.options and VARIANTS[self.options.keys()[0]]
      -
      -
      -
      -

      Testing another case

      -

      This will now have a line number in 'custom' since it's the default in - pelican.conf, it will …

      - read more -

      There are comments.

      -
    3. - -
    4. -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/category/yeah.html b/pelican/tests/output/custom/category/yeah.html deleted file mode 100644 index a6d76ac2..00000000 --- a/pelican/tests/output/custom/category/yeah.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - Alexis' log - yeah - - - - - - - - Fork me on GitHub - - - - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/drafts/a-draft-article-without-date.html b/pelican/tests/output/custom/drafts/a-draft-article-without-date.html deleted file mode 100644 index 70879483..00000000 --- a/pelican/tests/output/custom/drafts/a-draft-article-without-date.html +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - A draft article without date - - - - - - - - - Fork me on GitHub - - -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/drafts/a-draft-article.html b/pelican/tests/output/custom/drafts/a-draft-article.html deleted file mode 100644 index 8e56ba96..00000000 --- a/pelican/tests/output/custom/drafts/a-draft-article.html +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - A draft article - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - A draft article

    -
    - -
    -

    This is a draft article, it should live under the /drafts/ folder and not be - listed anywhere else.

    - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/feeds/alexis-metaireau.atom.xml b/pelican/tests/output/custom/feeds/alexis-metaireau.atom.xml deleted file mode 100644 index 5bfb73d0..00000000 --- a/pelican/tests/output/custom/feeds/alexis-metaireau.atom.xml +++ /dev/null @@ -1,74 +0,0 @@ - -Alexis' log - Alexis Métaireauhttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00A personal blog.FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> -Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article.html<p>This is some article, in english</p> -A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-1.html<p>Article 1</p> -Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-2.html<p>Article 2</p> -Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-3.html<p>Article 3</p> -This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> -Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will have nothing in default.</p> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-more-sourcecode-directives"> -<h2>Testing more sourcecode directives</h2> -<div class="highlight"><pre><span></span><span id="foo-8"><a id="foo-8" name="foo-8"></a><a href="#foo-8"><span class="linenos special"> 8</span></a><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a id="foo-9" name="foo-9"></a><a href="#foo-9"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a id="foo-10" name="foo-10"></a><a href="#foo-10"><span class="linenos special">10</span></a> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a id="foo-11" name="foo-11"></a><a href="#foo-11"><span class="linenos"> </span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a id="foo-12" name="foo-12"></a><a href="#foo-12"><span class="linenos special">12</span></a> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a id="foo-13" name="foo-13"></a><a href="#foo-13"><span class="linenos"> </span></a> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a id="foo-14" name="foo-14"></a><a href="#foo-14"><span class="linenos special">14</span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a id="foo-15" name="foo-15"></a><a href="#foo-15"><span class="linenos"> </span></a><br></span><span id="foo-16"><a id="foo-16" name="foo-16"></a><a href="#foo-16"><span class="linenos special">16</span></a> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a id="foo-17" name="foo-17"></a><a href="#foo-17"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a id="foo-18" name="foo-18"></a><a href="#foo-18"><span class="linenos special">18</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a id="foo-19" name="foo-19"></a><a href="#foo-19"><span class="linenos"> </span></a><br></span><span id="foo-20"><a id="foo-20" name="foo-20"></a><a href="#foo-20"><span class="linenos special">20</span></a> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a id="foo-21" name="foo-21"></a><a href="#foo-21"><span class="linenos"> </span></a> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a id="foo-22" name="foo-22"></a><a href="#foo-22"><span class="linenos special">22</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingkc">True</span><br></span><span id="foo-23"><a id="foo-23" name="foo-23"></a><a href="#foo-23"><span class="linenos"> </span></a><br></span><span id="foo-24"><a id="foo-24" name="foo-24"></a><a href="#foo-24"><span class="linenos special">24</span></a> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a id="foo-25" name="foo-25"></a><a href="#foo-25"><span class="linenos"> </span></a> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingkc">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a id="foo-26" name="foo-26"></a><a href="#foo-26"><span class="linenos special">26</span></a> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a id="foo-27" name="foo-27"></a><a href="#foo-27"><span class="linenos"> </span></a> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingnb">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-even-more-sourcecode-directives"> -<h2>Testing even more sourcecode directives</h2> -<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -<p>Lovely.</p> -</div> -<div class="section" id="testing-overriding-config-defaults"> -<h2>Testing overriding config defaults</h2> -<p>Even if the default is line numbers, we can override it here</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> - diff --git a/pelican/tests/output/custom/feeds/alexis-metaireau.rss.xml b/pelican/tests/output/custom/feeds/alexis-metaireau.rss.xml deleted file mode 100644 index b5654682..00000000 --- a/pelican/tests/output/custom/feeds/alexis-metaireau.rss.xml +++ /dev/null @@ -1,29 +0,0 @@ - -Alexis' log - Alexis Métaireauhttp://blog.notmyidea.org/A personal blog.Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/filename_metadata-example.html<p>Some cool stuff!</p> -Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.htmlmiscSecond articlehttp://blog.notmyidea.org/second-article.html<p>This is some article, in english</p> -Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/second-article.htmlmiscfoobarbazA markdown powered articlehttp://blog.notmyidea.org/a-markdown-powered-article.html<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.htmlcat1Article 1http://blog.notmyidea.org/article-1.html<p>Article 1</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-1.htmlcat1Article 2http://blog.notmyidea.org/article-2.html<p>Article 2</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-2.htmlcat1Article 3http://blog.notmyidea.org/article-3.html<p>Article 3</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-3.htmlcat1This is a super article !http://blog.notmyidea.org/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.htmlyeahfoobarfoobarOh yeah !http://blog.notmyidea.org/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/oh-yeah.htmlbarohbaryeahUnbelievable !http://blog.notmyidea.org/unbelievable.html<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/unbelievable.htmlmiscThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> -Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlmisc diff --git a/pelican/tests/output/custom/feeds/all-en.atom.xml b/pelican/tests/output/custom/feeds/all-en.atom.xml deleted file mode 100644 index 1aac415a..00000000 --- a/pelican/tests/output/custom/feeds/all-en.atom.xml +++ /dev/null @@ -1,74 +0,0 @@ - -Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00A personal blog.FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> -Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article.html<p>This is some article, in english</p> -A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-1.html<p>Article 1</p> -Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-2.html<p>Article 2</p> -Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-3.html<p>Article 3</p> -This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> -Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will have nothing in default.</p> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-more-sourcecode-directives"> -<h2>Testing more sourcecode directives</h2> -<div class="highlight"><pre><span></span><span id="foo-8"><a id="foo-8" name="foo-8"></a><a href="#foo-8"><span class="linenos special"> 8</span></a><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a id="foo-9" name="foo-9"></a><a href="#foo-9"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a id="foo-10" name="foo-10"></a><a href="#foo-10"><span class="linenos special">10</span></a> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a id="foo-11" name="foo-11"></a><a href="#foo-11"><span class="linenos"> </span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a id="foo-12" name="foo-12"></a><a href="#foo-12"><span class="linenos special">12</span></a> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a id="foo-13" name="foo-13"></a><a href="#foo-13"><span class="linenos"> </span></a> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a id="foo-14" name="foo-14"></a><a href="#foo-14"><span class="linenos special">14</span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a id="foo-15" name="foo-15"></a><a href="#foo-15"><span class="linenos"> </span></a><br></span><span id="foo-16"><a id="foo-16" name="foo-16"></a><a href="#foo-16"><span class="linenos special">16</span></a> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a id="foo-17" name="foo-17"></a><a href="#foo-17"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a id="foo-18" name="foo-18"></a><a href="#foo-18"><span class="linenos special">18</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a id="foo-19" name="foo-19"></a><a href="#foo-19"><span class="linenos"> </span></a><br></span><span id="foo-20"><a id="foo-20" name="foo-20"></a><a href="#foo-20"><span class="linenos special">20</span></a> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a id="foo-21" name="foo-21"></a><a href="#foo-21"><span class="linenos"> </span></a> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a id="foo-22" name="foo-22"></a><a href="#foo-22"><span class="linenos special">22</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingkc">True</span><br></span><span id="foo-23"><a id="foo-23" name="foo-23"></a><a href="#foo-23"><span class="linenos"> </span></a><br></span><span id="foo-24"><a id="foo-24" name="foo-24"></a><a href="#foo-24"><span class="linenos special">24</span></a> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a id="foo-25" name="foo-25"></a><a href="#foo-25"><span class="linenos"> </span></a> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingkc">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a id="foo-26" name="foo-26"></a><a href="#foo-26"><span class="linenos special">26</span></a> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a id="foo-27" name="foo-27"></a><a href="#foo-27"><span class="linenos"> </span></a> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingnb">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-even-more-sourcecode-directives"> -<h2>Testing even more sourcecode directives</h2> -<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -<p>Lovely.</p> -</div> -<div class="section" id="testing-overriding-config-defaults"> -<h2>Testing overriding config defaults</h2> -<p>Even if the default is line numbers, we can override it here</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> - diff --git a/pelican/tests/output/custom/feeds/all-fr.atom.xml b/pelican/tests/output/custom/feeds/all-fr.atom.xml deleted file mode 100644 index 68ebd738..00000000 --- a/pelican/tests/output/custom/feeds/all-fr.atom.xml +++ /dev/null @@ -1,4 +0,0 @@ - -Alexis' loghttp://blog.notmyidea.org/2012-02-29T00:00:00+01:00A personal blog.Deuxième article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> -Trop bien !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah-fr.html<p>Et voila du contenu en français</p> - diff --git a/pelican/tests/output/custom/feeds/all.atom.xml b/pelican/tests/output/custom/feeds/all.atom.xml deleted file mode 100644 index dbe37a32..00000000 --- a/pelican/tests/output/custom/feeds/all.atom.xml +++ /dev/null @@ -1,76 +0,0 @@ - -Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00A personal blog.FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> -Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article.html<p>This is some article, in english</p> -Deuxième article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> -A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-1.html<p>Article 1</p> -Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-2.html<p>Article 2</p> -Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-3.html<p>Article 3</p> -This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> -Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Trop bien !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah-fr.html<p>Et voila du contenu en français</p> -Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will have nothing in default.</p> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-more-sourcecode-directives"> -<h2>Testing more sourcecode directives</h2> -<div class="highlight"><pre><span></span><span id="foo-8"><a id="foo-8" name="foo-8"></a><a href="#foo-8"><span class="linenos special"> 8</span></a><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a id="foo-9" name="foo-9"></a><a href="#foo-9"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a id="foo-10" name="foo-10"></a><a href="#foo-10"><span class="linenos special">10</span></a> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a id="foo-11" name="foo-11"></a><a href="#foo-11"><span class="linenos"> </span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a id="foo-12" name="foo-12"></a><a href="#foo-12"><span class="linenos special">12</span></a> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a id="foo-13" name="foo-13"></a><a href="#foo-13"><span class="linenos"> </span></a> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a id="foo-14" name="foo-14"></a><a href="#foo-14"><span class="linenos special">14</span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a id="foo-15" name="foo-15"></a><a href="#foo-15"><span class="linenos"> </span></a><br></span><span id="foo-16"><a id="foo-16" name="foo-16"></a><a href="#foo-16"><span class="linenos special">16</span></a> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a id="foo-17" name="foo-17"></a><a href="#foo-17"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a id="foo-18" name="foo-18"></a><a href="#foo-18"><span class="linenos special">18</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a id="foo-19" name="foo-19"></a><a href="#foo-19"><span class="linenos"> </span></a><br></span><span id="foo-20"><a id="foo-20" name="foo-20"></a><a href="#foo-20"><span class="linenos special">20</span></a> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a id="foo-21" name="foo-21"></a><a href="#foo-21"><span class="linenos"> </span></a> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a id="foo-22" name="foo-22"></a><a href="#foo-22"><span class="linenos special">22</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingkc">True</span><br></span><span id="foo-23"><a id="foo-23" name="foo-23"></a><a href="#foo-23"><span class="linenos"> </span></a><br></span><span id="foo-24"><a id="foo-24" name="foo-24"></a><a href="#foo-24"><span class="linenos special">24</span></a> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a id="foo-25" name="foo-25"></a><a href="#foo-25"><span class="linenos"> </span></a> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingkc">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a id="foo-26" name="foo-26"></a><a href="#foo-26"><span class="linenos special">26</span></a> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a id="foo-27" name="foo-27"></a><a href="#foo-27"><span class="linenos"> </span></a> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingnb">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-even-more-sourcecode-directives"> -<h2>Testing even more sourcecode directives</h2> -<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -<p>Lovely.</p> -</div> -<div class="section" id="testing-overriding-config-defaults"> -<h2>Testing overriding config defaults</h2> -<p>Even if the default is line numbers, we can override it here</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> - diff --git a/pelican/tests/output/custom/feeds/all.rss.xml b/pelican/tests/output/custom/feeds/all.rss.xml deleted file mode 100644 index 45a8dc58..00000000 --- a/pelican/tests/output/custom/feeds/all.rss.xml +++ /dev/null @@ -1,31 +0,0 @@ - -Alexis' loghttp://blog.notmyidea.org/A personal blog.Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/filename_metadata-example.html<p>Some cool stuff!</p> -Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.htmlmiscSecond articlehttp://blog.notmyidea.org/second-article.html<p>This is some article, in english</p> -Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/second-article.htmlmiscfoobarbazDeuxième articlehttp://blog.notmyidea.org/second-article-fr.html<p>Ceci est un article, en français.</p> -Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/second-article-fr.htmlmiscfoobarbazA markdown powered articlehttp://blog.notmyidea.org/a-markdown-powered-article.html<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.htmlcat1Article 1http://blog.notmyidea.org/article-1.html<p>Article 1</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-1.htmlcat1Article 2http://blog.notmyidea.org/article-2.html<p>Article 2</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-2.htmlcat1Article 3http://blog.notmyidea.org/article-3.html<p>Article 3</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-3.htmlcat1This is a super article !http://blog.notmyidea.org/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.htmlyeahfoobarfoobarOh yeah !http://blog.notmyidea.org/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/oh-yeah.htmlbarohbaryeahTrop bien !http://blog.notmyidea.org/oh-yeah-fr.html<p>Et voila du contenu en français</p> -Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/oh-yeah-fr.htmlmiscUnbelievable !http://blog.notmyidea.org/unbelievable.html<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/unbelievable.htmlmiscThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> -Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlmisc diff --git a/pelican/tests/output/custom/feeds/bar.atom.xml b/pelican/tests/output/custom/feeds/bar.atom.xml deleted file mode 100644 index d79aad2d..00000000 --- a/pelican/tests/output/custom/feeds/bar.atom.xml +++ /dev/null @@ -1,8 +0,0 @@ - -Alexis' log - barhttp://blog.notmyidea.org/2010-10-20T10:14:00+02:00A personal blog.Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> - diff --git a/pelican/tests/output/custom/feeds/bar.rss.xml b/pelican/tests/output/custom/feeds/bar.rss.xml deleted file mode 100644 index c993753a..00000000 --- a/pelican/tests/output/custom/feeds/bar.rss.xml +++ /dev/null @@ -1,8 +0,0 @@ - -Alexis' log - barhttp://blog.notmyidea.org/A personal blog.Wed, 20 Oct 2010 10:14:00 +0200Oh yeah !http://blog.notmyidea.org/oh-yeah.html<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/oh-yeah.htmlbarohbaryeah diff --git a/pelican/tests/output/custom/feeds/cat1.atom.xml b/pelican/tests/output/custom/feeds/cat1.atom.xml deleted file mode 100644 index c44ac595..00000000 --- a/pelican/tests/output/custom/feeds/cat1.atom.xml +++ /dev/null @@ -1,7 +0,0 @@ - -Alexis' log - cat1http://blog.notmyidea.org/2011-04-20T00:00:00+02:00A personal blog.A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.html<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-1.html<p>Article 1</p> -Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-2.html<p>Article 2</p> -Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/article-3.html<p>Article 3</p> - diff --git a/pelican/tests/output/custom/feeds/cat1.rss.xml b/pelican/tests/output/custom/feeds/cat1.rss.xml deleted file mode 100644 index a6ca0b53..00000000 --- a/pelican/tests/output/custom/feeds/cat1.rss.xml +++ /dev/null @@ -1,7 +0,0 @@ - -Alexis' log - cat1http://blog.notmyidea.org/A personal blog.Wed, 20 Apr 2011 00:00:00 +0200A markdown powered articlehttp://blog.notmyidea.org/a-markdown-powered-article.html<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.htmlcat1Article 1http://blog.notmyidea.org/article-1.html<p>Article 1</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-1.htmlcat1Article 2http://blog.notmyidea.org/article-2.html<p>Article 2</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-2.htmlcat1Article 3http://blog.notmyidea.org/article-3.html<p>Article 3</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/article-3.htmlcat1 diff --git a/pelican/tests/output/custom/feeds/misc.atom.xml b/pelican/tests/output/custom/feeds/misc.atom.xml deleted file mode 100644 index 117c2bc2..00000000 --- a/pelican/tests/output/custom/feeds/misc.atom.xml +++ /dev/null @@ -1,49 +0,0 @@ - -Alexis' log - mischttp://blog.notmyidea.org/2012-11-30T00:00:00+01:00A personal blog.FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html<p>Some cool stuff!</p> -Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article.html<p>This is some article, in english</p> -Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/unbelievable.html<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will have nothing in default.</p> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-more-sourcecode-directives"> -<h2>Testing more sourcecode directives</h2> -<div class="highlight"><pre><span></span><span id="foo-8"><a id="foo-8" name="foo-8"></a><a href="#foo-8"><span class="linenos special"> 8</span></a><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a id="foo-9" name="foo-9"></a><a href="#foo-9"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a id="foo-10" name="foo-10"></a><a href="#foo-10"><span class="linenos special">10</span></a> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a id="foo-11" name="foo-11"></a><a href="#foo-11"><span class="linenos"> </span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a id="foo-12" name="foo-12"></a><a href="#foo-12"><span class="linenos special">12</span></a> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a id="foo-13" name="foo-13"></a><a href="#foo-13"><span class="linenos"> </span></a> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a id="foo-14" name="foo-14"></a><a href="#foo-14"><span class="linenos special">14</span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a id="foo-15" name="foo-15"></a><a href="#foo-15"><span class="linenos"> </span></a><br></span><span id="foo-16"><a id="foo-16" name="foo-16"></a><a href="#foo-16"><span class="linenos special">16</span></a> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a id="foo-17" name="foo-17"></a><a href="#foo-17"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a id="foo-18" name="foo-18"></a><a href="#foo-18"><span class="linenos special">18</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a id="foo-19" name="foo-19"></a><a href="#foo-19"><span class="linenos"> </span></a><br></span><span id="foo-20"><a id="foo-20" name="foo-20"></a><a href="#foo-20"><span class="linenos special">20</span></a> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a id="foo-21" name="foo-21"></a><a href="#foo-21"><span class="linenos"> </span></a> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a id="foo-22" name="foo-22"></a><a href="#foo-22"><span class="linenos special">22</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingkc">True</span><br></span><span id="foo-23"><a id="foo-23" name="foo-23"></a><a href="#foo-23"><span class="linenos"> </span></a><br></span><span id="foo-24"><a id="foo-24" name="foo-24"></a><a href="#foo-24"><span class="linenos special">24</span></a> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a id="foo-25" name="foo-25"></a><a href="#foo-25"><span class="linenos"> </span></a> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingkc">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a id="foo-26" name="foo-26"></a><a href="#foo-26"><span class="linenos special">26</span></a> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a id="foo-27" name="foo-27"></a><a href="#foo-27"><span class="linenos"> </span></a> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingnb">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-even-more-sourcecode-directives"> -<h2>Testing even more sourcecode directives</h2> -<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -<p>Lovely.</p> -</div> -<div class="section" id="testing-overriding-config-defaults"> -<h2>Testing overriding config defaults</h2> -<p>Even if the default is line numbers, we can override it here</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> - diff --git a/pelican/tests/output/custom/feeds/misc.rss.xml b/pelican/tests/output/custom/feeds/misc.rss.xml deleted file mode 100644 index 03b3b2fe..00000000 --- a/pelican/tests/output/custom/feeds/misc.rss.xml +++ /dev/null @@ -1,16 +0,0 @@ - -Alexis' log - mischttp://blog.notmyidea.org/A personal blog.Fri, 30 Nov 2012 00:00:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/filename_metadata-example.html<p>Some cool stuff!</p> -Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.htmlmiscSecond articlehttp://blog.notmyidea.org/second-article.html<p>This is some article, in english</p> -Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/second-article.htmlmiscfoobarbazUnbelievable !http://blog.notmyidea.org/unbelievable.html<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/unbelievable.htmlmiscThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> -Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlmisc diff --git a/pelican/tests/output/custom/feeds/yeah.atom.xml b/pelican/tests/output/custom/feeds/yeah.atom.xml deleted file mode 100644 index 0e5e8858..00000000 --- a/pelican/tests/output/custom/feeds/yeah.atom.xml +++ /dev/null @@ -1,16 +0,0 @@ - -Alexis' log - yeahhttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00A personal blog.This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> - diff --git a/pelican/tests/output/custom/feeds/yeah.rss.xml b/pelican/tests/output/custom/feeds/yeah.rss.xml deleted file mode 100644 index be592f11..00000000 --- a/pelican/tests/output/custom/feeds/yeah.rss.xml +++ /dev/null @@ -1,4 +0,0 @@ - -Alexis' log - yeahhttp://blog.notmyidea.org/A personal blog.Sun, 17 Nov 2013 23:29:00 +0100This is a super article !http://blog.notmyidea.org/this-is-a-super-article.html<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.htmlyeahfoobarfoobar diff --git a/pelican/tests/output/custom/filename_metadata-example.html b/pelican/tests/output/custom/filename_metadata-example.html deleted file mode 100644 index 00b1f158..00000000 --- a/pelican/tests/output/custom/filename_metadata-example.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - FILENAME_METADATA example - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - FILENAME_METADATA example

    -
    - -
    -

    Some cool stuff!

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/index.html b/pelican/tests/output/custom/index.html deleted file mode 100644 index b29d8d86..00000000 --- a/pelican/tests/output/custom/index.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - Alexis' log - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. - -
    3. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/index2.html b/pelican/tests/output/custom/index2.html deleted file mode 100644 index a1c3f5b5..00000000 --- a/pelican/tests/output/custom/index2.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - Alexis' log - - - - - - - - Fork me on GitHub - - - -
    -
      -
    1. - -
    2. - -
    3. - -
    4. -
      -

      Oh yeah !

      -
      - -
      -
      -

      Why not ?

      -

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

      - alternate text -
      - - read more -

      There are comments.

      -
    5. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/index3.html b/pelican/tests/output/custom/index3.html deleted file mode 100644 index 93e0d029..00000000 --- a/pelican/tests/output/custom/index3.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - Alexis' log - - - - - - - - Fork me on GitHub - - - -
    -
      -
    1. -
      -

      Unbelievable !

      -
      - -
      -

      Or completely awesome. Depends the needs.

      -

      a root-relative link to markdown-article - a file-relative link to markdown-article

      -
      -

      Testing sourcecode directive

      -
      1
      formatter = self.options and VARIANTS[self.options.keys()[0]]
      -
      -
      -
      -

      Testing another case

      -

      This will now have a line number in 'custom' since it's the default in - pelican.conf, it will …

      - read more -

      There are comments.

      -
    2. - -
    3. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/jinja2_template.html b/pelican/tests/output/custom/jinja2_template.html deleted file mode 100644 index e745d4cf..00000000 --- a/pelican/tests/output/custom/jinja2_template.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - Alexis' log - - - - - - - - Fork me on GitHub - - - - Some text - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/oh-yeah-fr.html b/pelican/tests/output/custom/oh-yeah-fr.html deleted file mode 100644 index 8659bd0e..00000000 --- a/pelican/tests/output/custom/oh-yeah-fr.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - Trop bien ! - - - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Trop bien !

    -
    - -
    -

    Et voila du contenu en français

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/oh-yeah.html b/pelican/tests/output/custom/oh-yeah.html deleted file mode 100644 index 0825e211..00000000 --- a/pelican/tests/output/custom/oh-yeah.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - Oh yeah ! - - - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Oh yeah !

    -
    - -
    -
    -

    Why not ?

    -

    After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

    - alternate text -
    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/override/index.html b/pelican/tests/output/custom/override/index.html deleted file mode 100644 index 8a5df3b4..00000000 --- a/pelican/tests/output/custom/override/index.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - Override url/save_as - - - - - - - - Fork me on GitHub - - -
    -

    Override url/save_as

    - -

    Test page which overrides save_as and url so that this page will be generated - at a custom location.

    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/pages/this-is-a-test-hidden-page.html b/pelican/tests/output/custom/pages/this-is-a-test-hidden-page.html deleted file mode 100644 index df4e9090..00000000 --- a/pelican/tests/output/custom/pages/this-is-a-test-hidden-page.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - This is a test hidden page - - - - - - - - Fork me on GitHub - - -
    -

    This is a test hidden page

    - -

    This is great for things like error(404) pages - Anyone can see this page but it's not linked to anywhere!

    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/pages/this-is-a-test-page.html b/pelican/tests/output/custom/pages/this-is-a-test-page.html deleted file mode 100644 index f9d959a5..00000000 --- a/pelican/tests/output/custom/pages/this-is-a-test-page.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - This is a test page - - - - - - - - Fork me on GitHub - - -
    -

    This is a test page

    - -

    Just an image.

    - alternate text - wrong path since 'images' folder does not exist - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/pictures/Fat_Cat.jpg b/pelican/tests/output/custom/pictures/Fat_Cat.jpg deleted file mode 100644 index d8a96d35..00000000 Binary files a/pelican/tests/output/custom/pictures/Fat_Cat.jpg and /dev/null differ diff --git a/pelican/tests/output/custom/pictures/Sushi.jpg b/pelican/tests/output/custom/pictures/Sushi.jpg deleted file mode 100644 index e49e5f0a..00000000 Binary files a/pelican/tests/output/custom/pictures/Sushi.jpg and /dev/null differ diff --git a/pelican/tests/output/custom/pictures/Sushi_Macro.jpg b/pelican/tests/output/custom/pictures/Sushi_Macro.jpg deleted file mode 100644 index 21f935a1..00000000 Binary files a/pelican/tests/output/custom/pictures/Sushi_Macro.jpg and /dev/null differ diff --git a/pelican/tests/output/custom/robots.txt b/pelican/tests/output/custom/robots.txt deleted file mode 100644 index 19a6e299..00000000 --- a/pelican/tests/output/custom/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: /pictures diff --git a/pelican/tests/output/custom/second-article-fr.html b/pelican/tests/output/custom/second-article-fr.html deleted file mode 100644 index c53cc23e..00000000 --- a/pelican/tests/output/custom/second-article-fr.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - Deuxième article - - - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Deuxième article

    -
    - -
    -

    Ceci est un article, en français.

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/second-article.html b/pelican/tests/output/custom/second-article.html deleted file mode 100644 index f42dd642..00000000 --- a/pelican/tests/output/custom/second-article.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - Second article - - - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Second article

    -
    - -
    -

    This is some article, in english

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/tag/bar.html b/pelican/tests/output/custom/tag/bar.html deleted file mode 100644 index 3abbc833..00000000 --- a/pelican/tests/output/custom/tag/bar.html +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - - Alexis' log - bar - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. -
      -

      Oh yeah !

      -
      - -
      -
      -

      Why not ?

      -

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

      - alternate text -
      - - read more -

      There are comments.

      -
    3. -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/tag/baz.html b/pelican/tests/output/custom/tag/baz.html deleted file mode 100644 index e2dfada4..00000000 --- a/pelican/tests/output/custom/tag/baz.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - The baz tag - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - The baz tag

    -
    - -
    -

    This article overrides the listening of the articles under the baz tag.

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/tag/foo.html b/pelican/tests/output/custom/tag/foo.html deleted file mode 100644 index c03bca5c..00000000 --- a/pelican/tests/output/custom/tag/foo.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - Alexis' log - foo - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/tag/foobar.html b/pelican/tests/output/custom/tag/foobar.html deleted file mode 100644 index d3609714..00000000 --- a/pelican/tests/output/custom/tag/foobar.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - Alexis' log - foobar - - - - - - - - Fork me on GitHub - - - - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/tag/oh.html b/pelican/tests/output/custom/tag/oh.html deleted file mode 100644 index 5530d037..00000000 --- a/pelican/tests/output/custom/tag/oh.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - Oh Oh Oh - - - - - - - - Fork me on GitHub - - -
    -

    Oh Oh Oh

    - -

    This page overrides the listening of the articles under the oh tag.

    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/tag/yeah.html b/pelican/tests/output/custom/tag/yeah.html deleted file mode 100644 index d0457390..00000000 --- a/pelican/tests/output/custom/tag/yeah.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - Alexis' log - yeah - - - - - - - - Fork me on GitHub - - - - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/tags.html b/pelican/tests/output/custom/tags.html deleted file mode 100644 index e5b3b08f..00000000 --- a/pelican/tests/output/custom/tags.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - Alexis' log - Tags - - - - - - - - Fork me on GitHub - - - -
    -

    Tags for Alexis' log

    - -
    - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/theme/css/fonts.css b/pelican/tests/output/custom/theme/css/fonts.css deleted file mode 100644 index 7c69215e..00000000 --- a/pelican/tests/output/custom/theme/css/fonts.css +++ /dev/null @@ -1,12 +0,0 @@ -@font-face { - font-family: 'Yanone Kaffeesatz'; - font-style: normal; - font-weight: 400; - src: - local('Yanone Kaffeesatz Regular'), - local('YanoneKaffeesatz-Regular'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff */ - url('../fonts/Yanone_Kaffeesatz_400.woff') format('woff'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLfGwxTS8d1Q9KiDNCMKLFUM.woff2 */ - url('../fonts/Yanone_Kaffeesatz_400.woff2') format('woff2'); -} diff --git a/pelican/tests/output/custom/theme/css/main.css b/pelican/tests/output/custom/theme/css/main.css deleted file mode 100644 index c1d86950..00000000 --- a/pelican/tests/output/custom/theme/css/main.css +++ /dev/null @@ -1,439 +0,0 @@ -/* - Name: Smashing HTML5 - Date: July 2009 - Description: Sample layout for HTML5 and CSS3 goodness. - Version: 1.0 - License: MIT - Licensed by: Smashing Media GmbH - Original author: Enrique Ramírez -*/ - -/* Imports */ -@import url("reset.css"); -@import url("pygment.css"); -@import url("typogrify.css"); -@import url("fonts.css"); - -/***** Global *****/ -/* Body */ -body { - background: #F5F4EF; - color: #000305; - font-size: 87.5%; /* Base font size: 14px */ - font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; - line-height: 1.429; - margin: 0; - padding: 0; - text-align: left; -} - -/* Headings */ -h1 {font-size: 2em } -h2 {font-size: 1.571em} /* 22px */ -h3 {font-size: 1.429em} /* 20px */ -h4 {font-size: 1.286em} /* 18px */ -h5 {font-size: 1.143em} /* 16px */ -h6 {font-size: 1em} /* 14px */ - -h1, h2, h3, h4, h5, h6 { - font-weight: 400; - line-height: 1.1; - margin-bottom: .8em; - font-family: 'Yanone Kaffeesatz', arial, serif; -} - -h3, h4, h5, h6 { margin-top: .8em; } - -hr { border: 2px solid #EEEEEE; } - -/* Anchors */ -a {outline: 0;} -a img {border: 0px; text-decoration: none;} -a:link, a:visited { - color: #C74350; - padding: 0 1px; - text-decoration: underline; -} -a:hover, a:active { - background-color: #C74350; - color: #fff; - text-decoration: none; - text-shadow: 1px 1px 1px #333; -} - -h1 a:hover { - background-color: inherit -} - -/* Paragraphs */ -div.line-block, -p { margin-top: 1em; - margin-bottom: 1em;} - -strong, b {font-weight: bold;} -em, i {font-style: italic;} - -/* Lists */ -ul { - list-style: outside disc; - margin: 0em 0 0 1.5em; -} - -ol { - list-style: outside decimal; - margin: 0em 0 0 1.5em; -} - -li { margin-top: 0.5em; - margin-bottom: 1em; } - -.post-info { - float:right; - margin:10px; - padding:5px; -} - -.post-info p{ - margin-top: 1px; - margin-bottom: 1px; -} - -.readmore { float: right } - -dl {margin: 0 0 1.5em 0;} -dt {font-weight: bold;} -dd {margin-left: 1.5em;} - -pre{background-color: rgb(238, 238, 238); padding: 10px; margin: 10px; overflow: auto;} - -/* Quotes */ -blockquote { - margin: 20px; - font-style: italic; -} -cite {} - -q {} - -div.note { - float: right; - margin: 5px; - font-size: 85%; - max-width: 300px; -} - -/* Tables */ -table {margin: .5em auto 1.5em auto; width: 98%;} - - /* Thead */ -thead th {padding: .5em .4em; text-align: left;} -thead td {} - - /* Tbody */ -tbody td {padding: .5em .4em;} -tbody th {} - -tbody .alt td {} -tbody .alt th {} - - /* Tfoot */ -tfoot th {} -tfoot td {} - -/* HTML5 tags */ -header, section, footer, -aside, nav, article, figure { - display: block; -} - -/***** Layout *****/ -.body {clear: both; margin: 0 auto; max-width: 800px;} -img { max-width: 100%; } -img.right, figure.right, div.figure.align-right { - float: right; - margin: 0 0 2em 2em; -} -img.left, figure.left, div.figure.align-left { - float: left; - margin: 0 2em 2em 0; -} - -/* .rst support */ -div.figure img, figure img { /* to fill figure exactly */ - max-width: 100%; -} -div.figure p.caption, figure p.caption { /* margin provided by figure */ - margin-top: 0; - margin-bottom: 0; -} - -/* - Header -*****************/ -#banner { - margin: 0 auto; - padding: 0.8em 0 0 0; -} - - /* Banner */ -#banner h1 { - font-size: 3.571em; - line-height: 1.0; - margin-bottom: .3em; -} - -#banner h1 a:link, #banner h1 a:visited { - color: #000305; - display: block; - font-weight: bold; - margin: 0 0 0 .2em; - text-decoration: none; -} -#banner h1 a:hover, #banner h1 a:active { - background: none; - color: #C74350; - text-shadow: none; -} - -#banner h1 strong {font-size: 0.36em; font-weight: normal;} - - /* Main Nav */ -#banner nav { - background: #000305; - font-size: 1.143em; - overflow: auto; - line-height: 30px; - margin: 0 auto 2em auto; - padding: 0; - text-align: center; - max-width: 800px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} - -#banner nav ul {list-style: none; margin: 0 auto; max-width: 800px;} -#banner nav li {float: left; display: inline; margin: 0;} - -#banner nav a:link, #banner nav a:visited { - color: #fff; - display: inline-block; - height: 30px; - padding: 5px 1.5em; - text-decoration: none; -} -#banner nav a:hover, #banner nav a:active, -#banner nav .active a:link, #banner nav .active a:visited { - background: #C74451; - color: #fff; - text-shadow: none !important; -} - -#banner nav li:first-child a { - border-top-left-radius: 5px; - -moz-border-radius-topleft: 5px; - -webkit-border-top-left-radius: 5px; - - border-bottom-left-radius: 5px; - -moz-border-radius-bottomleft: 5px; - -webkit-border-bottom-left-radius: 5px; -} - -/* - Featured -*****************/ -#featured { - background: #fff; - margin-bottom: 2em; - overflow: hidden; - padding: 20px; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -#featured figure { - border: 2px solid #eee; - float: right; - margin: 0.786em 2em 0 5em; - max-width: 248px; -} -#featured figure img {display: block; float: right;} - -#featured h2 {color: #C74451; font-size: 1.714em; margin-bottom: 0.333em;} -#featured h3 {font-size: 1.429em; margin-bottom: .5em;} - -#featured h3 a:link, #featured h3 a:visited {color: #000305; text-decoration: none;} -#featured h3 a:hover, #featured h3 a:active {color: #fff;} - -/* - Body -*****************/ -#content { - background: #fff; - margin-bottom: 2em; - overflow: hidden; - padding: 20px 20px; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -/* - Extras -*****************/ -#extras {margin: 0 auto 3em auto; overflow: hidden;} - -#extras ul {list-style: none; margin: 0;} -#extras li {border-bottom: 1px solid #fff;} -#extras h2 { - color: #C74350; - font-size: 1.429em; - margin-bottom: .25em; - padding: 0 3px; -} - -#extras a:link, #extras a:visited { - color: #444; - display: block; - border-bottom: 1px solid #F4E3E3; - text-decoration: none; - padding: .3em .25em; -} - -#extras a:hover, #extras a:active {color: #fff;} - - /* Blogroll */ -#extras .blogroll { - float: left; - max-width: 615px; -} - -#extras .blogroll li {float: left; margin: 0 20px 0 0; max-width: 185px;} - - /* Social */ -#extras .social { - float: right; - max-width: 175px; -} - -/* - About -*****************/ -#about { - background: #fff; - font-style: normal; - margin-bottom: 2em; - overflow: hidden; - padding: 20px; - text-align: left; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -#about .primary {float: left; max-width: 165px;} -#about .primary strong {color: #C64350; display: block; font-size: 1.286em;} -#about .photo {float: left; margin: 5px 20px;} - -#about .url:link, #about .url:visited {text-decoration: none;} - -#about .bio {float: right; max-width: 500px;} - -/* - Footer -*****************/ -#contentinfo {padding-bottom: 2em; text-align: right;} - -/***** Sections *****/ -/* Blog */ -.hentry { - display: block; - clear: both; - border-top: 1px solid #eee; - padding: 1.5em 0; -} -li:first-child .hentry, #content > .hentry {border: 0; margin: 0;} -#content > .hentry {padding: 1em 0;} -.hentry img{display : none ;} -.entry-title {font-size: 3em; margin-bottom: 10px; margin-top: 0;} -.entry-title a:link, .entry-title a:visited {text-decoration: none; color: #333;} -.entry-title a:visited {background-color: #fff;} - -.hentry .post-info * {font-style: normal;} - - /* Content */ -.hentry footer {margin-bottom: 2em;} -.hentry footer address {display: inline;} -#posts-list footer address {display: block;} - - /* Blog Index */ -#posts-list {list-style: none; margin: 0;} -#posts-list .hentry {padding-left: 10px; position: relative;} - -#posts-list footer { - left: 10px; - position: relative; - float: left; - top: 0.5em; - max-width: 190px; -} - - /* About the Author */ -#about-author { - background: #f9f9f9; - clear: both; - font-style: normal; - margin: 2em 0; - padding: 10px 20px 15px 20px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} - -#about-author strong { - color: #C64350; - clear: both; - display: block; - font-size: 1.429em; -} - -#about-author .photo {border: 1px solid #ddd; float: left; margin: 5px 1em 0 0;} - - /* Comments */ -#comments-list {list-style: none; margin: 0 1em;} -#comments-list blockquote { - background: #f8f8f8; - clear: both; - font-style: normal; - margin: 0; - padding: 15px 20px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} -#comments-list footer {color: #888; padding: .5em 1em 0 0; text-align: right;} - -#comments-list li:nth-child(2n) blockquote {background: #F5f5f5;} - - /* Add a Comment */ -#add-comment label {clear: left; float: left; text-align: left; max-width: 150px;} -#add-comment input[type='text'], -#add-comment input[type='email'], -#add-comment input[type='url'] {float: left; max-width: 200px;} - -#add-comment textarea {float: left; height: 150px; max-width: 495px;} - -#add-comment p.req {clear: both; margin: 0 .5em 1em 0; text-align: right;} - -#add-comment input[type='submit'] {float: right; margin: 0 .5em;} -#add-comment * {margin-bottom: .5em;} diff --git a/pelican/tests/output/custom/theme/css/pygment.css b/pelican/tests/output/custom/theme/css/pygment.css deleted file mode 100644 index a3877a83..00000000 --- a/pelican/tests/output/custom/theme/css/pygment.css +++ /dev/null @@ -1,205 +0,0 @@ -.hll { - background-color:#eee; -} -.c { - color:#408090; - font-style:italic; -} -.err { - border:1px solid #FF0000; -} -.k { - color:#007020; - font-weight:bold; -} -.o { - color:#666666; -} -.cm { - color:#408090; - font-style:italic; -} -.cp { - color:#007020; -} -.c1 { - color:#408090; - font-style:italic; -} -.cs { - background-color:#FFF0F0; - color:#408090; -} -.gd { - color:#A00000; -} -.ge { - font-style:italic; -} -.gr { - color:#FF0000; -} -.gh { - color:#000080; - font-weight:bold; -} -.gi { - color:#00A000; -} -.go { - color:#303030; -} -.gp { - color:#C65D09; - font-weight:bold; -} -.gs { - font-weight:bold; -} -.gu { - color:#800080; - font-weight:bold; -} -.gt { - color:#0040D0; -} -.kc { - color:#007020; - font-weight:bold; -} -.kd { - color:#007020; - font-weight:bold; -} -.kn { - color:#007020; - font-weight:bold; -} -.kp { - color:#007020; -} -.kr { - color:#007020; - font-weight:bold; -} -.kt { - color:#902000; -} -.m { - color:#208050; -} -.s { - color:#4070A0; -} -.na { - color:#4070A0; -} -.nb { - color:#007020; -} -.nc { - color:#0E84B5; - font-weight:bold; -} -.no { - color:#60ADD5; -} -.nd { - color:#555555; - font-weight:bold; -} -.ni { - color:#D55537; - font-weight:bold; -} -.ne { - color:#007020; -} -.nf { - color:#06287E; -} -.nl { - color:#002070; - font-weight:bold; -} -.nn { - color:#0E84B5; - font-weight:bold; -} -.nt { - color:#062873; - font-weight:bold; -} -.nv { - color:#BB60D5; -} -.ow { - color:#007020; - font-weight:bold; -} -.w { - color:#BBBBBB; -} -.mf { - color:#208050; -} -.mh { - color:#208050; -} -.mi { - color:#208050; -} -.mo { - color:#208050; -} -.sb { - color:#4070A0; -} -.sc { - color:#4070A0; -} -.sd { - color:#4070A0; - font-style:italic; -} -.s2 { - color:#4070A0; -} -.se { - color:#4070A0; - font-weight:bold; -} -.sh { - color:#4070A0; -} -.si { - color:#70A0D0; - font-style:italic; -} -.sx { - color:#C65D09; -} -.sr { - color:#235388; -} -.s1 { - color:#4070A0; -} -.ss { - color:#517918; -} -.bp { - color:#007020; -} -.vc { - color:#BB60D5; -} -.vg { - color:#BB60D5; -} -.vi { - color:#BB60D5; -} -.il { - color:#208050; -} diff --git a/pelican/tests/output/custom/theme/css/reset.css b/pelican/tests/output/custom/theme/css/reset.css deleted file mode 100644 index 10b3fde2..00000000 --- a/pelican/tests/output/custom/theme/css/reset.css +++ /dev/null @@ -1,52 +0,0 @@ -/* - Name: Reset Stylesheet - Description: Resets browser's default CSS - Author: Eric Meyer - Author URI: https://meyerweb.com/eric/tools/css/reset/ -*/ - -/* v1.0 | 20080212 */ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, font, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td { - background: transparent; - border: 0; - font-size: 100%; - margin: 0; - outline: 0; - padding: 0; - vertical-align: baseline; -} - -body {line-height: 1;} - -ol, ul {list-style: none;} - -blockquote, q {quotes: none;} - -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} - -/* remember to define focus styles! */ -:focus { - outline: 0; -} - -/* remember to highlight inserts somehow! */ -ins {text-decoration: none;} -del {text-decoration: line-through;} - -/* tables still need 'cellspacing="0"' in the markup */ -table { - border-collapse: collapse; - border-spacing: 0; -} diff --git a/pelican/tests/output/custom/theme/css/typogrify.css b/pelican/tests/output/custom/theme/css/typogrify.css deleted file mode 100644 index 3bae4976..00000000 --- a/pelican/tests/output/custom/theme/css/typogrify.css +++ /dev/null @@ -1,3 +0,0 @@ -.caps {font-size:.92em;} -.amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;} -.dquo {margin-left:-.38em;} diff --git a/pelican/tests/output/custom/theme/css/wide.css b/pelican/tests/output/custom/theme/css/wide.css deleted file mode 100644 index 88fd59ce..00000000 --- a/pelican/tests/output/custom/theme/css/wide.css +++ /dev/null @@ -1,48 +0,0 @@ -@import url("main.css"); - -body { - font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif; -} - -.post-info{ - display: none; -} - -#banner nav { - display: none; - -moz-border-radius: 0px; - margin-bottom: 20px; - overflow: hidden; - font-size: 1em; - background: #F5F4EF; -} - -#banner nav ul{ - padding-right: 50px; -} - -#banner nav li{ - float: right; - color: #000; -} - -#banner nav li a { - color: #000; -} - -#banner h1 { - margin-bottom: -18px; -} - -#featured, #extras { - padding: 50px; -} - -#featured { - padding-top: 20px; -} - -#extras { - padding-top: 0px; - padding-bottom: 0px; -} diff --git a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.eot b/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.eot deleted file mode 100644 index b3b90dbc..00000000 Binary files a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.eot and /dev/null differ diff --git a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.svg b/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.svg deleted file mode 100644 index a69669b5..00000000 --- a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.svg +++ /dev/null @@ -1,407 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.ttf b/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.ttf deleted file mode 100644 index 6f4feb02..00000000 Binary files a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.ttf and /dev/null differ diff --git a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.woff b/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.woff deleted file mode 100644 index ddccf765..00000000 Binary files a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.woff and /dev/null differ diff --git a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.woff2 b/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.woff2 deleted file mode 100644 index 7b18f7ea..00000000 Binary files a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_400.woff2 and /dev/null differ diff --git a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_LICENSE.txt b/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_LICENSE.txt deleted file mode 100644 index c70bcad3..00000000 --- a/pelican/tests/output/custom/theme/fonts/Yanone_Kaffeesatz_LICENSE.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2010 The Yanone Kaffeesatz Project Authors (https://github.com/alexeiva/yanone-kaffeesatz) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/pelican/tests/output/custom/theme/fonts/font.css b/pelican/tests/output/custom/theme/fonts/font.css deleted file mode 100644 index cf623603..00000000 --- a/pelican/tests/output/custom/theme/fonts/font.css +++ /dev/null @@ -1,12 +0,0 @@ -@font-face { - font-family: 'Yanone Kaffeesatz'; - font-style: normal; - font-weight: 400; - src: - local('Yanone Kaffeesatz Regular'), - local('YanoneKaffeesatz-Regular'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff */ - url('Yanone_Kaffeesatz_400.woff') format('woff'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLfGwxTS8d1Q9KiDNCMKLFUM.woff2 */ - url('Yanone_Kaffeesatz_400.woff2') format('woff2'); -} diff --git a/pelican/tests/output/custom/this-is-a-super-article.html b/pelican/tests/output/custom/this-is-a-super-article.html deleted file mode 100644 index 222fcbab..00000000 --- a/pelican/tests/output/custom/this-is-a-super-article.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - - This is a super article ! - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - This is a super article !

    -
    - -
    -

    Some content here !

    -
    -

    This is a simple title

    -

    And here comes the cool stuff.

    - alternate text - alternate text -
    ->>> from ipdb import set_trace
    ->>> set_trace()
    -
    -

    → And now try with some utf8 hell: ééé

    -
    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom/unbelievable.html b/pelican/tests/output/custom/unbelievable.html deleted file mode 100644 index 0d88db61..00000000 --- a/pelican/tests/output/custom/unbelievable.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - Unbelievable ! - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Unbelievable !

    -
    - -
    -

    Or completely awesome. Depends the needs.

    -

    a root-relative link to markdown-article - a file-relative link to markdown-article

    -
    -

    Testing sourcecode directive

    -
    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    -
    -
    -
    -

    Testing another case

    -

    This will now have a line number in 'custom' since it's the default in - pelican.conf, it will have nothing in default.

    -
    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    -
    -

    Lovely.

    -
    -
    -

    Testing more sourcecode directives

    -
     8def run(self):
    self.assert_has_content()
    10 try:
    lexer = get_lexer_by_name(self.arguments[0])
    12 except ValueError:
    # no lexer found - use the text one instead of an exception
    14 lexer = TextLexer()

    16 if ('linenos' in self.options and
    self.options['linenos'] not in ('table', 'inline')):
    18 self.options['linenos'] = 'table'

    20 for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
    if flag in self.options:
    22 self.options[flag] = True

    24 # noclasses should already default to False, but just in case...
    formatter = HtmlFormatter(noclasses=False, **self.options)
    26 parsed = highlight('\n'.join(self.content), lexer, formatter)
    return [nodes.raw('', parsed, format='html')]
    -

    Lovely.

    -
    -
    -

    Testing even more sourcecode directives

    - formatter = self.options and VARIANTS[self.options.keys()[0]] -

    Lovely.

    -
    -
    -

    Testing overriding config defaults

    -

    Even if the default is line numbers, we can override it here

    -
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    -
    -

    Lovely.

    -
    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/archives.html b/pelican/tests/output/custom_locale/archives.html deleted file mode 100644 index 3e85bc13..00000000 --- a/pelican/tests/output/custom_locale/archives.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - Alexis' log - - - - - - - - Fork me on GitHub - - -
    -

    Archives for Alexis' log

    - -
    -
    30 novembre 2012
    -
    FILENAME_METADATA example
    -
    29 février 2012
    -
    Second article
    -
    20 avril 2011
    -
    A markdown powered article
    -
    17 février 2011
    -
    Article 1
    -
    17 février 2011
    -
    Article 2
    -
    17 février 2011
    -
    Article 3
    -
    02 décembre 2010
    -
    This is a super article !
    -
    20 octobre 2010
    -
    Oh yeah !
    -
    15 octobre 2010
    -
    Unbelievable !
    -
    14 mars 2010
    -
    The baz tag
    -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/author/alexis-metaireau.html b/pelican/tests/output/custom_locale/author/alexis-metaireau.html deleted file mode 100644 index 7582d623..00000000 --- a/pelican/tests/output/custom_locale/author/alexis-metaireau.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - Alexis' log - Alexis Métaireau - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. - -
    3. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/author/alexis-metaireau2.html b/pelican/tests/output/custom_locale/author/alexis-metaireau2.html deleted file mode 100644 index 0ba022b7..00000000 --- a/pelican/tests/output/custom_locale/author/alexis-metaireau2.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - Alexis' log - Alexis Métaireau - - - - - - - - Fork me on GitHub - - - -
    -
      -
    1. - -
    2. - -
    3. - -
    4. -
      -

      Oh yeah !

      -
      - -
      -
      -

      Why not ?

      -

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

      - alternate text -
      - - read more -

      There are comments.

      -
    5. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/author/alexis-metaireau3.html b/pelican/tests/output/custom_locale/author/alexis-metaireau3.html deleted file mode 100644 index 5033e7f2..00000000 --- a/pelican/tests/output/custom_locale/author/alexis-metaireau3.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - Alexis' log - Alexis Métaireau - - - - - - - - Fork me on GitHub - - - -
    -
      -
    1. - -
    2. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/authors.html b/pelican/tests/output/custom_locale/authors.html deleted file mode 100644 index 1d1bb320..00000000 --- a/pelican/tests/output/custom_locale/authors.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - Alexis' log - Authors - - - - - - - - Fork me on GitHub - - - -
    -

    Authors on Alexis' log

    - -
    - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/categories.html b/pelican/tests/output/custom_locale/categories.html deleted file mode 100644 index 9a684dd2..00000000 --- a/pelican/tests/output/custom_locale/categories.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - Alexis' log - Categories - - - - - - - - Fork me on GitHub - - - -
    -

    Categories for Alexis' log

    - -
    - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/category/bar.html b/pelican/tests/output/custom_locale/category/bar.html deleted file mode 100644 index c061c8d8..00000000 --- a/pelican/tests/output/custom_locale/category/bar.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - Alexis' log - bar - - - - - - - - Fork me on GitHub - - - - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/category/cat1.html b/pelican/tests/output/custom_locale/category/cat1.html deleted file mode 100644 index a1b9156b..00000000 --- a/pelican/tests/output/custom_locale/category/cat1.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - - Alexis' log - cat1 - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. - -
    3. -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/category/misc.html b/pelican/tests/output/custom_locale/category/misc.html deleted file mode 100644 index 8df30965..00000000 --- a/pelican/tests/output/custom_locale/category/misc.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - - Alexis' log - misc - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. - -
    3. -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/category/yeah.html b/pelican/tests/output/custom_locale/category/yeah.html deleted file mode 100644 index 9e22f4f3..00000000 --- a/pelican/tests/output/custom_locale/category/yeah.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - Alexis' log - yeah - - - - - - - - Fork me on GitHub - - - - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/drafts/a-draft-article-without-date.html b/pelican/tests/output/custom_locale/drafts/a-draft-article-without-date.html deleted file mode 100644 index cf8c8760..00000000 --- a/pelican/tests/output/custom_locale/drafts/a-draft-article-without-date.html +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - A draft article without date - - - - - - - - - Fork me on GitHub - - -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/drafts/a-draft-article.html b/pelican/tests/output/custom_locale/drafts/a-draft-article.html deleted file mode 100644 index 56f9e0b4..00000000 --- a/pelican/tests/output/custom_locale/drafts/a-draft-article.html +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - A draft article - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - A draft article

    -
    - -
    -

    This is a draft article, it should live under the /drafts/ folder and not be - listed anywhere else.

    - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/feeds/alexis-metaireau.atom.xml b/pelican/tests/output/custom_locale/feeds/alexis-metaireau.atom.xml deleted file mode 100644 index 85b63173..00000000 --- a/pelican/tests/output/custom_locale/feeds/alexis-metaireau.atom.xml +++ /dev/null @@ -1,74 +0,0 @@ - -Alexis' log - Alexis Métaireauhttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> -Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/<p>This is some article, in english</p> -A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/<p>Article 1</p> -Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/<p>Article 2</p> -Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/<p>Article 3</p> -This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> -Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will have nothing in default.</p> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-more-sourcecode-directives"> -<h2>Testing more sourcecode directives</h2> -<div class="highlight"><pre><span></span><span id="foo-8"><a id="foo-8" name="foo-8"></a><a href="#foo-8"><span class="linenos special"> 8</span></a><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a id="foo-9" name="foo-9"></a><a href="#foo-9"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a id="foo-10" name="foo-10"></a><a href="#foo-10"><span class="linenos special">10</span></a> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a id="foo-11" name="foo-11"></a><a href="#foo-11"><span class="linenos"> </span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a id="foo-12" name="foo-12"></a><a href="#foo-12"><span class="linenos special">12</span></a> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a id="foo-13" name="foo-13"></a><a href="#foo-13"><span class="linenos"> </span></a> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a id="foo-14" name="foo-14"></a><a href="#foo-14"><span class="linenos special">14</span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a id="foo-15" name="foo-15"></a><a href="#foo-15"><span class="linenos"> </span></a><br></span><span id="foo-16"><a id="foo-16" name="foo-16"></a><a href="#foo-16"><span class="linenos special">16</span></a> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a id="foo-17" name="foo-17"></a><a href="#foo-17"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a id="foo-18" name="foo-18"></a><a href="#foo-18"><span class="linenos special">18</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a id="foo-19" name="foo-19"></a><a href="#foo-19"><span class="linenos"> </span></a><br></span><span id="foo-20"><a id="foo-20" name="foo-20"></a><a href="#foo-20"><span class="linenos special">20</span></a> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a id="foo-21" name="foo-21"></a><a href="#foo-21"><span class="linenos"> </span></a> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a id="foo-22" name="foo-22"></a><a href="#foo-22"><span class="linenos special">22</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingkc">True</span><br></span><span id="foo-23"><a id="foo-23" name="foo-23"></a><a href="#foo-23"><span class="linenos"> </span></a><br></span><span id="foo-24"><a id="foo-24" name="foo-24"></a><a href="#foo-24"><span class="linenos special">24</span></a> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a id="foo-25" name="foo-25"></a><a href="#foo-25"><span class="linenos"> </span></a> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingkc">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a id="foo-26" name="foo-26"></a><a href="#foo-26"><span class="linenos special">26</span></a> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a id="foo-27" name="foo-27"></a><a href="#foo-27"><span class="linenos"> </span></a> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingnb">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-even-more-sourcecode-directives"> -<h2>Testing even more sourcecode directives</h2> -<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -<p>Lovely.</p> -</div> -<div class="section" id="testing-overriding-config-defaults"> -<h2>Testing overriding config defaults</h2> -<p>Even if the default is line numbers, we can override it here</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> - diff --git a/pelican/tests/output/custom_locale/feeds/alexis-metaireau.rss.xml b/pelican/tests/output/custom_locale/feeds/alexis-metaireau.rss.xml deleted file mode 100644 index f383a84d..00000000 --- a/pelican/tests/output/custom_locale/feeds/alexis-metaireau.rss.xml +++ /dev/null @@ -1,29 +0,0 @@ - -Alexis' log - Alexis Métaireauhttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> -Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/miscSecond articlehttp://blog.notmyidea.org/posts/2012/f%C3%A9vrier/29/second-article/<p>This is some article, in english</p> -Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/miscfoobarbazA markdown powered articlehttp://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/cat1Article 1http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-1/<p>Article 1</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/cat1Article 2http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-2/<p>Article 2</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/cat1Article 3http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-3/<p>Article 3</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/cat1This is a super article !http://blog.notmyidea.org/posts/2010/d%C3%A9cembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/yeahfoobarfoobarOh yeah !http://blog.notmyidea.org/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/barohbaryeahUnbelievable !http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/miscThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> -Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlmisc diff --git a/pelican/tests/output/custom_locale/feeds/all-en.atom.xml b/pelican/tests/output/custom_locale/feeds/all-en.atom.xml deleted file mode 100644 index 974b4279..00000000 --- a/pelican/tests/output/custom_locale/feeds/all-en.atom.xml +++ /dev/null @@ -1,74 +0,0 @@ - -Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> -Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/<p>This is some article, in english</p> -A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/<p>Article 1</p> -Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/<p>Article 2</p> -Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/<p>Article 3</p> -This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> -Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will have nothing in default.</p> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-more-sourcecode-directives"> -<h2>Testing more sourcecode directives</h2> -<div class="highlight"><pre><span></span><span id="foo-8"><a id="foo-8" name="foo-8"></a><a href="#foo-8"><span class="linenos special"> 8</span></a><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a id="foo-9" name="foo-9"></a><a href="#foo-9"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a id="foo-10" name="foo-10"></a><a href="#foo-10"><span class="linenos special">10</span></a> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a id="foo-11" name="foo-11"></a><a href="#foo-11"><span class="linenos"> </span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a id="foo-12" name="foo-12"></a><a href="#foo-12"><span class="linenos special">12</span></a> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a id="foo-13" name="foo-13"></a><a href="#foo-13"><span class="linenos"> </span></a> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a id="foo-14" name="foo-14"></a><a href="#foo-14"><span class="linenos special">14</span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a id="foo-15" name="foo-15"></a><a href="#foo-15"><span class="linenos"> </span></a><br></span><span id="foo-16"><a id="foo-16" name="foo-16"></a><a href="#foo-16"><span class="linenos special">16</span></a> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a id="foo-17" name="foo-17"></a><a href="#foo-17"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a id="foo-18" name="foo-18"></a><a href="#foo-18"><span class="linenos special">18</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a id="foo-19" name="foo-19"></a><a href="#foo-19"><span class="linenos"> </span></a><br></span><span id="foo-20"><a id="foo-20" name="foo-20"></a><a href="#foo-20"><span class="linenos special">20</span></a> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a id="foo-21" name="foo-21"></a><a href="#foo-21"><span class="linenos"> </span></a> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a id="foo-22" name="foo-22"></a><a href="#foo-22"><span class="linenos special">22</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingkc">True</span><br></span><span id="foo-23"><a id="foo-23" name="foo-23"></a><a href="#foo-23"><span class="linenos"> </span></a><br></span><span id="foo-24"><a id="foo-24" name="foo-24"></a><a href="#foo-24"><span class="linenos special">24</span></a> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a id="foo-25" name="foo-25"></a><a href="#foo-25"><span class="linenos"> </span></a> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingkc">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a id="foo-26" name="foo-26"></a><a href="#foo-26"><span class="linenos special">26</span></a> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a id="foo-27" name="foo-27"></a><a href="#foo-27"><span class="linenos"> </span></a> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingnb">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-even-more-sourcecode-directives"> -<h2>Testing even more sourcecode directives</h2> -<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -<p>Lovely.</p> -</div> -<div class="section" id="testing-overriding-config-defaults"> -<h2>Testing overriding config defaults</h2> -<p>Even if the default is line numbers, we can override it here</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> - diff --git a/pelican/tests/output/custom_locale/feeds/all-fr.atom.xml b/pelican/tests/output/custom_locale/feeds/all-fr.atom.xml deleted file mode 100644 index f44b17f2..00000000 --- a/pelican/tests/output/custom_locale/feeds/all-fr.atom.xml +++ /dev/null @@ -1,4 +0,0 @@ - -Alexis' loghttp://blog.notmyidea.org/2012-02-29T00:00:00+01:00Deuxième article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> -Trop bien !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah-fr.html<p>Et voila du contenu en français</p> - diff --git a/pelican/tests/output/custom_locale/feeds/all.atom.xml b/pelican/tests/output/custom_locale/feeds/all.atom.xml deleted file mode 100644 index c2a5ef38..00000000 --- a/pelican/tests/output/custom_locale/feeds/all.atom.xml +++ /dev/null @@ -1,76 +0,0 @@ - -Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> -Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/<p>This is some article, in english</p> -Deuxième article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/second-article-fr.html<p>Ceci est un article, en français.</p> -A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/<p>Article 1</p> -Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/<p>Article 2</p> -Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/<p>Article 3</p> -This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> -Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Trop bien !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/oh-yeah-fr.html<p>Et voila du contenu en français</p> -Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will have nothing in default.</p> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-more-sourcecode-directives"> -<h2>Testing more sourcecode directives</h2> -<div class="highlight"><pre><span></span><span id="foo-8"><a id="foo-8" name="foo-8"></a><a href="#foo-8"><span class="linenos special"> 8</span></a><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a id="foo-9" name="foo-9"></a><a href="#foo-9"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a id="foo-10" name="foo-10"></a><a href="#foo-10"><span class="linenos special">10</span></a> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a id="foo-11" name="foo-11"></a><a href="#foo-11"><span class="linenos"> </span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a id="foo-12" name="foo-12"></a><a href="#foo-12"><span class="linenos special">12</span></a> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a id="foo-13" name="foo-13"></a><a href="#foo-13"><span class="linenos"> </span></a> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a id="foo-14" name="foo-14"></a><a href="#foo-14"><span class="linenos special">14</span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a id="foo-15" name="foo-15"></a><a href="#foo-15"><span class="linenos"> </span></a><br></span><span id="foo-16"><a id="foo-16" name="foo-16"></a><a href="#foo-16"><span class="linenos special">16</span></a> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a id="foo-17" name="foo-17"></a><a href="#foo-17"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a id="foo-18" name="foo-18"></a><a href="#foo-18"><span class="linenos special">18</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a id="foo-19" name="foo-19"></a><a href="#foo-19"><span class="linenos"> </span></a><br></span><span id="foo-20"><a id="foo-20" name="foo-20"></a><a href="#foo-20"><span class="linenos special">20</span></a> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a id="foo-21" name="foo-21"></a><a href="#foo-21"><span class="linenos"> </span></a> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a id="foo-22" name="foo-22"></a><a href="#foo-22"><span class="linenos special">22</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingkc">True</span><br></span><span id="foo-23"><a id="foo-23" name="foo-23"></a><a href="#foo-23"><span class="linenos"> </span></a><br></span><span id="foo-24"><a id="foo-24" name="foo-24"></a><a href="#foo-24"><span class="linenos special">24</span></a> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a id="foo-25" name="foo-25"></a><a href="#foo-25"><span class="linenos"> </span></a> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingkc">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a id="foo-26" name="foo-26"></a><a href="#foo-26"><span class="linenos special">26</span></a> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a id="foo-27" name="foo-27"></a><a href="#foo-27"><span class="linenos"> </span></a> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingnb">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-even-more-sourcecode-directives"> -<h2>Testing even more sourcecode directives</h2> -<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -<p>Lovely.</p> -</div> -<div class="section" id="testing-overriding-config-defaults"> -<h2>Testing overriding config defaults</h2> -<p>Even if the default is line numbers, we can override it here</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> - diff --git a/pelican/tests/output/custom_locale/feeds/all.rss.xml b/pelican/tests/output/custom_locale/feeds/all.rss.xml deleted file mode 100644 index 9642bef9..00000000 --- a/pelican/tests/output/custom_locale/feeds/all.rss.xml +++ /dev/null @@ -1,31 +0,0 @@ - -Alexis' loghttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> -Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/miscSecond articlehttp://blog.notmyidea.org/posts/2012/f%C3%A9vrier/29/second-article/<p>This is some article, in english</p> -Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/miscfoobarbazDeuxième articlehttp://blog.notmyidea.org/second-article-fr.html<p>Ceci est un article, en français.</p> -Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/second-article-fr.htmlmiscfoobarbazA markdown powered articlehttp://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/cat1Article 1http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-1/<p>Article 1</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/cat1Article 2http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-2/<p>Article 2</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/cat1Article 3http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-3/<p>Article 3</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/cat1This is a super article !http://blog.notmyidea.org/posts/2010/d%C3%A9cembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/yeahfoobarfoobarOh yeah !http://blog.notmyidea.org/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/barohbaryeahTrop bien !http://blog.notmyidea.org/oh-yeah-fr.html<p>Et voila du contenu en français</p> -Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/oh-yeah-fr.htmlmiscUnbelievable !http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/miscThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> -Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlmisc diff --git a/pelican/tests/output/custom_locale/feeds/bar.atom.xml b/pelican/tests/output/custom_locale/feeds/bar.atom.xml deleted file mode 100644 index f3d8cc1e..00000000 --- a/pelican/tests/output/custom_locale/feeds/bar.atom.xml +++ /dev/null @@ -1,8 +0,0 @@ - -Alexis' log - barhttp://blog.notmyidea.org/2010-10-20T10:14:00+02:00Oh yeah !2010-10-20T10:14:00+02:002010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> - diff --git a/pelican/tests/output/custom_locale/feeds/bar.rss.xml b/pelican/tests/output/custom_locale/feeds/bar.rss.xml deleted file mode 100644 index 71130b31..00000000 --- a/pelican/tests/output/custom_locale/feeds/bar.rss.xml +++ /dev/null @@ -1,8 +0,0 @@ - -Alexis' log - barhttp://blog.notmyidea.org/Wed, 20 Oct 2010 10:14:00 +0200Oh yeah !http://blog.notmyidea.org/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> -<h2>Why not ?</h2> -<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! -YEAH !</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -</div> -Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:/posts/2010/octobre/20/oh-yeah/barohbaryeah diff --git a/pelican/tests/output/custom_locale/feeds/cat1.atom.xml b/pelican/tests/output/custom_locale/feeds/cat1.atom.xml deleted file mode 100644 index 9a72b398..00000000 --- a/pelican/tests/output/custom_locale/feeds/cat1.atom.xml +++ /dev/null @@ -1,7 +0,0 @@ - -Alexis' log - cat1http://blog.notmyidea.org/2011-04-20T00:00:00+02:00A markdown powered article2011-04-20T00:00:00+02:002011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/<p>Article 1</p> -Article 22011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/<p>Article 2</p> -Article 32011-02-17T00:00:00+01:002011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/<p>Article 3</p> - diff --git a/pelican/tests/output/custom_locale/feeds/cat1.rss.xml b/pelican/tests/output/custom_locale/feeds/cat1.rss.xml deleted file mode 100644 index c16b8092..00000000 --- a/pelican/tests/output/custom_locale/feeds/cat1.rss.xml +++ /dev/null @@ -1,7 +0,0 @@ - -Alexis' log - cat1http://blog.notmyidea.org/Wed, 20 Apr 2011 00:00:00 +0200A markdown powered articlehttp://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> -<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> -<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:/posts/2011/avril/20/a-markdown-powered-article/cat1Article 1http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-1/<p>Article 1</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-1/cat1Article 2http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-2/<p>Article 2</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-2/cat1Article 3http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-3/<p>Article 3</p> -Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:/posts/2011/février/17/article-3/cat1 diff --git a/pelican/tests/output/custom_locale/feeds/misc.atom.xml b/pelican/tests/output/custom_locale/feeds/misc.atom.xml deleted file mode 100644 index 4898ab84..00000000 --- a/pelican/tests/output/custom_locale/feeds/misc.atom.xml +++ /dev/null @@ -1,49 +0,0 @@ - -Alexis' log - mischttp://blog.notmyidea.org/2012-11-30T00:00:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:002012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> -Second article2012-02-29T00:00:00+01:002012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/<p>This is some article, in english</p> -Unbelievable !2010-10-15T20:30:00+02:002010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div><p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will have nothing in default.</p> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-more-sourcecode-directives"> -<h2>Testing more sourcecode directives</h2> -<div class="highlight"><pre><span></span><span id="foo-8"><a id="foo-8" name="foo-8"></a><a href="#foo-8"><span class="linenos special"> 8</span></a><span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a id="foo-9" name="foo-9"></a><a href="#foo-9"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a id="foo-10" name="foo-10"></a><a href="#foo-10"><span class="linenos special">10</span></a> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a id="foo-11" name="foo-11"></a><a href="#foo-11"><span class="linenos"> </span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a id="foo-12" name="foo-12"></a><a href="#foo-12"><span class="linenos special">12</span></a> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a id="foo-13" name="foo-13"></a><a href="#foo-13"><span class="linenos"> </span></a> <span class="testingc1"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a id="foo-14" name="foo-14"></a><a href="#foo-14"><span class="linenos special">14</span></a> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a id="foo-15" name="foo-15"></a><a href="#foo-15"><span class="linenos"> </span></a><br></span><span id="foo-16"><a id="foo-16" name="foo-16"></a><a href="#foo-16"><span class="linenos special">16</span></a> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings1">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a id="foo-17" name="foo-17"></a><a href="#foo-17"><span class="linenos"> </span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a id="foo-18" name="foo-18"></a><a href="#foo-18"><span class="linenos special">18</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings1">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings1">&#39;table&#39;</span><br></span><span id="foo-19"><a id="foo-19" name="foo-19"></a><a href="#foo-19"><span class="linenos"> </span></a><br></span><span id="foo-20"><a id="foo-20" name="foo-20"></a><a href="#foo-20"><span class="linenos special">20</span></a> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings1">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings1">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a id="foo-21" name="foo-21"></a><a href="#foo-21"><span class="linenos"> </span></a> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a id="foo-22" name="foo-22"></a><a href="#foo-22"><span class="linenos special">22</span></a> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingkc">True</span><br></span><span id="foo-23"><a id="foo-23" name="foo-23"></a><a href="#foo-23"><span class="linenos"> </span></a><br></span><span id="foo-24"><a id="foo-24" name="foo-24"></a><a href="#foo-24"><span class="linenos special">24</span></a> <span class="testingc1"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a id="foo-25" name="foo-25"></a><a href="#foo-25"><span class="linenos"> </span></a> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingkc">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a id="foo-26" name="foo-26"></a><a href="#foo-26"><span class="linenos special">26</span></a> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings1">&#39;</span><span class="testingse">\n</span><span class="testings1">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a id="foo-27" name="foo-27"></a><a href="#foo-27"><span class="linenos"> </span></a> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings1">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingnb">format</span><span class="testingo">=</span><span class="testings1">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> -<p>Lovely.</p> -</div> -<div class="section" id="testing-even-more-sourcecode-directives"> -<h2>Testing even more sourcecode directives</h2> -<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -<p>Lovely.</p> -</div> -<div class="section" id="testing-overriding-config-defaults"> -<h2>Testing overriding config defaults</h2> -<p>Even if the default is line numbers, we can override it here</p> -<div class="highlight"><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div> -<p>Lovely.</p> -</div> -The baz tag2010-03-14T00:00:00+01:002010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> - diff --git a/pelican/tests/output/custom_locale/feeds/misc.rss.xml b/pelican/tests/output/custom_locale/feeds/misc.rss.xml deleted file mode 100644 index d1493ae8..00000000 --- a/pelican/tests/output/custom_locale/feeds/misc.rss.xml +++ /dev/null @@ -1,16 +0,0 @@ - -Alexis' log - mischttp://blog.notmyidea.org/Fri, 30 Nov 2012 00:00:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> -Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:/posts/2012/novembre/30/filename_metadata-example/miscSecond articlehttp://blog.notmyidea.org/posts/2012/f%C3%A9vrier/29/second-article/<p>This is some article, in english</p> -Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:/posts/2012/février/29/second-article/miscfoobarbazUnbelievable !http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> -<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> -<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> -<div class="section" id="testing-sourcecode-directive"> -<h2>Testing sourcecode directive</h2> -<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> -</pre></div></td></tr></table></div> -</div> -<div class="section" id="testing-another-case"> -<h2>Testing another case</h2> -<p>This will now have a line number in 'custom' since it's the default in -pelican.conf, it will …</p></div>Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:/posts/2010/octobre/15/unbelievable/miscThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> -Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:/tag/baz.htmlmisc diff --git a/pelican/tests/output/custom_locale/feeds/yeah.atom.xml b/pelican/tests/output/custom_locale/feeds/yeah.atom.xml deleted file mode 100644 index f316ada5..00000000 --- a/pelican/tests/output/custom_locale/feeds/yeah.atom.xml +++ /dev/null @@ -1,16 +0,0 @@ - -Alexis' log - yeahhttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00This is a super article !2010-12-02T10:14:00+01:002013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -<p>Some content here !</p> -<div class="section" id="this-is-a-simple-title"> -<h2>This is a simple title</h2> -<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> -<pre class="literal-block"> -&gt;&gt;&gt; from ipdb import set_trace -&gt;&gt;&gt; set_trace() -</pre> -<p>→ And now try with some utf8 hell: ééé</p> -</div> - diff --git a/pelican/tests/output/custom_locale/feeds/yeah.rss.xml b/pelican/tests/output/custom_locale/feeds/yeah.rss.xml deleted file mode 100644 index a0d0ba28..00000000 --- a/pelican/tests/output/custom_locale/feeds/yeah.rss.xml +++ /dev/null @@ -1,4 +0,0 @@ - -Alexis' log - yeahhttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100This is a super article !http://blog.notmyidea.org/posts/2010/d%C3%A9cembre/02/this-is-a-super-article/<p class="first last">Multi-line metadata should be supported -as well as <strong>inline markup</strong>.</p> -Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:/posts/2010/décembre/02/this-is-a-super-article/yeahfoobarfoobar diff --git a/pelican/tests/output/custom_locale/index.html b/pelican/tests/output/custom_locale/index.html deleted file mode 100644 index 5c5c3c27..00000000 --- a/pelican/tests/output/custom_locale/index.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - Alexis' log - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. - -
    3. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/index2.html b/pelican/tests/output/custom_locale/index2.html deleted file mode 100644 index 68d4f195..00000000 --- a/pelican/tests/output/custom_locale/index2.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - Alexis' log - - - - - - - - Fork me on GitHub - - - -
    -
      -
    1. - -
    2. - -
    3. - -
    4. -
      -

      Oh yeah !

      -
      - -
      -
      -

      Why not ?

      -

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

      - alternate text -
      - - read more -

      There are comments.

      -
    5. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/index3.html b/pelican/tests/output/custom_locale/index3.html deleted file mode 100644 index 030ea072..00000000 --- a/pelican/tests/output/custom_locale/index3.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - Alexis' log - - - - - - - - Fork me on GitHub - - - -
    -
      -
    1. - -
    2. -
    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/jinja2_template.html b/pelican/tests/output/custom_locale/jinja2_template.html deleted file mode 100644 index 3d2ac0e1..00000000 --- a/pelican/tests/output/custom_locale/jinja2_template.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - Alexis' log - - - - - - - - Fork me on GitHub - - - - Some text - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/oh-yeah-fr.html b/pelican/tests/output/custom_locale/oh-yeah-fr.html deleted file mode 100644 index a3203152..00000000 --- a/pelican/tests/output/custom_locale/oh-yeah-fr.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - Trop bien ! - - - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Trop bien !

    -
    - -
    -

    Et voila du contenu en français

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/override/index.html b/pelican/tests/output/custom_locale/override/index.html deleted file mode 100644 index f457679f..00000000 --- a/pelican/tests/output/custom_locale/override/index.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - Override url/save_as - - - - - - - - Fork me on GitHub - - -
    -

    Override url/save_as

    - -

    Test page which overrides save_as and url so that this page will be generated - at a custom location.

    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/pages/this-is-a-test-hidden-page.html b/pelican/tests/output/custom_locale/pages/this-is-a-test-hidden-page.html deleted file mode 100644 index 12cab620..00000000 --- a/pelican/tests/output/custom_locale/pages/this-is-a-test-hidden-page.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - This is a test hidden page - - - - - - - - Fork me on GitHub - - -
    -

    This is a test hidden page

    - -

    This is great for things like error(404) pages - Anyone can see this page but it's not linked to anywhere!

    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/pages/this-is-a-test-page.html b/pelican/tests/output/custom_locale/pages/this-is-a-test-page.html deleted file mode 100644 index e945a3ed..00000000 --- a/pelican/tests/output/custom_locale/pages/this-is-a-test-page.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - This is a test page - - - - - - - - Fork me on GitHub - - -
    -

    This is a test page

    - -

    Just an image.

    - alternate text - wrong path since 'images' folder does not exist - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/pictures/Fat_Cat.jpg b/pelican/tests/output/custom_locale/pictures/Fat_Cat.jpg deleted file mode 100644 index d8a96d35..00000000 Binary files a/pelican/tests/output/custom_locale/pictures/Fat_Cat.jpg and /dev/null differ diff --git a/pelican/tests/output/custom_locale/pictures/Sushi.jpg b/pelican/tests/output/custom_locale/pictures/Sushi.jpg deleted file mode 100644 index e49e5f0a..00000000 Binary files a/pelican/tests/output/custom_locale/pictures/Sushi.jpg and /dev/null differ diff --git a/pelican/tests/output/custom_locale/pictures/Sushi_Macro.jpg b/pelican/tests/output/custom_locale/pictures/Sushi_Macro.jpg deleted file mode 100644 index 21f935a1..00000000 Binary files a/pelican/tests/output/custom_locale/pictures/Sushi_Macro.jpg and /dev/null differ diff --git a/pelican/tests/output/custom_locale/posts/2010/décembre/02/this-is-a-super-article/index.html b/pelican/tests/output/custom_locale/posts/2010/décembre/02/this-is-a-super-article/index.html deleted file mode 100644 index 336a13cf..00000000 --- a/pelican/tests/output/custom_locale/posts/2010/décembre/02/this-is-a-super-article/index.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - - This is a super article ! - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - This is a super article !

    -
    - -
    -

    Some content here !

    -
    -

    This is a simple title

    -

    And here comes the cool stuff.

    - alternate text - alternate text -
    ->>> from ipdb import set_trace
    ->>> set_trace()
    -
    -

    → And now try with some utf8 hell: ééé

    -
    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/posts/2010/octobre/15/unbelievable/index.html b/pelican/tests/output/custom_locale/posts/2010/octobre/15/unbelievable/index.html deleted file mode 100644 index a5788171..00000000 --- a/pelican/tests/output/custom_locale/posts/2010/octobre/15/unbelievable/index.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - Unbelievable ! - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Unbelievable !

    -
    - -
    -

    Or completely awesome. Depends the needs.

    -

    a root-relative link to markdown-article - a file-relative link to markdown-article

    -
    -

    Testing sourcecode directive

    -
    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    -
    -
    -
    -

    Testing another case

    -

    This will now have a line number in 'custom' since it's the default in - pelican.conf, it will have nothing in default.

    -
    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    -
    -

    Lovely.

    -
    -
    -

    Testing more sourcecode directives

    -
     8def run(self):
    self.assert_has_content()
    10 try:
    lexer = get_lexer_by_name(self.arguments[0])
    12 except ValueError:
    # no lexer found - use the text one instead of an exception
    14 lexer = TextLexer()

    16 if ('linenos' in self.options and
    self.options['linenos'] not in ('table', 'inline')):
    18 self.options['linenos'] = 'table'

    20 for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
    if flag in self.options:
    22 self.options[flag] = True

    24 # noclasses should already default to False, but just in case...
    formatter = HtmlFormatter(noclasses=False, **self.options)
    26 parsed = highlight('\n'.join(self.content), lexer, formatter)
    return [nodes.raw('', parsed, format='html')]
    -

    Lovely.

    -
    -
    -

    Testing even more sourcecode directives

    - formatter = self.options and VARIANTS[self.options.keys()[0]] -

    Lovely.

    -
    -
    -

    Testing overriding config defaults

    -

    Even if the default is line numbers, we can override it here

    -
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    -
    -

    Lovely.

    -
    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/posts/2010/octobre/20/oh-yeah/index.html b/pelican/tests/output/custom_locale/posts/2010/octobre/20/oh-yeah/index.html deleted file mode 100644 index 23c57785..00000000 --- a/pelican/tests/output/custom_locale/posts/2010/octobre/20/oh-yeah/index.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - Oh yeah ! - - - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Oh yeah !

    -
    - -
    -
    -

    Why not ?

    -

    After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

    - alternate text -
    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/posts/2011/avril/20/a-markdown-powered-article/index.html b/pelican/tests/output/custom_locale/posts/2011/avril/20/a-markdown-powered-article/index.html deleted file mode 100644 index c2e1cc57..00000000 --- a/pelican/tests/output/custom_locale/posts/2011/avril/20/a-markdown-powered-article/index.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - A markdown powered article - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - A markdown powered article

    -
    - -
    -

    You're mutually oblivious.

    -

    a root-relative link to unbelievable - a file-relative link to unbelievable

    -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/posts/2011/février/17/article-1/index.html b/pelican/tests/output/custom_locale/posts/2011/février/17/article-1/index.html deleted file mode 100644 index 0742bc52..00000000 --- a/pelican/tests/output/custom_locale/posts/2011/février/17/article-1/index.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - Article 1 - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Article 1

    -
    - -
    -

    Article 1

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/posts/2011/février/17/article-2/index.html b/pelican/tests/output/custom_locale/posts/2011/février/17/article-2/index.html deleted file mode 100644 index a5201ffb..00000000 --- a/pelican/tests/output/custom_locale/posts/2011/février/17/article-2/index.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - Article 2 - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Article 2

    -
    - -
    -

    Article 2

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/posts/2011/février/17/article-3/index.html b/pelican/tests/output/custom_locale/posts/2011/février/17/article-3/index.html deleted file mode 100644 index fe175d6f..00000000 --- a/pelican/tests/output/custom_locale/posts/2011/février/17/article-3/index.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - Article 3 - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Article 3

    -
    - -
    -

    Article 3

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/posts/2012/février/29/second-article/index.html b/pelican/tests/output/custom_locale/posts/2012/février/29/second-article/index.html deleted file mode 100644 index d2d3cfe1..00000000 --- a/pelican/tests/output/custom_locale/posts/2012/février/29/second-article/index.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - Second article - - - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Second article

    -
    - -
    -

    This is some article, in english

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/posts/2012/novembre/30/filename_metadata-example/index.html b/pelican/tests/output/custom_locale/posts/2012/novembre/30/filename_metadata-example/index.html deleted file mode 100644 index a596dbed..00000000 --- a/pelican/tests/output/custom_locale/posts/2012/novembre/30/filename_metadata-example/index.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - FILENAME_METADATA example - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - FILENAME_METADATA example

    -
    - -
    -

    Some cool stuff!

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/robots.txt b/pelican/tests/output/custom_locale/robots.txt deleted file mode 100644 index 19a6e299..00000000 --- a/pelican/tests/output/custom_locale/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: /pictures diff --git a/pelican/tests/output/custom_locale/second-article-fr.html b/pelican/tests/output/custom_locale/second-article-fr.html deleted file mode 100644 index e631a575..00000000 --- a/pelican/tests/output/custom_locale/second-article-fr.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - Deuxième article - - - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - Deuxième article

    -
    - -
    -

    Ceci est un article, en français.

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/tag/bar.html b/pelican/tests/output/custom_locale/tag/bar.html deleted file mode 100644 index f8edf2f2..00000000 --- a/pelican/tests/output/custom_locale/tag/bar.html +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - - Alexis' log - bar - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. - -
    2. -
      -

      Oh yeah !

      -
      - -
      -
      -

      Why not ?

      -

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! - YEAH !

      - alternate text -
      - - read more -

      There are comments.

      -
    3. -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/tag/baz.html b/pelican/tests/output/custom_locale/tag/baz.html deleted file mode 100644 index ad8fefa9..00000000 --- a/pelican/tests/output/custom_locale/tag/baz.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - The baz tag - - - - - - - - - Fork me on GitHub - - -
    -
    -
    -

    - The baz tag

    -
    - -
    -

    This article overrides the listening of the articles under the baz tag.

    - -
    -
    -

    Comments !

    -
    - - -
    - -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/tag/foo.html b/pelican/tests/output/custom_locale/tag/foo.html deleted file mode 100644 index 688666f8..00000000 --- a/pelican/tests/output/custom_locale/tag/foo.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - Alexis' log - foo - - - - - - - - Fork me on GitHub - - - - -
    -

    Other articles

    -
    -
      - -
    1. -
    -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/tag/foobar.html b/pelican/tests/output/custom_locale/tag/foobar.html deleted file mode 100644 index 6abc2d24..00000000 --- a/pelican/tests/output/custom_locale/tag/foobar.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - Alexis' log - foobar - - - - - - - - Fork me on GitHub - - - - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/tag/oh.html b/pelican/tests/output/custom_locale/tag/oh.html deleted file mode 100644 index 72cde941..00000000 --- a/pelican/tests/output/custom_locale/tag/oh.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - Oh Oh Oh - - - - - - - - Fork me on GitHub - - -
    -

    Oh Oh Oh

    - -

    This page overrides the listening of the articles under the oh tag.

    - -
    -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/tag/yeah.html b/pelican/tests/output/custom_locale/tag/yeah.html deleted file mode 100644 index b0a1a5ac..00000000 --- a/pelican/tests/output/custom_locale/tag/yeah.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - Alexis' log - yeah - - - - - - - - Fork me on GitHub - - - - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/tags.html b/pelican/tests/output/custom_locale/tags.html deleted file mode 100644 index 40daf2ef..00000000 --- a/pelican/tests/output/custom_locale/tags.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - Alexis' log - Tags - - - - - - - - Fork me on GitHub - - - -
    -

    Tags for Alexis' log

    - -
    - -
    - - -
    - - - - - - diff --git a/pelican/tests/output/custom_locale/theme/css/fonts.css b/pelican/tests/output/custom_locale/theme/css/fonts.css deleted file mode 100644 index 7c69215e..00000000 --- a/pelican/tests/output/custom_locale/theme/css/fonts.css +++ /dev/null @@ -1,12 +0,0 @@ -@font-face { - font-family: 'Yanone Kaffeesatz'; - font-style: normal; - font-weight: 400; - src: - local('Yanone Kaffeesatz Regular'), - local('YanoneKaffeesatz-Regular'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff */ - url('../fonts/Yanone_Kaffeesatz_400.woff') format('woff'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLfGwxTS8d1Q9KiDNCMKLFUM.woff2 */ - url('../fonts/Yanone_Kaffeesatz_400.woff2') format('woff2'); -} diff --git a/pelican/tests/output/custom_locale/theme/css/main.css b/pelican/tests/output/custom_locale/theme/css/main.css deleted file mode 100644 index c1d86950..00000000 --- a/pelican/tests/output/custom_locale/theme/css/main.css +++ /dev/null @@ -1,439 +0,0 @@ -/* - Name: Smashing HTML5 - Date: July 2009 - Description: Sample layout for HTML5 and CSS3 goodness. - Version: 1.0 - License: MIT - Licensed by: Smashing Media GmbH - Original author: Enrique Ramírez -*/ - -/* Imports */ -@import url("reset.css"); -@import url("pygment.css"); -@import url("typogrify.css"); -@import url("fonts.css"); - -/***** Global *****/ -/* Body */ -body { - background: #F5F4EF; - color: #000305; - font-size: 87.5%; /* Base font size: 14px */ - font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; - line-height: 1.429; - margin: 0; - padding: 0; - text-align: left; -} - -/* Headings */ -h1 {font-size: 2em } -h2 {font-size: 1.571em} /* 22px */ -h3 {font-size: 1.429em} /* 20px */ -h4 {font-size: 1.286em} /* 18px */ -h5 {font-size: 1.143em} /* 16px */ -h6 {font-size: 1em} /* 14px */ - -h1, h2, h3, h4, h5, h6 { - font-weight: 400; - line-height: 1.1; - margin-bottom: .8em; - font-family: 'Yanone Kaffeesatz', arial, serif; -} - -h3, h4, h5, h6 { margin-top: .8em; } - -hr { border: 2px solid #EEEEEE; } - -/* Anchors */ -a {outline: 0;} -a img {border: 0px; text-decoration: none;} -a:link, a:visited { - color: #C74350; - padding: 0 1px; - text-decoration: underline; -} -a:hover, a:active { - background-color: #C74350; - color: #fff; - text-decoration: none; - text-shadow: 1px 1px 1px #333; -} - -h1 a:hover { - background-color: inherit -} - -/* Paragraphs */ -div.line-block, -p { margin-top: 1em; - margin-bottom: 1em;} - -strong, b {font-weight: bold;} -em, i {font-style: italic;} - -/* Lists */ -ul { - list-style: outside disc; - margin: 0em 0 0 1.5em; -} - -ol { - list-style: outside decimal; - margin: 0em 0 0 1.5em; -} - -li { margin-top: 0.5em; - margin-bottom: 1em; } - -.post-info { - float:right; - margin:10px; - padding:5px; -} - -.post-info p{ - margin-top: 1px; - margin-bottom: 1px; -} - -.readmore { float: right } - -dl {margin: 0 0 1.5em 0;} -dt {font-weight: bold;} -dd {margin-left: 1.5em;} - -pre{background-color: rgb(238, 238, 238); padding: 10px; margin: 10px; overflow: auto;} - -/* Quotes */ -blockquote { - margin: 20px; - font-style: italic; -} -cite {} - -q {} - -div.note { - float: right; - margin: 5px; - font-size: 85%; - max-width: 300px; -} - -/* Tables */ -table {margin: .5em auto 1.5em auto; width: 98%;} - - /* Thead */ -thead th {padding: .5em .4em; text-align: left;} -thead td {} - - /* Tbody */ -tbody td {padding: .5em .4em;} -tbody th {} - -tbody .alt td {} -tbody .alt th {} - - /* Tfoot */ -tfoot th {} -tfoot td {} - -/* HTML5 tags */ -header, section, footer, -aside, nav, article, figure { - display: block; -} - -/***** Layout *****/ -.body {clear: both; margin: 0 auto; max-width: 800px;} -img { max-width: 100%; } -img.right, figure.right, div.figure.align-right { - float: right; - margin: 0 0 2em 2em; -} -img.left, figure.left, div.figure.align-left { - float: left; - margin: 0 2em 2em 0; -} - -/* .rst support */ -div.figure img, figure img { /* to fill figure exactly */ - max-width: 100%; -} -div.figure p.caption, figure p.caption { /* margin provided by figure */ - margin-top: 0; - margin-bottom: 0; -} - -/* - Header -*****************/ -#banner { - margin: 0 auto; - padding: 0.8em 0 0 0; -} - - /* Banner */ -#banner h1 { - font-size: 3.571em; - line-height: 1.0; - margin-bottom: .3em; -} - -#banner h1 a:link, #banner h1 a:visited { - color: #000305; - display: block; - font-weight: bold; - margin: 0 0 0 .2em; - text-decoration: none; -} -#banner h1 a:hover, #banner h1 a:active { - background: none; - color: #C74350; - text-shadow: none; -} - -#banner h1 strong {font-size: 0.36em; font-weight: normal;} - - /* Main Nav */ -#banner nav { - background: #000305; - font-size: 1.143em; - overflow: auto; - line-height: 30px; - margin: 0 auto 2em auto; - padding: 0; - text-align: center; - max-width: 800px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} - -#banner nav ul {list-style: none; margin: 0 auto; max-width: 800px;} -#banner nav li {float: left; display: inline; margin: 0;} - -#banner nav a:link, #banner nav a:visited { - color: #fff; - display: inline-block; - height: 30px; - padding: 5px 1.5em; - text-decoration: none; -} -#banner nav a:hover, #banner nav a:active, -#banner nav .active a:link, #banner nav .active a:visited { - background: #C74451; - color: #fff; - text-shadow: none !important; -} - -#banner nav li:first-child a { - border-top-left-radius: 5px; - -moz-border-radius-topleft: 5px; - -webkit-border-top-left-radius: 5px; - - border-bottom-left-radius: 5px; - -moz-border-radius-bottomleft: 5px; - -webkit-border-bottom-left-radius: 5px; -} - -/* - Featured -*****************/ -#featured { - background: #fff; - margin-bottom: 2em; - overflow: hidden; - padding: 20px; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -#featured figure { - border: 2px solid #eee; - float: right; - margin: 0.786em 2em 0 5em; - max-width: 248px; -} -#featured figure img {display: block; float: right;} - -#featured h2 {color: #C74451; font-size: 1.714em; margin-bottom: 0.333em;} -#featured h3 {font-size: 1.429em; margin-bottom: .5em;} - -#featured h3 a:link, #featured h3 a:visited {color: #000305; text-decoration: none;} -#featured h3 a:hover, #featured h3 a:active {color: #fff;} - -/* - Body -*****************/ -#content { - background: #fff; - margin-bottom: 2em; - overflow: hidden; - padding: 20px 20px; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -/* - Extras -*****************/ -#extras {margin: 0 auto 3em auto; overflow: hidden;} - -#extras ul {list-style: none; margin: 0;} -#extras li {border-bottom: 1px solid #fff;} -#extras h2 { - color: #C74350; - font-size: 1.429em; - margin-bottom: .25em; - padding: 0 3px; -} - -#extras a:link, #extras a:visited { - color: #444; - display: block; - border-bottom: 1px solid #F4E3E3; - text-decoration: none; - padding: .3em .25em; -} - -#extras a:hover, #extras a:active {color: #fff;} - - /* Blogroll */ -#extras .blogroll { - float: left; - max-width: 615px; -} - -#extras .blogroll li {float: left; margin: 0 20px 0 0; max-width: 185px;} - - /* Social */ -#extras .social { - float: right; - max-width: 175px; -} - -/* - About -*****************/ -#about { - background: #fff; - font-style: normal; - margin-bottom: 2em; - overflow: hidden; - padding: 20px; - text-align: left; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -#about .primary {float: left; max-width: 165px;} -#about .primary strong {color: #C64350; display: block; font-size: 1.286em;} -#about .photo {float: left; margin: 5px 20px;} - -#about .url:link, #about .url:visited {text-decoration: none;} - -#about .bio {float: right; max-width: 500px;} - -/* - Footer -*****************/ -#contentinfo {padding-bottom: 2em; text-align: right;} - -/***** Sections *****/ -/* Blog */ -.hentry { - display: block; - clear: both; - border-top: 1px solid #eee; - padding: 1.5em 0; -} -li:first-child .hentry, #content > .hentry {border: 0; margin: 0;} -#content > .hentry {padding: 1em 0;} -.hentry img{display : none ;} -.entry-title {font-size: 3em; margin-bottom: 10px; margin-top: 0;} -.entry-title a:link, .entry-title a:visited {text-decoration: none; color: #333;} -.entry-title a:visited {background-color: #fff;} - -.hentry .post-info * {font-style: normal;} - - /* Content */ -.hentry footer {margin-bottom: 2em;} -.hentry footer address {display: inline;} -#posts-list footer address {display: block;} - - /* Blog Index */ -#posts-list {list-style: none; margin: 0;} -#posts-list .hentry {padding-left: 10px; position: relative;} - -#posts-list footer { - left: 10px; - position: relative; - float: left; - top: 0.5em; - max-width: 190px; -} - - /* About the Author */ -#about-author { - background: #f9f9f9; - clear: both; - font-style: normal; - margin: 2em 0; - padding: 10px 20px 15px 20px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} - -#about-author strong { - color: #C64350; - clear: both; - display: block; - font-size: 1.429em; -} - -#about-author .photo {border: 1px solid #ddd; float: left; margin: 5px 1em 0 0;} - - /* Comments */ -#comments-list {list-style: none; margin: 0 1em;} -#comments-list blockquote { - background: #f8f8f8; - clear: both; - font-style: normal; - margin: 0; - padding: 15px 20px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} -#comments-list footer {color: #888; padding: .5em 1em 0 0; text-align: right;} - -#comments-list li:nth-child(2n) blockquote {background: #F5f5f5;} - - /* Add a Comment */ -#add-comment label {clear: left; float: left; text-align: left; max-width: 150px;} -#add-comment input[type='text'], -#add-comment input[type='email'], -#add-comment input[type='url'] {float: left; max-width: 200px;} - -#add-comment textarea {float: left; height: 150px; max-width: 495px;} - -#add-comment p.req {clear: both; margin: 0 .5em 1em 0; text-align: right;} - -#add-comment input[type='submit'] {float: right; margin: 0 .5em;} -#add-comment * {margin-bottom: .5em;} diff --git a/pelican/tests/output/custom_locale/theme/css/pygment.css b/pelican/tests/output/custom_locale/theme/css/pygment.css deleted file mode 100644 index a3877a83..00000000 --- a/pelican/tests/output/custom_locale/theme/css/pygment.css +++ /dev/null @@ -1,205 +0,0 @@ -.hll { - background-color:#eee; -} -.c { - color:#408090; - font-style:italic; -} -.err { - border:1px solid #FF0000; -} -.k { - color:#007020; - font-weight:bold; -} -.o { - color:#666666; -} -.cm { - color:#408090; - font-style:italic; -} -.cp { - color:#007020; -} -.c1 { - color:#408090; - font-style:italic; -} -.cs { - background-color:#FFF0F0; - color:#408090; -} -.gd { - color:#A00000; -} -.ge { - font-style:italic; -} -.gr { - color:#FF0000; -} -.gh { - color:#000080; - font-weight:bold; -} -.gi { - color:#00A000; -} -.go { - color:#303030; -} -.gp { - color:#C65D09; - font-weight:bold; -} -.gs { - font-weight:bold; -} -.gu { - color:#800080; - font-weight:bold; -} -.gt { - color:#0040D0; -} -.kc { - color:#007020; - font-weight:bold; -} -.kd { - color:#007020; - font-weight:bold; -} -.kn { - color:#007020; - font-weight:bold; -} -.kp { - color:#007020; -} -.kr { - color:#007020; - font-weight:bold; -} -.kt { - color:#902000; -} -.m { - color:#208050; -} -.s { - color:#4070A0; -} -.na { - color:#4070A0; -} -.nb { - color:#007020; -} -.nc { - color:#0E84B5; - font-weight:bold; -} -.no { - color:#60ADD5; -} -.nd { - color:#555555; - font-weight:bold; -} -.ni { - color:#D55537; - font-weight:bold; -} -.ne { - color:#007020; -} -.nf { - color:#06287E; -} -.nl { - color:#002070; - font-weight:bold; -} -.nn { - color:#0E84B5; - font-weight:bold; -} -.nt { - color:#062873; - font-weight:bold; -} -.nv { - color:#BB60D5; -} -.ow { - color:#007020; - font-weight:bold; -} -.w { - color:#BBBBBB; -} -.mf { - color:#208050; -} -.mh { - color:#208050; -} -.mi { - color:#208050; -} -.mo { - color:#208050; -} -.sb { - color:#4070A0; -} -.sc { - color:#4070A0; -} -.sd { - color:#4070A0; - font-style:italic; -} -.s2 { - color:#4070A0; -} -.se { - color:#4070A0; - font-weight:bold; -} -.sh { - color:#4070A0; -} -.si { - color:#70A0D0; - font-style:italic; -} -.sx { - color:#C65D09; -} -.sr { - color:#235388; -} -.s1 { - color:#4070A0; -} -.ss { - color:#517918; -} -.bp { - color:#007020; -} -.vc { - color:#BB60D5; -} -.vg { - color:#BB60D5; -} -.vi { - color:#BB60D5; -} -.il { - color:#208050; -} diff --git a/pelican/tests/output/custom_locale/theme/css/reset.css b/pelican/tests/output/custom_locale/theme/css/reset.css deleted file mode 100644 index 10b3fde2..00000000 --- a/pelican/tests/output/custom_locale/theme/css/reset.css +++ /dev/null @@ -1,52 +0,0 @@ -/* - Name: Reset Stylesheet - Description: Resets browser's default CSS - Author: Eric Meyer - Author URI: https://meyerweb.com/eric/tools/css/reset/ -*/ - -/* v1.0 | 20080212 */ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, font, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td { - background: transparent; - border: 0; - font-size: 100%; - margin: 0; - outline: 0; - padding: 0; - vertical-align: baseline; -} - -body {line-height: 1;} - -ol, ul {list-style: none;} - -blockquote, q {quotes: none;} - -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} - -/* remember to define focus styles! */ -:focus { - outline: 0; -} - -/* remember to highlight inserts somehow! */ -ins {text-decoration: none;} -del {text-decoration: line-through;} - -/* tables still need 'cellspacing="0"' in the markup */ -table { - border-collapse: collapse; - border-spacing: 0; -} diff --git a/pelican/tests/output/custom_locale/theme/css/typogrify.css b/pelican/tests/output/custom_locale/theme/css/typogrify.css deleted file mode 100644 index 3bae4976..00000000 --- a/pelican/tests/output/custom_locale/theme/css/typogrify.css +++ /dev/null @@ -1,3 +0,0 @@ -.caps {font-size:.92em;} -.amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;} -.dquo {margin-left:-.38em;} diff --git a/pelican/tests/output/custom_locale/theme/css/wide.css b/pelican/tests/output/custom_locale/theme/css/wide.css deleted file mode 100644 index 88fd59ce..00000000 --- a/pelican/tests/output/custom_locale/theme/css/wide.css +++ /dev/null @@ -1,48 +0,0 @@ -@import url("main.css"); - -body { - font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif; -} - -.post-info{ - display: none; -} - -#banner nav { - display: none; - -moz-border-radius: 0px; - margin-bottom: 20px; - overflow: hidden; - font-size: 1em; - background: #F5F4EF; -} - -#banner nav ul{ - padding-right: 50px; -} - -#banner nav li{ - float: right; - color: #000; -} - -#banner nav li a { - color: #000; -} - -#banner h1 { - margin-bottom: -18px; -} - -#featured, #extras { - padding: 50px; -} - -#featured { - padding-top: 20px; -} - -#extras { - padding-top: 0px; - padding-bottom: 0px; -} diff --git a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.eot b/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.eot deleted file mode 100644 index b3b90dbc..00000000 Binary files a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.eot and /dev/null differ diff --git a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.svg b/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.svg deleted file mode 100644 index a69669b5..00000000 --- a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.svg +++ /dev/null @@ -1,407 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.ttf b/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.ttf deleted file mode 100644 index 6f4feb02..00000000 Binary files a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.ttf and /dev/null differ diff --git a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.woff b/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.woff deleted file mode 100644 index ddccf765..00000000 Binary files a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.woff and /dev/null differ diff --git a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.woff2 b/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.woff2 deleted file mode 100644 index 7b18f7ea..00000000 Binary files a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_400.woff2 and /dev/null differ diff --git a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_LICENSE.txt b/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_LICENSE.txt deleted file mode 100644 index c70bcad3..00000000 --- a/pelican/tests/output/custom_locale/theme/fonts/Yanone_Kaffeesatz_LICENSE.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2010 The Yanone Kaffeesatz Project Authors (https://github.com/alexeiva/yanone-kaffeesatz) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/pelican/tests/output/custom_locale/theme/fonts/font.css b/pelican/tests/output/custom_locale/theme/fonts/font.css deleted file mode 100644 index cf623603..00000000 --- a/pelican/tests/output/custom_locale/theme/fonts/font.css +++ /dev/null @@ -1,12 +0,0 @@ -@font-face { - font-family: 'Yanone Kaffeesatz'; - font-style: normal; - font-weight: 400; - src: - local('Yanone Kaffeesatz Regular'), - local('YanoneKaffeesatz-Regular'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff */ - url('Yanone_Kaffeesatz_400.woff') format('woff'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLfGwxTS8d1Q9KiDNCMKLFUM.woff2 */ - url('Yanone_Kaffeesatz_400.woff2') format('woff2'); -} diff --git a/pelican/tests/parse_error/parse_error.rst b/pelican/tests/parse_error/parse_error.rst deleted file mode 100644 index 7aee68e1..00000000 --- a/pelican/tests/parse_error/parse_error.rst +++ /dev/null @@ -1,4 +0,0 @@ -Page with a parse error -############# - -The underline is too short. diff --git a/pelican/tests/simple_content/article_with_md_extension.md b/pelican/tests/simple_content/article_with_md_extension.md deleted file mode 120000 index 00a11ad3..00000000 --- a/pelican/tests/simple_content/article_with_md_extension.md +++ /dev/null @@ -1 +0,0 @@ -../content/article_with_md_extension.md \ No newline at end of file diff --git a/pelican/tests/support.py b/pelican/tests/support.py deleted file mode 100644 index f43468b2..00000000 --- a/pelican/tests/support.py +++ /dev/null @@ -1,279 +0,0 @@ -import locale -import logging -import os -import re -import subprocess -import sys -import unittest -from contextlib import contextmanager -from functools import wraps -from io import StringIO -from logging.handlers import BufferingHandler -from shutil import rmtree -from tempfile import mkdtemp - -from pelican.contents import Article -from pelican.readers import default_metadata -from pelican.settings import DEFAULT_CONFIG - -__all__ = [ - "get_article", - "unittest", -] - - -@contextmanager -def temporary_folder(): - """creates a temporary folder, return it and delete it afterwards. - - This allows to do something like this in tests: - - >>> with temporary_folder() as d: - # do whatever you want - """ - tempdir = mkdtemp() - try: - yield tempdir - finally: - rmtree(tempdir) - - -def isplit(s, sep=None): - """Behaves like str.split but returns a generator instead of a list. - - >>> list(isplit('\tUse the force\n')) == '\tUse the force\n'.split() - True - >>> list(isplit('\tUse the force\n')) == ['Use', 'the', 'force'] - True - >>> (list(isplit('\tUse the force\n', "e")) - == '\tUse the force\n'.split("e")) - True - >>> list(isplit('Use the force', "e")) == 'Use the force'.split("e") - True - >>> list(isplit('Use the force', "e")) == ['Us', ' th', ' forc', ''] - True - - """ - sep, hardsep = r"\s+" if sep is None else re.escape(sep), sep is not None - exp, pos, length = re.compile(sep), 0, len(s) - while True: - m = exp.search(s, pos) - if not m: - if pos < length or hardsep: - # ^ mimic "split()": ''.split() returns [] - yield s[pos:] - break - start = m.start() - if pos < start or hardsep: - # ^ mimic "split()": includes trailing empty string - yield s[pos:start] - pos = m.end() - - -def mute(returns_output=False): - """Decorate a function that prints to stdout, intercepting the output. - If "returns_output" is True, the function will return a generator - yielding the printed lines instead of the return values. - - The decorator literally hijack sys.stdout during each function - execution, so be careful with what you apply it to. - - >>> def numbers(): - print "42" - print "1984" - ... - >>> numbers() - 42 - 1984 - >>> mute()(numbers)() - >>> list(mute(True)(numbers)()) - ['42', '1984'] - - """ - - def decorator(func): - @wraps(func) - def wrapper(*args, **kwargs): - saved_stdout = sys.stdout - sys.stdout = StringIO() - - try: - out = func(*args, **kwargs) - if returns_output: - out = isplit(sys.stdout.getvalue().strip()) - finally: - sys.stdout = saved_stdout - - return out - - return wrapper - - return decorator - - -def get_article(title, content, **extra_metadata): - metadata = default_metadata(settings=DEFAULT_CONFIG) - metadata["title"] = title - if extra_metadata: - metadata.update(extra_metadata) - return Article(content, metadata=metadata) - - -def skipIfNoExecutable(executable): - """Skip test if `executable` is not found - - Tries to run `executable` with subprocess to make sure it's in the path, - and skips the tests if not found (if subprocess raises a `OSError`). - """ - - with open(os.devnull, "w") as fnull: - try: - res = subprocess.call(executable, stdout=fnull, stderr=fnull) - except OSError: - res = None - - if res is None: - return unittest.skip(f"{executable} executable not found") - - return lambda func: func - - -def module_exists(module_name): - """Test if a module is importable.""" - - try: - __import__(module_name) - except ImportError: - return False - else: - return True - - -def locale_available(locale_): - old_locale = locale.setlocale(locale.LC_TIME) - - try: - locale.setlocale(locale.LC_TIME, str(locale_)) - except locale.Error: - return False - else: - locale.setlocale(locale.LC_TIME, old_locale) - return True - - -def can_symlink(): - res = True - try: - with temporary_folder() as f: - os.symlink(f, os.path.join(f, "symlink")) - except OSError: - res = False - return res - - -def get_settings(**kwargs): - """Provide tweaked setting dictionaries for testing - - Set keyword arguments to override specific settings. - """ - settings = DEFAULT_CONFIG.copy() - for key, value in kwargs.items(): - settings[key] = value - return settings - - -def get_context(settings=None, **kwargs): - context = settings.copy() if settings else {} - context["generated_content"] = {} - context["static_links"] = set() - context["static_content"] = {} - context.update(kwargs) - return context - - -class LogCountHandler(BufferingHandler): - """Capturing and counting logged messages.""" - - def __init__(self, capacity=1000): - super().__init__(capacity) - - def count_logs(self, msg=None, level=None): - return len( - [ - rec - for rec in self.buffer - if (msg is None or re.match(msg, rec.getMessage())) - and (level is None or rec.levelno == level) - ] - ) - - def count_formatted_logs(self, msg=None, level=None): - return len( - [ - rec - for rec in self.buffer - if (msg is None or re.search(msg, self.format(rec))) - and (level is None or rec.levelno == level) - ] - ) - - -def diff_subproc(first, second): - """ - Return a subprocess that runs a diff on the two paths. - - Check results with:: - - >>> out_stream, err_stream = proc.communicate() - >>> didCheckFail = proc.returnCode != 0 - """ - return subprocess.Popen( - [ - "git", - "--no-pager", - "diff", - "--no-ext-diff", - "--exit-code", - "-w", - first, - second, - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - encoding="utf-8", - ) - - -class LoggedTestCase(unittest.TestCase): - """A test case that captures log messages.""" - - def setUp(self): - super().setUp() - self._logcount_handler = LogCountHandler() - logging.getLogger().addHandler(self._logcount_handler) - - def tearDown(self): - logging.getLogger().removeHandler(self._logcount_handler) - super().tearDown() - - def assertLogCountEqual(self, count=None, msg=None, **kwargs): - actual = self._logcount_handler.count_logs(msg=msg, **kwargs) - self.assertEqual( - actual, - count, - msg=f"expected {count} occurrences of {msg!r}, but found {actual}", - ) - - -class TestCaseWithCLocale(unittest.TestCase): - """Set locale to C for each test case, then restore afterward. - - Use utils.temporary_locale if you want a context manager ("with" statement). - """ - - def setUp(self): - self.old_locale = locale.setlocale(locale.LC_ALL) - locale.setlocale(locale.LC_ALL, "C") - - def tearDown(self): - locale.setlocale(locale.LC_ALL, self.old_locale) diff --git a/pelican/tests/test_cache.py b/pelican/tests/test_cache.py deleted file mode 100644 index 8876a8a5..00000000 --- a/pelican/tests/test_cache.py +++ /dev/null @@ -1,354 +0,0 @@ -import os -from shutil import rmtree -from tempfile import mkdtemp -from unittest.mock import MagicMock - -from pelican.generators import ArticlesGenerator, PagesGenerator -from pelican.tests.support import get_context, get_settings, unittest - -CUR_DIR = os.path.dirname(__file__) -CONTENT_DIR = os.path.join(CUR_DIR, "content") - - -class TestCache(unittest.TestCase): - def setUp(self): - self.temp_cache = mkdtemp(prefix="pelican_cache.") - - def tearDown(self): - rmtree(self.temp_cache) - - def _get_cache_enabled_settings(self): - settings = get_settings() - settings["CACHE_CONTENT"] = True - settings["LOAD_CONTENT_CACHE"] = True - settings["CACHE_PATH"] = self.temp_cache - return settings - - def test_generator_caching(self): - """Test that cached and uncached content is same in generator level""" - settings = self._get_cache_enabled_settings() - settings["CONTENT_CACHING_LAYER"] = "generator" - settings["PAGE_PATHS"] = ["TestPages"] - settings["DEFAULT_DATE"] = (1970, 1, 1) - settings["READERS"] = {"asc": None} - context = get_context(settings) - - def sorted_titles(items): - return sorted(item.title for item in items) - - # Articles - generator = ArticlesGenerator( - context=context.copy(), - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - uncached_articles = sorted_titles(generator.articles) - uncached_drafts = sorted_titles(generator.drafts) - - generator = ArticlesGenerator( - context=context.copy(), - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - cached_articles = sorted_titles(generator.articles) - cached_drafts = sorted_titles(generator.drafts) - - self.assertEqual(uncached_articles, cached_articles) - self.assertEqual(uncached_drafts, cached_drafts) - - # Pages - generator = PagesGenerator( - context=context.copy(), - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - uncached_pages = sorted_titles(generator.pages) - uncached_hidden_pages = sorted_titles(generator.hidden_pages) - uncached_draft_pages = sorted_titles(generator.draft_pages) - - generator = PagesGenerator( - context=context.copy(), - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - cached_pages = sorted_titles(generator.pages) - cached_hidden_pages = sorted_titles(generator.hidden_pages) - cached_draft_pages = sorted_titles(generator.draft_pages) - - self.assertEqual(uncached_pages, cached_pages) - self.assertEqual(uncached_hidden_pages, cached_hidden_pages) - self.assertEqual(uncached_draft_pages, cached_draft_pages) - - def test_reader_caching(self): - """Test that cached and uncached content is same in reader level""" - settings = self._get_cache_enabled_settings() - settings["CONTENT_CACHING_LAYER"] = "reader" - settings["PAGE_PATHS"] = ["TestPages"] - settings["DEFAULT_DATE"] = (1970, 1, 1) - settings["READERS"] = {"asc": None} - context = get_context(settings) - - def sorted_titles(items): - return sorted(item.title for item in items) - - # Articles - generator = ArticlesGenerator( - context=context.copy(), - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - uncached_articles = sorted_titles(generator.articles) - uncached_drafts = sorted_titles(generator.drafts) - - generator = ArticlesGenerator( - context=context.copy(), - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - cached_articles = sorted_titles(generator.articles) - cached_drafts = sorted_titles(generator.drafts) - - self.assertEqual(uncached_articles, cached_articles) - self.assertEqual(uncached_drafts, cached_drafts) - - # Pages - generator = PagesGenerator( - context=context.copy(), - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - uncached_pages = sorted_titles(generator.pages) - uncached_hidden_pages = sorted_titles(generator.hidden_pages) - - generator = PagesGenerator( - context=context.copy(), - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - cached_pages = sorted_titles(generator.pages) - cached_hidden_pages = sorted_titles(generator.hidden_pages) - - self.assertEqual(uncached_pages, cached_pages) - self.assertEqual(uncached_hidden_pages, cached_hidden_pages) - - def test_article_object_caching(self): - """Test Article objects caching at the generator level""" - settings = self._get_cache_enabled_settings() - settings["CONTENT_CACHING_LAYER"] = "generator" - settings["DEFAULT_DATE"] = (1970, 1, 1) - settings["READERS"] = {"asc": None} - context = get_context(settings) - - generator = ArticlesGenerator( - context=context.copy(), - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - self.assertTrue(hasattr(generator, "_cache")) - - generator = ArticlesGenerator( - context=context.copy(), - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.readers.read_file = MagicMock() - generator.generate_context() - """ - 7 files don't get cached because they were not valid - - article_with_attributes_containing_double_quotes.html - - article_with_comments.html - - article_with_null_attributes.html - - 2012-11-30_md_w_filename_meta#foo-bar.md - - empty.md - - empty_with_bom.md - - article_skip.md - """ - self.assertEqual(generator.readers.read_file.call_count, 7) - - def test_article_reader_content_caching(self): - """Test raw article content caching at the reader level""" - settings = self._get_cache_enabled_settings() - settings["READERS"] = {"asc": None} - context = get_context(settings) - - generator = ArticlesGenerator( - context=context.copy(), - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - self.assertTrue(hasattr(generator.readers, "_cache")) - - generator = ArticlesGenerator( - context=context.copy(), - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - readers = generator.readers.readers - for reader in readers.values(): - reader.read = MagicMock() - generator.generate_context() - for reader in readers.values(): - self.assertEqual(reader.read.call_count, 0) - - def test_article_ignore_cache(self): - """Test that all the articles are read again when not loading cache - - used in --ignore-cache or autoreload mode""" - settings = self._get_cache_enabled_settings() - settings["READERS"] = {"asc": None} - context = get_context(settings) - - generator = ArticlesGenerator( - context=context.copy(), - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.readers.read_file = MagicMock() - generator.generate_context() - self.assertTrue(hasattr(generator, "_cache_open")) - orig_call_count = generator.readers.read_file.call_count - - settings["LOAD_CONTENT_CACHE"] = False - generator = ArticlesGenerator( - context=context.copy(), - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.readers.read_file = MagicMock() - generator.generate_context() - self.assertEqual(generator.readers.read_file.call_count, orig_call_count) - - def test_page_object_caching(self): - """Test Page objects caching at the generator level""" - settings = self._get_cache_enabled_settings() - settings["CONTENT_CACHING_LAYER"] = "generator" - settings["PAGE_PATHS"] = ["TestPages"] - settings["READERS"] = {"asc": None} - context = get_context(settings) - - generator = PagesGenerator( - context=context.copy(), - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - self.assertTrue(hasattr(generator, "_cache")) - - generator = PagesGenerator( - context=context.copy(), - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.readers.read_file = MagicMock() - generator.generate_context() - """ - 1 File doesn't get cached because it was not valid - - bad_page.rst - """ - self.assertEqual(generator.readers.read_file.call_count, 1) - - def test_page_reader_content_caching(self): - """Test raw page content caching at the reader level""" - settings = self._get_cache_enabled_settings() - settings["PAGE_PATHS"] = ["TestPages"] - settings["READERS"] = {"asc": None} - context = get_context(settings) - - generator = PagesGenerator( - context=context.copy(), - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - self.assertTrue(hasattr(generator.readers, "_cache")) - - generator = PagesGenerator( - context=context.copy(), - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - readers = generator.readers.readers - for reader in readers.values(): - reader.read = MagicMock() - generator.generate_context() - for reader in readers.values(): - self.assertEqual(reader.read.call_count, 0) - - def test_page_ignore_cache(self): - """Test that all the pages are read again when not loading cache - - used in --ignore_cache or autoreload mode""" - settings = self._get_cache_enabled_settings() - settings["PAGE_PATHS"] = ["TestPages"] - settings["READERS"] = {"asc": None} - context = get_context(settings) - - generator = PagesGenerator( - context=context.copy(), - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.readers.read_file = MagicMock() - generator.generate_context() - self.assertTrue(hasattr(generator, "_cache_open")) - orig_call_count = generator.readers.read_file.call_count - - settings["LOAD_CONTENT_CACHE"] = False - generator = PagesGenerator( - context=context.copy(), - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.readers.read_file = MagicMock() - generator.generate_context() - self.assertEqual(generator.readers.read_file.call_count, orig_call_count) diff --git a/pelican/tests/test_cli.py b/pelican/tests/test_cli.py deleted file mode 100644 index 0b9656be..00000000 --- a/pelican/tests/test_cli.py +++ /dev/null @@ -1,81 +0,0 @@ -import unittest - -from pelican import get_config, parse_arguments - - -class TestParseOverrides(unittest.TestCase): - def test_flags(self): - for flag in ["-e", "--extra-settings"]: - args = parse_arguments([flag, "k=1"]) - self.assertDictEqual(args.overrides, {"k": 1}) - - def test_parse_multiple_items(self): - args = parse_arguments("-e k1=1 k2=2".split()) - self.assertDictEqual(args.overrides, {"k1": 1, "k2": 2}) - - def test_parse_valid_json(self): - json_values_python_values_map = { - '""': "", - "null": None, - '"string"': "string", - '["foo", 12, "4", {}]': ["foo", 12, "4", {}], - } - for k, v in json_values_python_values_map.items(): - args = parse_arguments(["-e", "k=" + k]) - self.assertDictEqual(args.overrides, {"k": v}) - - def test_parse_invalid_syntax(self): - invalid_items = ["k= 1", "k =1", "k", "k v"] - for item in invalid_items: - with self.assertRaises(ValueError): - parse_arguments(f"-e {item}".split()) - - def test_parse_invalid_json(self): - invalid_json = { - "", - "False", - "True", - "None", - "some other string", - '{"foo": bar}', - "[foo]", - } - for v in invalid_json: - with self.assertRaises(ValueError): - parse_arguments(["-e ", "k=" + v]) - - -class TestGetConfigFromArgs(unittest.TestCase): - def test_overrides_known_keys(self): - args = parse_arguments( - [ - "-e", - "DELETE_OUTPUT_DIRECTORY=false", - 'OUTPUT_RETENTION=["1.txt"]', - 'SITENAME="Title"', - ] - ) - config = get_config(args) - config_must_contain = { - "DELETE_OUTPUT_DIRECTORY": False, - "OUTPUT_RETENTION": ["1.txt"], - "SITENAME": "Title", - } - self.assertDictEqual(config, {**config, **config_must_contain}) - - def test_overrides_non_default_type(self): - args = parse_arguments( - [ - "-e", - "DISPLAY_PAGES_ON_MENU=123", - "PAGE_TRANSLATION_ID=null", - 'TRANSLATION_FEED_RSS_URL="someurl"', - ] - ) - config = get_config(args) - config_must_contain = { - "DISPLAY_PAGES_ON_MENU": 123, - "PAGE_TRANSLATION_ID": None, - "TRANSLATION_FEED_RSS_URL": "someurl", - } - self.assertDictEqual(config, {**config, **config_must_contain}) diff --git a/pelican/tests/test_contents.py b/pelican/tests/test_contents.py deleted file mode 100644 index 06d1a690..00000000 --- a/pelican/tests/test_contents.py +++ /dev/null @@ -1,1103 +0,0 @@ -import datetime -import locale -import logging -import os.path -from posixpath import join as posix_join -from sys import platform - -from jinja2.utils import generate_lorem_ipsum - -from pelican.contents import Article, Author, Category, Page, Static -from pelican.plugins.signals import content_object_init -from pelican.settings import DEFAULT_CONFIG -from pelican.tests.support import LoggedTestCase, get_context, get_settings, unittest -from pelican.utils import path_to_url, posixize_path, truncate_html_words - -# generate one paragraph, enclosed with

    -TEST_CONTENT = str(generate_lorem_ipsum(n=1)) -TEST_SUMMARY = generate_lorem_ipsum(n=1, html=False) - - -class TestBase(LoggedTestCase): - def setUp(self): - super().setUp() - self.old_locale = locale.setlocale(locale.LC_ALL) - locale.setlocale(locale.LC_ALL, "C") - self.page_kwargs = { - "content": TEST_CONTENT, - "context": { - "localsiteurl": "", - "generated_content": {}, - "static_content": {}, - "static_links": set(), - }, - "metadata": { - "summary": TEST_SUMMARY, - "title": "foo bar", - "author": Author("Blogger", DEFAULT_CONFIG), - }, - "source_path": "/path/to/file/foo.ext", - } - self._disable_limit_filter() - - def tearDown(self): - locale.setlocale(locale.LC_ALL, self.old_locale) - self._enable_limit_filter() - - def _disable_limit_filter(self): - from pelican.contents import logger - - logger.disable_filter() - - def _enable_limit_filter(self): - from pelican.contents import logger - - logger.enable_filter() - - def _copy_page_kwargs(self): - # make a deep copy of page_kwargs - page_kwargs = {key: self.page_kwargs[key] for key in self.page_kwargs} - for key in page_kwargs: - if not isinstance(page_kwargs[key], dict): - break - page_kwargs[key] = { - subkey: page_kwargs[key][subkey] for subkey in page_kwargs[key] - } - - return page_kwargs - - -class TestPage(TestBase): - def test_use_args(self): - # Creating a page with arguments passed to the constructor should use - # them to initialise object's attributes. - metadata = { - "foo": "bar", - "foobar": "baz", - "title": "foobar", - } - page = Page(TEST_CONTENT, metadata=metadata, context={"localsiteurl": ""}) - for key, value in metadata.items(): - self.assertTrue(hasattr(page, key)) - self.assertEqual(value, getattr(page, key)) - self.assertEqual(page.content, TEST_CONTENT) - - def test_mandatory_properties(self): - # If the title is not set, must throw an exception. - page = Page("content") - self.assertFalse(page._has_valid_mandatory_properties()) - self.assertLogCountEqual( - count=1, - msg="Skipping .*: could not find information about 'title'", - level=logging.ERROR, - ) - page = Page("content", metadata={"title": "foobar"}) - self.assertTrue(page._has_valid_mandatory_properties()) - - def test_summary_from_metadata(self): - # If a :summary: metadata is given, it should be used - page = Page(**self.page_kwargs) - self.assertEqual(page.summary, TEST_SUMMARY) - - def test_summary_max_length(self): - # If a :SUMMARY_MAX_LENGTH: is set, and there is no other summary, - # generated summary should not exceed the given length. - page_kwargs = self._copy_page_kwargs() - settings = get_settings() - page_kwargs["settings"] = settings - del page_kwargs["metadata"]["summary"] - settings["SUMMARY_MAX_LENGTH"] = None - page = Page(**page_kwargs) - self.assertEqual(page.summary, TEST_CONTENT) - settings["SUMMARY_MAX_LENGTH"] = 10 - page = Page(**page_kwargs) - self.assertEqual(page.summary, truncate_html_words(TEST_CONTENT, 10)) - settings["SUMMARY_MAX_LENGTH"] = 0 - page = Page(**page_kwargs) - self.assertEqual(page.summary, "") - - def test_summary_paragraph(self): - # If SUMMARY_MAX_PARAGRAPHS is set, the generated summary should - # not exceed the given paragraph count. - page_kwargs = self._copy_page_kwargs() - settings = get_settings() - page_kwargs["settings"] = settings - del page_kwargs["metadata"]["summary"] - settings["SUMMARY_MAX_PARAGRAPHS"] = 1 - settings["SUMMARY_MAX_LENGTH"] = None - page = Page(**page_kwargs) - self.assertEqual(page.summary, TEST_CONTENT) - - def test_summary_paragraph_max_length(self): - # If both SUMMARY_MAX_PARAGRAPHS and SUMMARY_MAX_LENGTH are set, - # the generated summary should not exceed the given paragraph count and - # not exceed the given length. - page_kwargs = self._copy_page_kwargs() - settings = get_settings() - page_kwargs["settings"] = settings - del page_kwargs["metadata"]["summary"] - settings["SUMMARY_MAX_PARAGRAPHS"] = 1 - settings["SUMMARY_MAX_LENGTH"] = 10 - page = Page(**page_kwargs) - self.assertEqual(page.summary, truncate_html_words(TEST_CONTENT, 10)) - - def test_summary_end_suffix(self): - # If a :SUMMARY_END_SUFFIX: is set, and there is no other summary, - # generated summary should contain the specified marker at the end. - page_kwargs = self._copy_page_kwargs() - settings = get_settings() - page_kwargs["settings"] = settings - del page_kwargs["metadata"]["summary"] - settings["SUMMARY_END_SUFFIX"] = "test_marker" - settings["SUMMARY_MAX_LENGTH"] = 10 - page = Page(**page_kwargs) - self.assertEqual( - page.summary, truncate_html_words(TEST_CONTENT, 10, "test_marker") - ) - self.assertIn("test_marker", page.summary) - - def test_summary_get_summary_warning(self): - """calling ._get_summary() should issue a warning""" - page_kwargs = self._copy_page_kwargs() - page = Page(**page_kwargs) - self.assertEqual(page.summary, TEST_SUMMARY) - self.assertEqual(page._get_summary(), TEST_SUMMARY) - self.assertLogCountEqual( - count=1, - msg=r"_get_summary\(\) has been deprecated since 3\.6\.4\. " - "Use the summary decorator instead", - level=logging.WARNING, - ) - - def test_slug(self): - page_kwargs = self._copy_page_kwargs() - settings = get_settings() - page_kwargs["settings"] = settings - settings["SLUGIFY_SOURCE"] = "title" - page = Page(**page_kwargs) - self.assertEqual(page.slug, "foo-bar") - settings["SLUGIFY_SOURCE"] = "basename" - page = Page(**page_kwargs) - self.assertEqual(page.slug, "foo") - - # test slug from title with unicode and case - - inputs = ( - # (title, expected, preserve_case, use_unicode) - ("指導書", "zhi-dao-shu", False, False), - ("指導書", "Zhi-Dao-Shu", True, False), - ("指導書", "指導書", False, True), - ("指導書", "指導書", True, True), - ("Çığ", "cig", False, False), - ("Çığ", "Cig", True, False), - ("Çığ", "çığ", False, True), - ("Çığ", "Çığ", True, True), - ) - - settings = get_settings() - page_kwargs = self._copy_page_kwargs() - page_kwargs["settings"] = settings - - for title, expected, preserve_case, use_unicode in inputs: - settings["SLUGIFY_PRESERVE_CASE"] = preserve_case - settings["SLUGIFY_USE_UNICODE"] = use_unicode - page_kwargs["metadata"]["title"] = title - page = Page(**page_kwargs) - self.assertEqual(page.slug, expected, (title, preserve_case, use_unicode)) - - def test_defaultlang(self): - # If no lang is given, default to the default one. - page = Page(**self.page_kwargs) - self.assertEqual(page.lang, DEFAULT_CONFIG["DEFAULT_LANG"]) - - # it is possible to specify the lang in the metadata infos - self.page_kwargs["metadata"].update( - { - "lang": "fr", - } - ) - page = Page(**self.page_kwargs) - self.assertEqual(page.lang, "fr") - - def test_save_as(self): - # If a lang is not the default lang, save_as should be set - # accordingly. - - # if a title is defined, save_as should be set - page = Page(**self.page_kwargs) - self.assertEqual(page.save_as, "pages/foo-bar.html") - - # if a language is defined, save_as should include it accordingly - self.page_kwargs["metadata"].update( - { - "lang": "fr", - } - ) - page = Page(**self.page_kwargs) - self.assertEqual(page.save_as, "pages/foo-bar-fr.html") - - def test_relative_source_path(self): - # 'relative_source_path' should be the relative path - # from 'PATH' to 'source_path' - page_kwargs = self._copy_page_kwargs() - - # If 'source_path' is None, 'relative_source_path' should - # also return None - page_kwargs["source_path"] = None - page = Page(**page_kwargs) - self.assertIsNone(page.relative_source_path) - - page_kwargs = self._copy_page_kwargs() - settings = get_settings() - full_path = page_kwargs["source_path"] - - settings["PATH"] = os.path.dirname(full_path) - page_kwargs["settings"] = settings - page = Page(**page_kwargs) - - # if 'source_path' is set, 'relative_source_path' should - # return the relative path from 'PATH' to 'source_path' - self.assertEqual( - page.relative_source_path, - os.path.relpath(full_path, os.path.dirname(full_path)), - ) - - def test_metadata_url_format(self): - # Arbitrary metadata should be passed through url_format() - page = Page(**self.page_kwargs) - self.assertIn("summary", page.url_format.keys()) - page.metadata["directory"] = "test-dir" - page.settings = get_settings(PAGE_SAVE_AS="{directory}/{slug}") - self.assertEqual(page.save_as, "test-dir/foo-bar") - - def test_datetime(self): - # If DATETIME is set to a tuple, it should be used to override LOCALE - dt = datetime.datetime(2015, 9, 13) - - page_kwargs = self._copy_page_kwargs() - - # set its date to dt - page_kwargs["metadata"]["date"] = dt - page = Page(**page_kwargs) - - # page.locale_date is a unicode string in both python2 and python3 - dt_date = dt.strftime(DEFAULT_CONFIG["DEFAULT_DATE_FORMAT"]) - - self.assertEqual(page.locale_date, dt_date) - page_kwargs["settings"] = get_settings() - - # I doubt this can work on all platforms ... - if platform == "win32": - locale = "jpn" - else: - locale = "ja_JP.utf8" - page_kwargs["settings"]["DATE_FORMATS"] = {"jp": (locale, "%Y-%m-%d(%a)")} - page_kwargs["metadata"]["lang"] = "jp" - - import locale as locale_module - - try: - page = Page(**page_kwargs) - self.assertEqual(page.locale_date, "2015-09-13(\u65e5)") - except locale_module.Error: - # The constructor of ``Page`` will try to set the locale to - # ``ja_JP.utf8``. But this attempt will failed when there is no - # such locale in the system. You can see which locales there are - # in your system with ``locale -a`` command. - # - # Until we find some other method to test this functionality, we - # will simply skip this test. - unittest.skip(f"There is no locale {locale} in this system.") - - def test_template(self): - # Pages default to page, metadata overwrites - default_page = Page(**self.page_kwargs) - self.assertEqual("page", default_page.template) - page_kwargs = self._copy_page_kwargs() - page_kwargs["metadata"]["template"] = "custom" - custom_page = Page(**page_kwargs) - self.assertEqual("custom", custom_page.template) - - def test_signal(self): - def receiver_test_function(sender): - receiver_test_function.has_been_called = True - - receiver_test_function.has_been_called = False - - content_object_init.connect(receiver_test_function) - self.assertIn(receiver_test_function, content_object_init.receivers_for(Page)) - - self.assertFalse(receiver_test_function.has_been_called) - Page(**self.page_kwargs) - self.assertTrue(receiver_test_function.has_been_called) - - def test_get_content(self): - # Test that the content is updated with the relative links to - # filenames, tags and categories. - settings = get_settings() - args = self.page_kwargs.copy() - args["settings"] = settings - - # Tag - args["content"] = 'A simple test, with a link' - page = Page(**args) - content = page.get_content("http://notmyidea.org") - self.assertEqual( - content, - ( - "A simple test, with a " - 'link' - ), - ) - - # Category - args["content"] = 'A simple test, with a link' - page = Page(**args) - content = page.get_content("http://notmyidea.org") - self.assertEqual( - content, - ( - "A simple test, with a " - 'link' - ), - ) - - def test_intrasite_link(self): - cls_name = "_DummyArticle" - article = type(cls_name, (object,), {"url": "article.html"}) - - args = self.page_kwargs.copy() - args["settings"] = get_settings() - args["source_path"] = "content" - args["context"]["generated_content"] = {"article.rst": article} - - # Classic intrasite link via filename - args["content"] = ( - 'A simple test, with a link' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual( - content, - "A simple test, with a " - 'link', - ) - - # fragment - args["content"] = ( - "A simple test, with a " - 'link' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual( - content, - "A simple test, with a " - 'link', - ) - - # query - args["content"] = ( - "A simple test, with a " - 'link' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual( - content, - "A simple test, with a " - 'link', - ) - - # combination - args["content"] = ( - "A simple test, with a " - 'link' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual( - content, - "A simple test, with a " - 'link', - ) - - # also test for summary in metadata - parsed = ( - 'A simple summary test, with a link' - ) - linked = ( - "A simple summary test, with a " - 'link' - ) - args["settings"]["FORMATTED_FIELDS"] = ["summary", "custom"] - args["metadata"]["summary"] = parsed - args["metadata"]["custom"] = parsed - args["context"]["localsiteurl"] = "http://notmyidea.org" - p = Page(**args) - # This is called implicitly from all generators and Pelican.run() once - # all files are processed. Here we process just one page so it needs - # to be called explicitly. - p.refresh_metadata_intersite_links() - self.assertEqual(p.summary, linked) - self.assertEqual(p.custom, linked) - - def test_intrasite_link_more(self): - cls_name = "_DummyAsset" - - args = self.page_kwargs.copy() - args["settings"] = get_settings() - args["source_path"] = "content" - args["context"]["static_content"] = { - "images/poster.jpg": type( - cls_name, (object,), {"url": "images/poster.jpg"} - ), - "assets/video.mp4": type(cls_name, (object,), {"url": "assets/video.mp4"}), - "images/graph.svg": type(cls_name, (object,), {"url": "images/graph.svg"}), - } - args["context"]["generated_content"] = { - "reference.rst": type(cls_name, (object,), {"url": "reference.html"}), - } - - # video.poster - args["content"] = ( - "There is a video with poster " - '" - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual( - content, - "There is a video with poster " - '", - ) - - # object.data - args["content"] = ( - "There is a svg object " - '' - "" - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual( - content, - "There is a svg object " - '' - "", - ) - - # blockquote.cite - args["content"] = ( - "There is a blockquote with cite attribute " - '

    blah blah
    ' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual( - content, - "There is a blockquote with cite attribute " - '
    ' - "blah blah" - "
    ", - ) - - def test_intrasite_link_absolute(self): - """Test that absolute URLs are merged properly.""" - - args = self.page_kwargs.copy() - args["settings"] = get_settings( - STATIC_URL="http://static.cool.site/{path}", - ARTICLE_URL="http://blog.cool.site/{slug}.html", - ) - args["source_path"] = "content" - args["context"]["static_content"] = { - "images/poster.jpg": Static( - "", settings=args["settings"], source_path="images/poster.jpg" - ), - } - args["context"]["generated_content"] = { - "article.rst": Article( - "", - settings=args["settings"], - metadata={"slug": "article", "title": "Article"}, - ) - } - - # Article link will go to blog - args["content"] = 'Article' - content = Page(**args).get_content("http://cool.site") - self.assertEqual( - content, 'Article' - ) - - # Page link will go to the main site - args["content"] = 'Index' - content = Page(**args).get_content("http://cool.site") - self.assertEqual(content, 'Index') - - # Image link will go to static - args["content"] = '' - content = Page(**args).get_content("http://cool.site") - self.assertEqual( - content, '' - ) - - # Image link will go to static - args["content"] = '' - content = Page(**args).get_content("http://cool.site") - self.assertEqual( - content, '' - ) - - def test_intrasite_link_escape(self): - article = type("_DummyArticle", (object,), {"url": "article-spaces.html"}) - asset = type("_DummyAsset", (object,), {"url": "name@example.com"}) - - args = self.page_kwargs.copy() - args["settings"] = get_settings() - args["source_path"] = "content" - args["context"]["generated_content"] = {"article spaces.rst": article} - args["context"]["static_content"] = {"name@example.com": asset} - - expected_output = ( - "A simple test with a " - 'link ' - 'file' - ) - - # not escaped - args["content"] = ( - "A simple test with a " - 'link ' - 'file' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual(content, expected_output) - - # html escaped - args["content"] = ( - "A simple test with a " - 'link ' - 'file' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual(content, expected_output) - - # url escaped - args["content"] = ( - "A simple test with a " - 'link ' - 'file' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual(content, expected_output) - - # html and url escaped - args["content"] = ( - "A simple test with a " - 'link ' - 'file' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual(content, expected_output) - - def test_intrasite_link_markdown_spaces(self): - cls_name = "_DummyArticle" - article = type(cls_name, (object,), {"url": "article-spaces.html"}) - - args = self.page_kwargs.copy() - args["settings"] = get_settings() - args["source_path"] = "content" - args["context"]["generated_content"] = {"article spaces.rst": article} - - # An intrasite link via filename with %20 as a space - args["content"] = ( - 'A simple test, with a link' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual( - content, - "A simple test, with a " - 'link', - ) - - def test_intrasite_link_source_and_generated(self): - """Test linking both to the source and the generated article""" - cls_name = "_DummyAsset" - - args = self.page_kwargs.copy() - args["settings"] = get_settings() - args["source_path"] = "content" - args["context"]["generated_content"] = { - "article.rst": type(cls_name, (object,), {"url": "article.html"}) - } - args["context"]["static_content"] = { - "article.rst": type(cls_name, (object,), {"url": "article.rst"}) - } - - args["content"] = ( - "A simple test, with a link to an" - 'article and its' - 'source' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual( - content, - "A simple test, with a link to an" - 'article and its' - 'source', - ) - - def test_intrasite_link_to_static_content_with_filename(self): - """Test linking to a static resource with deprecated {filename}""" - cls_name = "_DummyAsset" - - args = self.page_kwargs.copy() - args["settings"] = get_settings() - args["source_path"] = "content" - args["context"]["static_content"] = { - "poster.jpg": type(cls_name, (object,), {"url": "images/poster.jpg"}) - } - - args["content"] = ( - "A simple test, with a link to a" - 'poster' - ) - content = Page(**args).get_content("http://notmyidea.org") - self.assertEqual( - content, - "A simple test, with a link to a" - 'poster', - ) - - def test_multiple_authors(self): - """Test article with multiple authors.""" - args = self.page_kwargs.copy() - content = Page(**args) - assert content.authors == [content.author] - args["metadata"].pop("author") - args["metadata"]["authors"] = [ - Author("First Author", DEFAULT_CONFIG), - Author("Second Author", DEFAULT_CONFIG), - ] - content = Page(**args) - assert content.authors - assert content.author == content.authors[0] - - -class TestArticle(TestBase): - def test_template(self): - # Articles default to article, metadata overwrites - default_article = Article(**self.page_kwargs) - self.assertEqual("article", default_article.template) - article_kwargs = self._copy_page_kwargs() - article_kwargs["metadata"]["template"] = "custom" - custom_article = Article(**article_kwargs) - self.assertEqual("custom", custom_article.template) - - def test_slugify_category_author(self): - settings = get_settings() - settings["SLUG_REGEX_SUBSTITUTIONS"] = [ - (r"C#", "csharp"), - (r"[^\w\s-]", ""), - (r"(?u)\A\s*", ""), - (r"(?u)\s*\Z", ""), - (r"[-\s]+", "-"), - ] - settings["ARTICLE_URL"] = "{author}/{category}/{slug}/" - settings["ARTICLE_SAVE_AS"] = "{author}/{category}/{slug}/index.html" - article_kwargs = self._copy_page_kwargs() - article_kwargs["metadata"]["author"] = Author("O'Brien", settings) - article_kwargs["metadata"]["category"] = Category("C# & stuff", settings) - article_kwargs["metadata"]["title"] = "fnord" - article_kwargs["settings"] = settings - article = Article(**article_kwargs) - self.assertEqual(article.url, "obrien/csharp-stuff/fnord/") - self.assertEqual(article.save_as, "obrien/csharp-stuff/fnord/index.html") - - def test_slugify_with_author_substitutions(self): - settings = get_settings() - settings["AUTHOR_REGEX_SUBSTITUTIONS"] = [ - ("Alexander Todorov", "atodorov"), - ("Krasimir Tsonev", "krasimir"), - (r"[^\w\s-]", ""), - (r"(?u)\A\s*", ""), - (r"(?u)\s*\Z", ""), - (r"[-\s]+", "-"), - ] - settings["ARTICLE_URL"] = "blog/{author}/{slug}/" - settings["ARTICLE_SAVE_AS"] = "blog/{author}/{slug}/index.html" - article_kwargs = self._copy_page_kwargs() - article_kwargs["metadata"]["author"] = Author("Alexander Todorov", settings) - article_kwargs["metadata"]["title"] = "fnord" - article_kwargs["settings"] = settings - article = Article(**article_kwargs) - self.assertEqual(article.url, "blog/atodorov/fnord/") - self.assertEqual(article.save_as, "blog/atodorov/fnord/index.html") - - def test_slugify_category_with_dots(self): - settings = get_settings() - settings["CATEGORY_REGEX_SUBSTITUTIONS"] = [ - ("Fedora QA", "fedora.qa"), - ] - settings["ARTICLE_URL"] = "{category}/{slug}/" - article_kwargs = self._copy_page_kwargs() - article_kwargs["metadata"]["category"] = Category("Fedora QA", settings) - article_kwargs["metadata"]["title"] = "This Week in Fedora QA" - article_kwargs["settings"] = settings - article = Article(**article_kwargs) - self.assertEqual(article.url, "fedora.qa/this-week-in-fedora-qa/") - - def test_valid_save_as_detects_breakout(self): - settings = get_settings() - article_kwargs = self._copy_page_kwargs() - article_kwargs["metadata"]["slug"] = "../foo" - article_kwargs["settings"] = settings - article = Article(**article_kwargs) - self.assertFalse(article._has_valid_save_as()) - - def test_valid_save_as_detects_breakout_to_root(self): - settings = get_settings() - article_kwargs = self._copy_page_kwargs() - article_kwargs["metadata"]["slug"] = "/foo" - article_kwargs["settings"] = settings - article = Article(**article_kwargs) - self.assertFalse(article._has_valid_save_as()) - - def test_valid_save_as_passes_valid(self): - settings = get_settings() - article_kwargs = self._copy_page_kwargs() - article_kwargs["metadata"]["slug"] = "foo" - article_kwargs["settings"] = settings - article = Article(**article_kwargs) - self.assertTrue(article._has_valid_save_as()) - - -class TestStatic(LoggedTestCase): - def setUp(self): - super().setUp() - self.settings = get_settings( - STATIC_SAVE_AS="{path}", - STATIC_URL="{path}", - PAGE_SAVE_AS=os.path.join("outpages", "{slug}.html"), - PAGE_URL="outpages/{slug}.html", - ) - self.context = get_context(self.settings) - - self.static = Static( - content=None, - metadata={}, - settings=self.settings, - source_path=posix_join("dir", "foo.jpg"), - context=self.context, - ) - - self.context["static_content"][self.static.source_path] = self.static - - def tearDown(self): - pass - - def test_attach_to_same_dir(self): - """attach_to() overrides a static file's save_as and url.""" - page = Page( - content="fake page", - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "fakepage.md"), - ) - self.static.attach_to(page) - - expected_save_as = os.path.join("outpages", "foo.jpg") - self.assertEqual(self.static.save_as, expected_save_as) - self.assertEqual(self.static.url, path_to_url(expected_save_as)) - - def test_attach_to_parent_dir(self): - """attach_to() preserves dirs inside the linking document dir.""" - page = Page( - content="fake page", - metadata={"title": "fakepage"}, - settings=self.settings, - source_path="fakepage.md", - ) - self.static.attach_to(page) - - expected_save_as = os.path.join("outpages", "dir", "foo.jpg") - self.assertEqual(self.static.save_as, expected_save_as) - self.assertEqual(self.static.url, path_to_url(expected_save_as)) - - def test_attach_to_other_dir(self): - """attach_to() ignores dirs outside the linking document dir.""" - page = Page( - content="fake page", - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "otherdir", "fakepage.md"), - ) - self.static.attach_to(page) - - expected_save_as = os.path.join("outpages", "foo.jpg") - self.assertEqual(self.static.save_as, expected_save_as) - self.assertEqual(self.static.url, path_to_url(expected_save_as)) - - def test_attach_to_ignores_subsequent_calls(self): - """attach_to() does nothing when called a second time.""" - page = Page( - content="fake page", - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "fakepage.md"), - ) - - self.static.attach_to(page) - - otherdir_settings = self.settings.copy() - otherdir_settings.update( - { - "PAGE_SAVE_AS": os.path.join("otherpages", "{slug}.html"), - "PAGE_URL": "otherpages/{slug}.html", - } - ) - otherdir_page = Page( - content="other page", - metadata={"title": "otherpage"}, - settings=otherdir_settings, - source_path=os.path.join("dir", "otherpage.md"), - ) - - self.static.attach_to(otherdir_page) - - otherdir_save_as = os.path.join("otherpages", "foo.jpg") - self.assertNotEqual(self.static.save_as, otherdir_save_as) - self.assertNotEqual(self.static.url, path_to_url(otherdir_save_as)) - - def test_attach_to_does_nothing_after_save_as_referenced(self): - """attach_to() does nothing if the save_as was already referenced. - (For example, by a {static} link an a document processed earlier.) - """ - original_save_as = self.static.save_as - - page = Page( - content="fake page", - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "fakepage.md"), - ) - self.static.attach_to(page) - - self.assertEqual(self.static.save_as, original_save_as) - self.assertEqual(self.static.url, path_to_url(original_save_as)) - - def test_attach_to_does_nothing_after_url_referenced(self): - """attach_to() does nothing if the url was already referenced. - (For example, by a {static} link an a document processed earlier.) - """ - original_url = self.static.url - - page = Page( - content="fake page", - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "fakepage.md"), - ) - self.static.attach_to(page) - - self.assertEqual(self.static.save_as, self.static.source_path) - self.assertEqual(self.static.url, original_url) - - def test_attach_to_does_not_override_an_override(self): - """attach_to() does not override paths that were overridden elsewhere. - (For example, by the user with EXTRA_PATH_METADATA) - """ - customstatic = Static( - content=None, - metadata={"save_as": "customfoo.jpg", "url": "customfoo.jpg"}, - settings=self.settings, - source_path=os.path.join("dir", "foo.jpg"), - context=self.settings.copy(), - ) - - page = Page( - content="fake page", - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "fakepage.md"), - ) - - customstatic.attach_to(page) - - self.assertEqual(customstatic.save_as, "customfoo.jpg") - self.assertEqual(customstatic.url, "customfoo.jpg") - - def test_attach_link_syntax(self): - """{attach} link syntax triggers output path override & url replacement.""" - html = 'link' - page = Page( - content=html, - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "otherdir", "fakepage.md"), - context=self.context, - ) - content = page.get_content("") - - self.assertNotEqual( - content, html, "{attach} link syntax did not trigger URL replacement." - ) - - expected_save_as = os.path.join("outpages", "foo.jpg") - self.assertEqual(self.static.save_as, expected_save_as) - self.assertEqual(self.static.url, path_to_url(expected_save_as)) - - def test_tag_link_syntax(self): - "{tag} link syntax triggers url replacement." - - html = 'link' - page = Page( - content=html, - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "otherdir", "fakepage.md"), - context=self.context, - ) - content = page.get_content("") - - self.assertNotEqual(content, html) - - def test_category_link_syntax(self): - "{category} link syntax triggers url replacement." - - html = 'link' - page = Page( - content=html, - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "otherdir", "fakepage.md"), - context=self.context, - ) - content = page.get_content("") - - self.assertNotEqual(content, html) - - def test_author_link_syntax(self): - "{author} link syntax triggers url replacement." - - html = 'link' - page = Page( - content=html, - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "otherdir", "fakepage.md"), - context=self.context, - ) - content = page.get_content("") - - self.assertNotEqual(content, html) - - def test_index_link_syntax(self): - "{index} link syntax triggers url replacement." - - html = 'link' - page = Page( - content=html, - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "otherdir", "fakepage.md"), - context=self.context, - ) - content = page.get_content("") - - self.assertNotEqual(content, html) - - expected_html = ( - 'link' - ) - self.assertEqual(content, expected_html) - - def test_unknown_link_syntax(self): - "{unknown} link syntax should trigger warning." - - html = 'link' - page = Page( - content=html, - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "otherdir", "fakepage.md"), - context=self.context, - ) - content = page.get_content("") - - self.assertEqual(content, html) - self.assertLogCountEqual( - count=1, - msg="Replacement Indicator 'unknown' not recognized, " - "skipping replacement", - level=logging.WARNING, - ) - - def test_link_to_unknown_file(self): - "{filename} link to unknown file should trigger warning." - - html = 'link' - page = Page( - content=html, - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "otherdir", "fakepage.md"), - context=self.context, - ) - content = page.get_content("") - - self.assertEqual(content, html) - self.assertLogCountEqual( - count=1, - msg="Unable to find 'foo', skipping url replacement.", - level=logging.WARNING, - ) - - def test_index_link_syntax_with_spaces(self): - """{index} link syntax triggers url replacement - with spaces around the equal sign.""" - - html = 'link' - page = Page( - content=html, - metadata={"title": "fakepage"}, - settings=self.settings, - source_path=os.path.join("dir", "otherdir", "fakepage.md"), - context=self.context, - ) - content = page.get_content("") - - self.assertNotEqual(content, html) - - expected_html = ( - 'link' - ) - self.assertEqual(content, expected_html) - - def test_not_save_as_draft(self): - """Static.save_as is not affected by draft status.""" - - static = Static( - content=None, - metadata={ - "status": "draft", - }, - settings=self.settings, - source_path=os.path.join("dir", "foo.jpg"), - context=self.settings.copy(), - ) - - expected_save_as = posixize_path(os.path.join("dir", "foo.jpg")) - self.assertEqual(static.status, "draft") - self.assertEqual(static.save_as, expected_save_as) - self.assertEqual(static.url, path_to_url(expected_save_as)) diff --git a/pelican/tests/test_generators.py b/pelican/tests/test_generators.py deleted file mode 100644 index e739e180..00000000 --- a/pelican/tests/test_generators.py +++ /dev/null @@ -1,1652 +0,0 @@ -import os -import sys -from shutil import copy, rmtree -from tempfile import mkdtemp -from unittest.mock import MagicMock - -from pelican.generators import ( - ArticlesGenerator, - Generator, - PagesGenerator, - PelicanTemplateNotFound, - StaticGenerator, - TemplatePagesGenerator, -) -from pelican.tests.support import ( - TestCaseWithCLocale, - can_symlink, - get_context, - get_settings, - unittest, -) -from pelican.writers import Writer - -CUR_DIR = os.path.dirname(__file__) -CONTENT_DIR = os.path.join(CUR_DIR, "content") - - -class TestGenerator(TestCaseWithCLocale): - def setUp(self): - super().setUp() - self.settings = get_settings() - self.settings["READERS"] = {"asc": None} - self.generator = Generator( - self.settings.copy(), self.settings, CUR_DIR, self.settings["THEME"], None - ) - - def test_include_path(self): - self.settings["IGNORE_FILES"] = {"ignored1.rst", "ignored2.rst"} - - filename = os.path.join(CUR_DIR, "content", "article.rst") - include_path = self.generator._include_path - self.assertTrue(include_path(filename)) - self.assertTrue(include_path(filename, extensions=("rst",))) - self.assertFalse(include_path(filename, extensions=("md",))) - - ignored_file = os.path.join(CUR_DIR, "content", "ignored1.rst") - self.assertFalse(include_path(ignored_file)) - - def test_get_files_exclude(self): - """Test that Generator.get_files() properly excludes directories.""" - # We use our own Generator so we can give it our own content path - generator = Generator( - context=self.settings.copy(), - settings=self.settings, - path=os.path.join(CUR_DIR, "nested_content"), - theme=self.settings["THEME"], - output_path=None, - ) - - filepaths = generator.get_files(paths=["maindir"]) - found_files = {os.path.basename(f) for f in filepaths} - expected_files = {"maindir.md", "subdir.md"} - self.assertFalse( - expected_files - found_files, "get_files() failed to find one or more files" - ) - - # Test string as `paths` argument rather than list - filepaths = generator.get_files(paths="maindir") - found_files = {os.path.basename(f) for f in filepaths} - expected_files = {"maindir.md", "subdir.md"} - self.assertFalse( - expected_files - found_files, "get_files() failed to find one or more files" - ) - - filepaths = generator.get_files(paths=[""], exclude=["maindir"]) - found_files = {os.path.basename(f) for f in filepaths} - self.assertNotIn( - "maindir.md", - found_files, - "get_files() failed to exclude a top-level directory", - ) - self.assertNotIn( - "subdir.md", - found_files, - "get_files() failed to exclude a subdir of an excluded directory", - ) - - filepaths = generator.get_files( - paths=[""], exclude=[os.path.join("maindir", "subdir")] - ) - found_files = {os.path.basename(f) for f in filepaths} - self.assertNotIn( - "subdir.md", found_files, "get_files() failed to exclude a subdirectory" - ) - - filepaths = generator.get_files(paths=[""], exclude=["subdir"]) - found_files = {os.path.basename(f) for f in filepaths} - self.assertIn( - "subdir.md", - found_files, - "get_files() excluded a subdirectory by name, ignoring its path", - ) - - def test_custom_jinja_environment(self): - """ - Test that setting the JINJA_ENVIRONMENT - properly gets set from the settings config - """ - settings = get_settings() - comment_start_string = "abc" - comment_end_string = "/abc" - settings["JINJA_ENVIRONMENT"] = { - "comment_start_string": comment_start_string, - "comment_end_string": comment_end_string, - } - generator = Generator( - settings.copy(), settings, CUR_DIR, settings["THEME"], None - ) - self.assertEqual(comment_start_string, generator.env.comment_start_string) - self.assertEqual(comment_end_string, generator.env.comment_end_string) - - def test_theme_overrides(self): - """ - Test that the THEME_TEMPLATES_OVERRIDES configuration setting is - utilized correctly in the Generator. - """ - override_dirs = ( - os.path.join(CUR_DIR, "theme_overrides", "level1"), - os.path.join(CUR_DIR, "theme_overrides", "level2"), - ) - self.settings["THEME_TEMPLATES_OVERRIDES"] = override_dirs - generator = Generator( - context=self.settings.copy(), - settings=self.settings, - path=CUR_DIR, - theme=self.settings["THEME"], - output_path=None, - ) - - filename = generator.get_template("article").filename - self.assertEqual(override_dirs[0], os.path.dirname(filename)) - self.assertEqual("article.html", os.path.basename(filename)) - - filename = generator.get_template("authors").filename - self.assertEqual(override_dirs[1], os.path.dirname(filename)) - self.assertEqual("authors.html", os.path.basename(filename)) - - filename = generator.get_template("taglist").filename - self.assertEqual( - os.path.join(self.settings["THEME"], "templates"), os.path.dirname(filename) - ) - self.assertNotIn(os.path.dirname(filename), override_dirs) - self.assertEqual("taglist.html", os.path.basename(filename)) - - def test_simple_prefix(self): - """ - Test `!simple` theme prefix. - """ - filename = self.generator.get_template("!simple/authors").filename - expected_path = os.path.join( - os.path.dirname(CUR_DIR), "themes", "simple", "templates" - ) - self.assertEqual(expected_path, os.path.dirname(filename)) - self.assertEqual("authors.html", os.path.basename(filename)) - - def test_theme_prefix(self): - """ - Test `!theme` theme prefix. - """ - filename = self.generator.get_template("!theme/authors").filename - expected_path = os.path.join( - os.path.dirname(CUR_DIR), "themes", "notmyidea", "templates" - ) - self.assertEqual(expected_path, os.path.dirname(filename)) - self.assertEqual("authors.html", os.path.basename(filename)) - - def test_bad_prefix(self): - """ - Test unknown/bad theme prefix throws exception. - """ - self.assertRaises( - PelicanTemplateNotFound, self.generator.get_template, "!UNKNOWN/authors" - ) - - -class TestArticlesGenerator(unittest.TestCase): - @classmethod - def setUpClass(cls): - settings = get_settings() - settings["DEFAULT_CATEGORY"] = "Default" - settings["DEFAULT_DATE"] = (1970, 1, 1) - settings["READERS"] = {"asc": None} - settings["CACHE_CONTENT"] = False - context = get_context(settings) - - cls.generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - cls.generator.generate_context() - cls.articles = cls.distill_articles(cls.generator.articles) - cls.drafts = cls.distill_articles(cls.generator.drafts) - cls.hidden_articles = cls.distill_articles(cls.generator.hidden_articles) - - def setUp(self): - self.temp_cache = mkdtemp(prefix="pelican_cache.") - - def tearDown(self): - rmtree(self.temp_cache) - - @staticmethod - def distill_articles(articles): - return [ - [article.title, article.status, article.category.name, article.template] - for article in articles - ] - - def test_generate_feeds(self): - settings = get_settings() - settings["CACHE_PATH"] = self.temp_cache - generator = ArticlesGenerator( - context=settings, - settings=settings, - path=None, - theme=settings["THEME"], - output_path=None, - ) - writer = MagicMock() - generator.generate_feeds(writer) - writer.write_feed.assert_called_with( - [], settings, "feeds/all.atom.xml", "feeds/all.atom.xml" - ) - - generator = ArticlesGenerator( - context=settings, - settings=get_settings(FEED_ALL_ATOM=None), - path=None, - theme=settings["THEME"], - output_path=None, - ) - writer = MagicMock() - generator.generate_feeds(writer) - self.assertFalse(writer.write_feed.called) - - def test_generate_feeds_override_url(self): - settings = get_settings() - settings["CACHE_PATH"] = self.temp_cache - settings["FEED_ALL_ATOM_URL"] = "feeds/atom/all/" - generator = ArticlesGenerator( - context=settings, - settings=settings, - path=None, - theme=settings["THEME"], - output_path=None, - ) - writer = MagicMock() - generator.generate_feeds(writer) - writer.write_feed.assert_called_with( - [], settings, "feeds/all.atom.xml", "feeds/atom/all/" - ) - - def test_generate_context(self): - articles_expected = [ - ["A title", "published", "medium_posts", "article"], - ["Article title", "published", "Default", "article"], - [ - "Article with markdown and summary metadata multi", - "published", - "Default", - "article", - ], - [ - "Article with markdown and nested summary metadata", - "published", - "Default", - "article", - ], - [ - "Article with markdown and summary metadata single", - "published", - "Default", - "article", - ], - [ - "Article with markdown containing footnotes", - "published", - "Default", - "article", - ], - ["Article with template", "published", "Default", "custom"], - ["Metadata tags as list!", "published", "Default", "article"], - ["Rst with filename metadata", "published", "yeah", "article"], - ["One -, two --, three --- dashes!", "published", "Default", "article"], - ["One -, two --, three --- dashes!", "published", "Default", "article"], - ["Test Markdown extensions", "published", "Default", "article"], - ["Test markdown File", "published", "test", "article"], - ["Test md File", "published", "test", "article"], - ["Test mdown File", "published", "test", "article"], - ["Test metadata duplicates", "published", "test", "article"], - ["Test mkd File", "published", "test", "article"], - ["This is a super article !", "published", "Yeah", "article"], - ["This is a super article !", "published", "Yeah", "article"], - [ - "Article with Nonconformant HTML meta tags", - "published", - "Default", - "article", - ], - ["This is a super article !", "published", "yeah", "article"], - ["This is a super article !", "published", "yeah", "article"], - ["This is a super article !", "published", "yeah", "article"], - ["This is a super article !", "published", "yeah", "article"], - ["This is a super article !", "published", "yeah", "article"], - ["This is a super article !", "published", "yeah", "article"], - ["This is a super article !", "published", "yeah", "article"], - ["This is a super article !", "published", "yeah", "article"], - ["This is a super article !", "published", "Default", "article"], - ["Article with an inline SVG", "published", "Default", "article"], - ["Article with markdown and empty tags", "published", "Default", "article"], - ["This is an article with category !", "published", "yeah", "article"], - [ - "This is an article with multiple authors!", - "published", - "Default", - "article", - ], - [ - "This is an article with multiple authors!", - "published", - "Default", - "article", - ], - [ - "This is an article with multiple authors in list format!", - "published", - "Default", - "article", - ], - [ - "This is an article with multiple authors in lastname, " - "firstname format!", - "published", - "Default", - "article", - ], - [ - "This is an article without category !", - "published", - "Default", - "article", - ], - [ - "This is an article without category !", - "published", - "TestCategory", - "article", - ], - [ - "An Article With Code Block To Test Typogrify Ignore", - "published", - "Default", - "article", - ], - [ - "マックOS X 10.8でパイソンとVirtualenvをインストールと設定", - "published", - "指導書", - "article", - ], - ] - self.assertEqual(sorted(articles_expected), sorted(self.articles)) - - def test_articles_draft(self): - draft_articles_expected = [ - ["Draft article", "draft", "Default", "article"], - ] - self.assertEqual(sorted(draft_articles_expected), sorted(self.drafts)) - - def test_articles_hidden(self): - hidden_articles_expected = [ - ["Hidden article", "hidden", "Default", "article"], - ] - self.assertEqual(sorted(hidden_articles_expected), sorted(self.hidden_articles)) - - def test_generate_categories(self): - # test for name - # categories are grouped by slug; if two categories have the same slug - # but different names they will be grouped together, the first one in - # terms of process order will define the name for that category - categories = [cat.name for cat, _ in self.generator.categories] - categories_alternatives = ( - sorted( - ["Default", "TestCategory", "medium_posts", "Yeah", "test", "指導書"] - ), - sorted( - ["Default", "TestCategory", "medium_posts", "yeah", "test", "指導書"] - ), - ) - self.assertIn(sorted(categories), categories_alternatives) - # test for slug - categories = [cat.slug for cat, _ in self.generator.categories] - categories_expected = [ - "default", - "testcategory", - "medium_posts", - "yeah", - "test", - "zhi-dao-shu", - ] - self.assertEqual(sorted(categories), sorted(categories_expected)) - - def test_do_not_use_folder_as_category(self): - settings = get_settings() - settings["DEFAULT_CATEGORY"] = "Default" - settings["DEFAULT_DATE"] = (1970, 1, 1) - settings["USE_FOLDER_AS_CATEGORY"] = False - settings["CACHE_PATH"] = self.temp_cache - settings["READERS"] = {"asc": None} - context = get_context(settings) - generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - # test for name - # categories are grouped by slug; if two categories have the same slug - # but different names they will be grouped together, the first one in - # terms of process order will define the name for that category - categories = [cat.name for cat, _ in generator.categories] - categories_alternatives = ( - sorted(["Default", "Yeah", "test", "指導書"]), - sorted(["Default", "yeah", "test", "指導書"]), - ) - self.assertIn(sorted(categories), categories_alternatives) - # test for slug - categories = [cat.slug for cat, _ in generator.categories] - categories_expected = ["default", "yeah", "test", "zhi-dao-shu"] - self.assertEqual(sorted(categories), sorted(categories_expected)) - - def test_direct_templates_save_as_url_default(self): - settings = get_settings() - settings["CACHE_PATH"] = self.temp_cache - context = get_context(settings) - generator = ArticlesGenerator( - context=context, - settings=settings, - path=None, - theme=settings["THEME"], - output_path=None, - ) - write = MagicMock() - generator.generate_direct_templates(write) - write.assert_called_with( - "archives.html", - generator.get_template("archives"), - context, - articles=generator.articles, - dates=generator.dates, - blog=True, - template_name="archives", - page_name="archives", - url="archives.html", - ) - - def test_direct_templates_save_as_url_modified(self): - settings = get_settings() - settings["DIRECT_TEMPLATES"] = ["archives"] - settings["ARCHIVES_SAVE_AS"] = "archives/index.html" - settings["ARCHIVES_URL"] = "archives/" - settings["CACHE_PATH"] = self.temp_cache - generator = ArticlesGenerator( - context=settings, - settings=settings, - path=None, - theme=settings["THEME"], - output_path=None, - ) - write = MagicMock() - generator.generate_direct_templates(write) - write.assert_called_with( - "archives/index.html", - generator.get_template("archives"), - settings, - articles=generator.articles, - dates=generator.dates, - blog=True, - template_name="archives", - page_name="archives/index", - url="archives/", - ) - - def test_direct_templates_save_as_false(self): - settings = get_settings() - settings["DIRECT_TEMPLATES"] = ["archives"] - settings["ARCHIVES_SAVE_AS"] = False - settings["CACHE_PATH"] = self.temp_cache - generator = ArticlesGenerator( - context=settings, - settings=settings, - path=None, - theme=settings["THEME"], - output_path=None, - ) - write = MagicMock() - generator.generate_direct_templates(write) - self.assertEqual(write.call_count, 0) - - def test_per_article_template(self): - """ - Custom template articles get the field but standard/unset are None - """ - custom_template = ["Article with template", "published", "Default", "custom"] - standard_template = [ - "This is a super article !", - "published", - "Yeah", - "article", - ] - self.assertIn(custom_template, self.articles) - self.assertIn(standard_template, self.articles) - - def test_period_archives_context(self): - """Test correctness of the period_archives context values.""" - - settings = get_settings() - settings["CACHE_PATH"] = self.temp_cache - - # No period archives enabled: - context = get_context(settings) - generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - period_archives = generator.context["period_archives"] - self.assertEqual(len(period_archives.items()), 0) - - # Year archives enabled: - settings["YEAR_ARCHIVE_SAVE_AS"] = "posts/{date:%Y}/index.html" - settings["YEAR_ARCHIVE_URL"] = "posts/{date:%Y}/" - context = get_context(settings) - generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - period_archives = generator.context["period_archives"] - abbreviated_archives = { - granularity: {period["period"] for period in periods} - for granularity, periods in period_archives.items() - } - self.maxDiff = None - expected = {"year": {(1970,), (2010,), (2012,), (2014,), (2017,)}} - self.assertEqual(expected, abbreviated_archives) - - # Month archives enabled: - settings["MONTH_ARCHIVE_SAVE_AS"] = "posts/{date:%Y}/{date:%b}/index.html" - settings["MONTH_ARCHIVE_URL"] = "posts/{date:%Y}/{date:%b}/" - context = get_context(settings) - generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - period_archives = generator.context["period_archives"] - abbreviated_archives = { - granularity: {period["period"] for period in periods} - for granularity, periods in period_archives.items() - } - expected = { - "year": {(1970,), (2010,), (2012,), (2014,), (2017,)}, - "month": { - (1970, "January"), - (2010, "December"), - (2012, "December"), - (2012, "November"), - (2012, "October"), - (2014, "February"), - (2017, "April"), - }, - } - self.assertEqual(expected, abbreviated_archives) - - # Day archives enabled: - settings["DAY_ARCHIVE_SAVE_AS"] = ( - "posts/{date:%Y}/{date:%b}/{date:%d}/index.html" - ) - settings["DAY_ARCHIVE_URL"] = "posts/{date:%Y}/{date:%b}/{date:%d}/" - context = get_context(settings) - generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - period_archives = generator.context["period_archives"] - abbreviated_archives = { - granularity: {period["period"] for period in periods} - for granularity, periods in period_archives.items() - } - expected = { - "year": {(1970,), (2010,), (2012,), (2014,), (2017,)}, - "month": { - (1970, "January"), - (2010, "December"), - (2012, "December"), - (2012, "November"), - (2012, "October"), - (2014, "February"), - (2017, "April"), - }, - "day": { - (1970, "January", 1), - (2010, "December", 2), - (2012, "December", 20), - (2012, "November", 29), - (2012, "October", 30), - (2012, "October", 31), - (2014, "February", 9), - (2017, "April", 21), - }, - } - self.assertEqual(expected, abbreviated_archives) - - # Further item values tests - filtered_archives = [ - p for p in period_archives["day"] if p["period"] == (2014, "February", 9) - ] - self.assertEqual(len(filtered_archives), 1) - sample_archive = filtered_archives[0] - self.assertEqual(sample_archive["period_num"], (2014, 2, 9)) - self.assertEqual(sample_archive["save_as"], "posts/2014/Feb/09/index.html") - self.assertEqual(sample_archive["url"], "posts/2014/Feb/09/") - articles = [ - d - for d in generator.articles - if d.date.year == 2014 and d.date.month == 2 and d.date.day == 9 - ] - self.assertEqual(len(sample_archive["articles"]), len(articles)) - dates = [ - d - for d in generator.dates - if d.date.year == 2014 and d.date.month == 2 and d.date.day == 9 - ] - self.assertEqual(len(sample_archive["dates"]), len(dates)) - self.assertEqual(sample_archive["dates"][0].title, dates[0].title) - self.assertEqual(sample_archive["dates"][0].date, dates[0].date) - - def test_period_in_timeperiod_archive(self): - """ - Test that the context of a generated period_archive is passed - 'period' : a tuple of year, month, day according to the time period - """ - settings = get_settings() - - settings["YEAR_ARCHIVE_SAVE_AS"] = "posts/{date:%Y}/index.html" - settings["YEAR_ARCHIVE_URL"] = "posts/{date:%Y}/" - settings["CACHE_PATH"] = self.temp_cache - context = get_context(settings) - generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - write = MagicMock() - generator.generate_period_archives(write) - dates = [d for d in generator.dates if d.date.year == 1970] - articles = [d for d in generator.articles if d.date.year == 1970] - self.assertEqual(len(dates), 1) - # among other things it must have at least been called with this - context["period"] = (1970,) - context["period_num"] = (1970,) - write.assert_called_with( - "posts/1970/index.html", - generator.get_template("period_archives"), - context, - blog=True, - articles=articles, - dates=dates, - template_name="period_archives", - url="posts/1970/", - all_articles=generator.articles, - ) - - settings["MONTH_ARCHIVE_SAVE_AS"] = "posts/{date:%Y}/{date:%b}/index.html" - settings["MONTH_ARCHIVE_URL"] = "posts/{date:%Y}/{date:%b}/" - context = get_context(settings) - generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - write = MagicMock() - generator.generate_period_archives(write) - dates = [ - d for d in generator.dates if d.date.year == 1970 and d.date.month == 1 - ] - articles = [ - d for d in generator.articles if d.date.year == 1970 and d.date.month == 1 - ] - self.assertEqual(len(dates), 1) - context["period"] = (1970, "January") - context["period_num"] = (1970, 1) - # among other things it must have at least been called with this - write.assert_called_with( - "posts/1970/Jan/index.html", - generator.get_template("period_archives"), - context, - blog=True, - articles=articles, - dates=dates, - template_name="period_archives", - url="posts/1970/Jan/", - all_articles=generator.articles, - ) - - settings["DAY_ARCHIVE_SAVE_AS"] = ( - "posts/{date:%Y}/{date:%b}/{date:%d}/index.html" - ) - settings["DAY_ARCHIVE_URL"] = "posts/{date:%Y}/{date:%b}/{date:%d}/" - context = get_context(settings) - generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - write = MagicMock() - generator.generate_period_archives(write) - dates = [ - d - for d in generator.dates - if d.date.year == 1970 and d.date.month == 1 and d.date.day == 1 - ] - articles = [ - d - for d in generator.articles - if d.date.year == 1970 and d.date.month == 1 and d.date.day == 1 - ] - self.assertEqual(len(dates), 1) - context["period"] = (1970, "January", 1) - context["period_num"] = (1970, 1, 1) - # among other things it must have at least been called with this - write.assert_called_with( - "posts/1970/Jan/01/index.html", - generator.get_template("period_archives"), - context, - blog=True, - articles=articles, - dates=dates, - template_name="period_archives", - url="posts/1970/Jan/01/", - all_articles=generator.articles, - ) - - def test_nonexistent_template(self): - """Attempt to load a non-existent template""" - settings = get_settings() - context = get_context(settings) - generator = ArticlesGenerator( - context=context, - settings=settings, - path=None, - theme=settings["THEME"], - output_path=None, - ) - self.assertRaises(Exception, generator.get_template, "not_a_template") - - def test_generate_authors(self): - """Check authors generation.""" - authors = [author.name for author, _ in self.generator.authors] - authors_expected = sorted( - [ - "Alexis Métaireau", - "Author, First", - "Author, Second", - "First Author", - "Second Author", - ] - ) - self.assertEqual(sorted(authors), authors_expected) - # test for slug - authors = [author.slug for author, _ in self.generator.authors] - authors_expected = [ - "alexis-metaireau", - "author-first", - "author-second", - "first-author", - "second-author", - ] - self.assertEqual(sorted(authors), sorted(authors_expected)) - - def test_standard_metadata_in_default_metadata(self): - settings = get_settings() - settings["CACHE_CONTENT"] = False - settings["DEFAULT_CATEGORY"] = "Default" - settings["DEFAULT_DATE"] = (1970, 1, 1) - settings["DEFAULT_METADATA"] = ( - ("author", "Blogger"), - # category will be ignored in favor of - # DEFAULT_CATEGORY - ("category", "Random"), - ("tags", "general, untagged"), - ) - context = get_context(settings) - generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - - authors = sorted([author.name for author, _ in generator.authors]) - authors_expected = sorted( - [ - "Alexis Métaireau", - "Blogger", - "Author, First", - "Author, Second", - "First Author", - "Second Author", - ] - ) - self.assertEqual(authors, authors_expected) - - categories = sorted([category.name for category, _ in generator.categories]) - categories_expected = [ - sorted( - ["Default", "TestCategory", "medium_posts", "yeah", "test", "指導書"] - ), - sorted( - ["Default", "TestCategory", "medium_posts", "Yeah", "test", "指導書"] - ), - ] - self.assertIn(categories, categories_expected) - - tags = sorted([tag.name for tag in generator.tags]) - tags_expected = sorted( - ["bar", "foo", "foobar", "general", "untagged", "パイソン", "マック"] - ) - self.assertEqual(tags, tags_expected) - - def test_article_order_by(self): - settings = get_settings() - settings["DEFAULT_CATEGORY"] = "Default" - settings["DEFAULT_DATE"] = (1970, 1, 1) - settings["ARTICLE_ORDER_BY"] = "title" - context = get_context(settings) - - generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - - expected = [ - "A title", - "An Article With Code Block To Test Typogrify Ignore", - "Article title", - "Article with Nonconformant HTML meta tags", - "Article with an inline SVG", - "Article with markdown and empty tags", - "Article with markdown and nested summary metadata", - "Article with markdown and summary metadata multi", - "Article with markdown and summary metadata single", - "Article with markdown containing footnotes", - "Article with template", - "Metadata tags as list!", - "One -, two --, three --- dashes!", - "One -, two --, three --- dashes!", - "Rst with filename metadata", - "Test Markdown extensions", - "Test markdown File", - "Test md File", - "Test mdown File", - "Test metadata duplicates", - "Test mkd File", - "This is a super article !", - "This is a super article !", - "This is a super article !", - "This is a super article !", - "This is a super article !", - "This is a super article !", - "This is a super article !", - "This is a super article !", - "This is a super article !", - "This is a super article !", - "This is a super article !", - "This is an article with category !", - ( - "This is an article with multiple authors in lastname, " - "firstname format!" - ), - "This is an article with multiple authors in list format!", - "This is an article with multiple authors!", - "This is an article with multiple authors!", - "This is an article without category !", - "This is an article without category !", - "マックOS X 10.8でパイソンとVirtualenvをインストールと設定", - ] - - articles = [article.title for article in generator.articles] - self.assertEqual(articles, expected) - - # reversed title - settings = get_settings() - settings["DEFAULT_CATEGORY"] = "Default" - settings["DEFAULT_DATE"] = (1970, 1, 1) - settings["ARTICLE_ORDER_BY"] = "reversed-title" - context = get_context(settings) - - generator = ArticlesGenerator( - context=context, - settings=settings, - path=CONTENT_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - - articles = [article.title for article in generator.articles] - self.assertEqual(articles, list(reversed(expected))) - - -class TestPageGenerator(unittest.TestCase): - # Note: Every time you want to test for a new field; Make sure the test - # pages in "TestPages" have all the fields Add it to distilled in - # distill_pages Then update the assertEqual in test_generate_context - # to match expected - - def setUp(self): - self.temp_cache = mkdtemp(prefix="pelican_cache.") - - def tearDown(self): - rmtree(self.temp_cache) - - def distill_pages(self, pages): - return [[page.title, page.status, page.template] for page in pages] - - def test_generate_context(self): - settings = get_settings() - settings["CACHE_PATH"] = self.temp_cache - settings["PAGE_PATHS"] = ["TestPages"] # relative to CUR_DIR - settings["DEFAULT_DATE"] = (1970, 1, 1) - context = get_context(settings) - - generator = PagesGenerator( - context=context, - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - pages = self.distill_pages(generator.pages) - hidden_pages = self.distill_pages(generator.hidden_pages) - draft_pages = self.distill_pages(generator.draft_pages) - - pages_expected = [ - ["This is a test page", "published", "page"], - ["This is a markdown test page", "published", "page"], - ["This is a test page with a preset template", "published", "custom"], - ["Page with a bunch of links", "published", "page"], - ["Page with static links", "published", "page"], - ["A Page (Test) for sorting", "published", "page"], - ] - hidden_pages_expected = [ - ["This is a test hidden page", "hidden", "page"], - ["This is a markdown test hidden page", "hidden", "page"], - ["This is a test hidden page with a custom template", "hidden", "custom"], - ] - draft_pages_expected = [ - ["This is a test draft page", "draft", "page"], - ["This is a markdown test draft page", "draft", "page"], - ["This is a test draft page with a custom template", "draft", "custom"], - ] - - self.assertEqual(sorted(pages_expected), sorted(pages)) - self.assertEqual( - sorted(pages_expected), - sorted(self.distill_pages(generator.context["pages"])), - ) - self.assertEqual(sorted(hidden_pages_expected), sorted(hidden_pages)) - self.assertEqual(sorted(draft_pages_expected), sorted(draft_pages)) - self.assertEqual( - sorted(hidden_pages_expected), - sorted(self.distill_pages(generator.context["hidden_pages"])), - ) - self.assertEqual( - sorted(draft_pages_expected), - sorted(self.distill_pages(generator.context["draft_pages"])), - ) - - def test_generate_sorted(self): - settings = get_settings() - settings["PAGE_PATHS"] = ["TestPages"] # relative to CUR_DIR - settings["CACHE_PATH"] = self.temp_cache - settings["DEFAULT_DATE"] = (1970, 1, 1) - context = get_context(settings) - - # default sort (filename) - pages_expected_sorted_by_filename = [ - ["This is a test page", "published", "page"], - ["This is a markdown test page", "published", "page"], - ["A Page (Test) for sorting", "published", "page"], - ["Page with a bunch of links", "published", "page"], - ["Page with static links", "published", "page"], - ["This is a test page with a preset template", "published", "custom"], - ] - generator = PagesGenerator( - context=context, - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - pages = self.distill_pages(generator.pages) - self.assertEqual(pages_expected_sorted_by_filename, pages) - - # sort by title - pages_expected_sorted_by_title = [ - ["A Page (Test) for sorting", "published", "page"], - ["Page with a bunch of links", "published", "page"], - ["Page with static links", "published", "page"], - ["This is a markdown test page", "published", "page"], - ["This is a test page", "published", "page"], - ["This is a test page with a preset template", "published", "custom"], - ] - settings["PAGE_ORDER_BY"] = "title" - context = get_context(settings) - generator = PagesGenerator( - context=context.copy(), - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - pages = self.distill_pages(generator.pages) - self.assertEqual(pages_expected_sorted_by_title, pages) - - # sort by title reversed - pages_expected_sorted_by_title = [ - ["This is a test page with a preset template", "published", "custom"], - ["This is a test page", "published", "page"], - ["This is a markdown test page", "published", "page"], - ["Page with static links", "published", "page"], - ["Page with a bunch of links", "published", "page"], - ["A Page (Test) for sorting", "published", "page"], - ] - settings["PAGE_ORDER_BY"] = "reversed-title" - context = get_context(settings) - generator = PagesGenerator( - context=context, - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - pages = self.distill_pages(generator.pages) - self.assertEqual(pages_expected_sorted_by_title, pages) - - def test_tag_and_category_links_on_generated_pages(self): - """ - Test to ensure links of the form {tag}tagname and {category}catname - are generated correctly on pages - """ - settings = get_settings() - settings["PAGE_PATHS"] = ["TestPages"] # relative to CUR_DIR - settings["CACHE_PATH"] = self.temp_cache - settings["DEFAULT_DATE"] = (1970, 1, 1) - context = get_context(settings) - - generator = PagesGenerator( - context=context, - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - pages_by_title = {p.title: p for p in generator.pages} - - test_content = pages_by_title["Page with a bunch of links"].content - self.assertIn('', test_content) - self.assertIn('', test_content) - - def test_static_and_attach_links_on_generated_pages(self): - """ - Test to ensure links of the form {static}filename and {attach}filename - are included in context['static_links'] - """ - settings = get_settings() - settings["PAGE_PATHS"] = ["TestPages/page_with_static_links.md"] - settings["CACHE_PATH"] = self.temp_cache - settings["DEFAULT_DATE"] = (1970, 1, 1) - context = get_context(settings) - - generator = PagesGenerator( - context=context, - settings=settings, - path=CUR_DIR, - theme=settings["THEME"], - output_path=None, - ) - generator.generate_context() - - self.assertIn("pelican/tests/TestPages/image0.jpg", context["static_links"]) - self.assertIn("pelican/tests/TestPages/image1.jpg", context["static_links"]) - - -class TestTemplatePagesGenerator(TestCaseWithCLocale): - TEMPLATE_CONTENT = "foo: {{ foo }}" - - def setUp(self): - super().setUp() - self.temp_content = mkdtemp(prefix="pelicantests.") - self.temp_output = mkdtemp(prefix="pelicantests.") - - def tearDown(self): - rmtree(self.temp_content) - rmtree(self.temp_output) - - def test_generate_output(self): - settings = get_settings() - settings["STATIC_PATHS"] = ["static"] - settings["TEMPLATE_PAGES"] = {"template/source.html": "generated/file.html"} - - generator = TemplatePagesGenerator( - context={"foo": "bar"}, - settings=settings, - path=self.temp_content, - theme="", - output_path=self.temp_output, - ) - - # create a dummy template file - template_dir = os.path.join(self.temp_content, "template") - template_path = os.path.join(template_dir, "source.html") - os.makedirs(template_dir) - with open(template_path, "w") as template_file: - template_file.write(self.TEMPLATE_CONTENT) - - writer = Writer(self.temp_output, settings=settings) - generator.generate_output(writer) - - output_path = os.path.join(self.temp_output, "generated", "file.html") - - # output file has been generated - self.assertTrue(os.path.exists(output_path)) - - # output content is correct - with open(output_path) as output_file: - self.assertEqual(output_file.read(), "foo: bar") - - -class TestStaticGenerator(unittest.TestCase): - def setUp(self): - self.content_path = os.path.join(CUR_DIR, "mixed_content") - self.temp_content = mkdtemp(prefix="testcontent.") - self.temp_output = mkdtemp(prefix="testoutput.") - self.settings = get_settings() - self.settings["PATH"] = self.temp_content - self.settings["STATIC_PATHS"] = ["static"] - self.settings["OUTPUT_PATH"] = self.temp_output - os.mkdir(os.path.join(self.temp_content, "static")) - self.startfile = os.path.join(self.temp_content, "static", "staticfile") - self.endfile = os.path.join(self.temp_output, "static", "staticfile") - self.generator = StaticGenerator( - context=get_context(), - settings=self.settings, - path=self.temp_content, - theme="", - output_path=self.temp_output, - ) - - def tearDown(self): - rmtree(self.temp_content) - rmtree(self.temp_output) - - def set_ancient_mtime(self, path, timestamp=1): - os.utime(path, (timestamp, timestamp)) - - def test_theme_static_paths_dirs(self): - """Test that StaticGenerator properly copies also files mentioned in - TEMPLATE_STATIC_PATHS, not just directories.""" - settings = get_settings(PATH=self.content_path) - context = get_context(settings, staticfiles=[]) - - StaticGenerator( - context=context, - settings=settings, - path=settings["PATH"], - output_path=self.temp_output, - theme=settings["THEME"], - ).generate_output(None) - - # The content of dirs listed in THEME_STATIC_PATHS (defaulting to - # "static") is put into the output - self.assertTrue(os.path.isdir(os.path.join(self.temp_output, "theme/css/"))) - self.assertTrue(os.path.isdir(os.path.join(self.temp_output, "theme/fonts/"))) - - def test_theme_static_paths_files(self): - """Test that StaticGenerator properly copies also files mentioned in - TEMPLATE_STATIC_PATHS, not just directories.""" - settings = get_settings( - PATH=self.content_path, - THEME_STATIC_PATHS=["static/css/fonts.css", "static/fonts/"], - ) - context = get_context(settings, staticfiles=[]) - - StaticGenerator( - context=context, - settings=settings, - path=settings["PATH"], - output_path=self.temp_output, - theme=settings["THEME"], - ).generate_output(None) - - # Only the content of dirs and files listed in THEME_STATIC_PATHS are - # put into the output, not everything from static/ - self.assertFalse(os.path.isdir(os.path.join(self.temp_output, "theme/css/"))) - self.assertFalse(os.path.isdir(os.path.join(self.temp_output, "theme/fonts/"))) - - self.assertTrue( - os.path.isfile( - os.path.join(self.temp_output, "theme/Yanone_Kaffeesatz_400.eot") - ) - ) - self.assertTrue( - os.path.isfile( - os.path.join(self.temp_output, "theme/Yanone_Kaffeesatz_400.svg") - ) - ) - self.assertTrue( - os.path.isfile( - os.path.join(self.temp_output, "theme/Yanone_Kaffeesatz_400.ttf") - ) - ) - self.assertTrue( - os.path.isfile( - os.path.join(self.temp_output, "theme/Yanone_Kaffeesatz_400.woff") - ) - ) - self.assertTrue( - os.path.isfile( - os.path.join(self.temp_output, "theme/Yanone_Kaffeesatz_400.woff2") - ) - ) - self.assertTrue( - os.path.isfile(os.path.join(self.temp_output, "theme/font.css")) - ) - self.assertTrue( - os.path.isfile(os.path.join(self.temp_output, "theme/fonts.css")) - ) - - def test_static_excludes(self): - """Test that StaticGenerator respects STATIC_EXCLUDES.""" - settings = get_settings( - STATIC_EXCLUDES=["subdir"], - PATH=self.content_path, - STATIC_PATHS=[""], - ) - context = get_context(settings) - - StaticGenerator( - context=context, - settings=settings, - path=settings["PATH"], - output_path=self.temp_output, - theme=settings["THEME"], - ).generate_context() - - staticnames = [os.path.basename(c.source_path) for c in context["staticfiles"]] - - self.assertNotIn( - "subdir_fake_image.jpg", - staticnames, - "StaticGenerator processed a file in a STATIC_EXCLUDES directory", - ) - self.assertIn( - "fake_image.jpg", - staticnames, - "StaticGenerator skipped a file that it should have included", - ) - - def test_static_exclude_sources(self): - """Test that StaticGenerator respects STATIC_EXCLUDE_SOURCES.""" - - settings = get_settings( - STATIC_EXCLUDE_SOURCES=True, - PATH=self.content_path, - PAGE_PATHS=[""], - STATIC_PATHS=[""], - CACHE_CONTENT=False, - ) - context = get_context(settings) - - for generator_class in (PagesGenerator, StaticGenerator): - generator_class( - context=context, - settings=settings, - path=settings["PATH"], - output_path=self.temp_output, - theme=settings["THEME"], - ).generate_context() - - staticnames = [os.path.basename(c.source_path) for c in context["staticfiles"]] - - self.assertFalse( - any(name.endswith(".md") for name in staticnames), - "STATIC_EXCLUDE_SOURCES=True failed to exclude a markdown file", - ) - - settings.update(STATIC_EXCLUDE_SOURCES=False) - context = get_context(settings) - - for generator_class in (PagesGenerator, StaticGenerator): - generator_class( - context=context, - settings=settings, - path=settings["PATH"], - output_path=self.temp_output, - theme=settings["THEME"], - ).generate_context() - - staticnames = [os.path.basename(c.source_path) for c in context["staticfiles"]] - - self.assertTrue( - any(name.endswith(".md") for name in staticnames), - "STATIC_EXCLUDE_SOURCES=False failed to include a markdown file", - ) - - def test_static_links(self): - """Test that StaticGenerator uses files in static_links""" - settings = get_settings( - STATIC_EXCLUDES=["subdir"], - PATH=self.content_path, - STATIC_PATHS=[], - ) - context = get_context(settings) - context["static_links"] |= {"short_page.md", "subdir_fake_image.jpg"} - - StaticGenerator( - context=context, - settings=settings, - path=settings["PATH"], - output_path=self.temp_output, - theme=settings["THEME"], - ).generate_context() - - staticfiles_names = [ - os.path.basename(c.source_path) for c in context["staticfiles"] - ] - - static_content_names = [os.path.basename(c) for c in context["static_content"]] - - self.assertIn( - "short_page.md", - staticfiles_names, - "StaticGenerator skipped a file that it should have included", - ) - self.assertIn( - "short_page.md", - static_content_names, - "StaticGenerator skipped a file that it should have included", - ) - self.assertIn( - "subdir_fake_image.jpg", - staticfiles_names, - "StaticGenerator skipped a file that it should have included", - ) - self.assertIn( - "subdir_fake_image.jpg", - static_content_names, - "StaticGenerator skipped a file that it should have included", - ) - - def test_copy_one_file(self): - with open(self.startfile, "w") as f: - f.write("staticcontent") - self.generator.generate_context() - self.generator.generate_output(None) - with open(self.endfile) as f: - self.assertEqual(f.read(), "staticcontent") - - def test_file_update_required_when_dest_does_not_exist(self): - staticfile = MagicMock() - staticfile.source_path = self.startfile - staticfile.save_as = self.endfile - with open(staticfile.source_path, "w") as f: - f.write("a") - update_required = self.generator._file_update_required(staticfile) - self.assertTrue(update_required) - - def test_dest_and_source_mtimes_are_equal(self): - staticfile = MagicMock() - staticfile.source_path = self.startfile - staticfile.save_as = self.endfile - self.settings["STATIC_CHECK_IF_MODIFIED"] = True - with open(staticfile.source_path, "w") as f: - f.write("a") - os.mkdir(os.path.join(self.temp_output, "static")) - copy(staticfile.source_path, staticfile.save_as) - isnewer = self.generator._source_is_newer(staticfile) - self.assertFalse(isnewer) - - def test_source_is_newer(self): - staticfile = MagicMock() - staticfile.source_path = self.startfile - staticfile.save_as = self.endfile - with open(staticfile.source_path, "w") as f: - f.write("a") - os.mkdir(os.path.join(self.temp_output, "static")) - copy(staticfile.source_path, staticfile.save_as) - self.set_ancient_mtime(staticfile.save_as) - isnewer = self.generator._source_is_newer(staticfile) - self.assertTrue(isnewer) - - def test_skip_file_when_source_is_not_newer(self): - self.settings["STATIC_CHECK_IF_MODIFIED"] = True - with open(self.startfile, "w") as f: - f.write("staticcontent") - os.mkdir(os.path.join(self.temp_output, "static")) - with open(self.endfile, "w") as f: - f.write("staticcontent") - expected = os.path.getmtime(self.endfile) - self.set_ancient_mtime(self.startfile) - self.generator.generate_context() - self.generator.generate_output(None) - self.assertEqual(os.path.getmtime(self.endfile), expected) - - def test_dont_link_by_default(self): - with open(self.startfile, "w") as f: - f.write("staticcontent") - self.generator.generate_context() - self.generator.generate_output(None) - self.assertFalse(os.path.samefile(self.startfile, self.endfile)) - - def test_output_file_is_linked_to_source(self): - self.settings["STATIC_CREATE_LINKS"] = True - with open(self.startfile, "w") as f: - f.write("staticcontent") - self.generator.generate_context() - self.generator.generate_output(None) - self.assertTrue(os.path.samefile(self.startfile, self.endfile)) - - def test_output_file_exists_and_is_newer(self): - self.settings["STATIC_CREATE_LINKS"] = True - with open(self.startfile, "w") as f: - f.write("staticcontent") - os.mkdir(os.path.join(self.temp_output, "static")) - with open(self.endfile, "w") as f: - f.write("othercontent") - self.generator.generate_context() - self.generator.generate_output(None) - self.assertTrue(os.path.samefile(self.startfile, self.endfile)) - - @unittest.skipUnless(can_symlink(), "No symlink privilege") - def test_can_symlink_when_hardlink_not_possible(self): - self.settings["STATIC_CREATE_LINKS"] = True - with open(self.startfile, "w") as f: - f.write("staticcontent") - os.mkdir(os.path.join(self.temp_output, "static")) - self.generator.fallback_to_symlinks = True - self.generator.generate_context() - self.generator.generate_output(None) - self.assertTrue(os.path.islink(self.endfile)) - - @unittest.skipUnless(can_symlink(), "No symlink privilege") - def test_existing_symlink_is_considered_up_to_date(self): - self.settings["STATIC_CREATE_LINKS"] = True - with open(self.startfile, "w") as f: - f.write("staticcontent") - os.mkdir(os.path.join(self.temp_output, "static")) - os.symlink(self.startfile, self.endfile) - staticfile = MagicMock() - staticfile.source_path = self.startfile - staticfile.save_as = self.endfile - requires_update = self.generator._file_update_required(staticfile) - self.assertFalse(requires_update) - - @unittest.skipUnless(can_symlink(), "No symlink privilege") - def test_invalid_symlink_is_overwritten(self): - self.settings["STATIC_CREATE_LINKS"] = True - with open(self.startfile, "w") as f: - f.write("staticcontent") - os.mkdir(os.path.join(self.temp_output, "static")) - os.symlink("invalid", self.endfile) - staticfile = MagicMock() - staticfile.source_path = self.startfile - staticfile.save_as = self.endfile - requires_update = self.generator._file_update_required(staticfile) - self.assertTrue(requires_update) - self.generator.fallback_to_symlinks = True - self.generator.generate_context() - self.generator.generate_output(None) - self.assertTrue(os.path.islink(self.endfile)) - - # os.path.realpath is broken on Windows before python3.8 for symlinks. - # This is a (ugly) workaround. - # see: https://bugs.python.org/issue9949 - if os.name == "nt" and sys.version_info < (3, 8): - - def get_real_path(path): - return os.readlink(path) if os.path.islink(path) else path - else: - get_real_path = os.path.realpath - - self.assertEqual(get_real_path(self.endfile), get_real_path(self.startfile)) - - def test_delete_existing_file_before_mkdir(self): - with open(self.startfile, "w") as f: - f.write("staticcontent") - with open(os.path.join(self.temp_output, "static"), "w") as f: - f.write("This file should be a directory") - self.generator.generate_context() - self.generator.generate_output(None) - self.assertTrue(os.path.isdir(os.path.join(self.temp_output, "static"))) - self.assertTrue(os.path.isfile(self.endfile)) - - -class TestJinja2Environment(TestCaseWithCLocale): - def setUp(self): - self.temp_content = mkdtemp(prefix="pelicantests.") - self.temp_output = mkdtemp(prefix="pelicantests.") - - def tearDown(self): - rmtree(self.temp_content) - rmtree(self.temp_output) - - def _test_jinja2_helper(self, additional_settings, content, expected): - settings = get_settings() - settings["STATIC_PATHS"] = ["static"] - settings["TEMPLATE_PAGES"] = {"template/source.html": "generated/file.html"} - settings.update(additional_settings) - - generator = TemplatePagesGenerator( - context={"foo": "foo", "bar": "bar"}, - settings=settings, - path=self.temp_content, - theme="", - output_path=self.temp_output, - ) - - # create a dummy template file - template_dir = os.path.join(self.temp_content, "template") - template_path = os.path.join(template_dir, "source.html") - os.makedirs(template_dir) - with open(template_path, "w") as template_file: - template_file.write(content) - - writer = Writer(self.temp_output, settings=settings) - generator.generate_output(writer) - - output_path = os.path.join(self.temp_output, "generated", "file.html") - - # output file has been generated - self.assertTrue(os.path.exists(output_path)) - - # output content is correct - with open(output_path) as output_file: - self.assertEqual(output_file.read(), expected) - - def test_jinja2_filter(self): - """JINJA_FILTERS adds custom filters to Jinja2 environment""" - content = "foo: {{ foo|custom_filter }}, bar: {{ bar|custom_filter }}" - settings = {"JINJA_FILTERS": {"custom_filter": lambda x: x.upper()}} - expected = "foo: FOO, bar: BAR" - - self._test_jinja2_helper(settings, content, expected) - - def test_jinja2_filter_plugin_enabled(self): - """JINJA_FILTERS adds custom filters to Jinja2 environment""" - settings = {"PLUGINS": ["legacy_plugin", "pelican.plugins.ns_plugin"]} - jinja_template = ( - "{plugin}: " - "{{% if '{plugin}' is plugin_enabled %}}yes" - "{{% else %}}no{{% endif %}}" - ) - content = " / ".join( - ( - jinja_template.format(plugin="ns_plugin"), - jinja_template.format(plugin="pelican.plugins.ns_plugin"), - jinja_template.format(plugin="legacy_plugin"), - jinja_template.format(plugin="unknown"), - ) - ) - expected = ( - "ns_plugin: yes / " - "pelican.plugins.ns_plugin: yes / " - "legacy_plugin: yes / " - "unknown: no" - ) - - self._test_jinja2_helper(settings, content, expected) - - def test_jinja2_test(self): - """JINJA_TESTS adds custom tests to Jinja2 environment""" - content = "foo {{ foo is custom_test }}, bar {{ bar is custom_test }}" - settings = {"JINJA_TESTS": {"custom_test": lambda x: x == "bar"}} - expected = "foo False, bar True" - - self._test_jinja2_helper(settings, content, expected) - - def test_jinja2_global(self): - """JINJA_GLOBALS adds custom globals to Jinja2 environment""" - content = "{{ custom_global }}" - settings = {"JINJA_GLOBALS": {"custom_global": "foobar"}} - expected = "foobar" - - self._test_jinja2_helper(settings, content, expected) - - def test_jinja2_extension(self): - """JINJA_ENVIRONMENT adds extensions to Jinja2 environment""" - content = "{% set stuff = [] %}{% do stuff.append(1) %}{{ stuff }}" - settings = {"JINJA_ENVIRONMENT": {"extensions": ["jinja2.ext.do"]}} - expected = "[1]" - - self._test_jinja2_helper(settings, content, expected) diff --git a/pelican/tests/test_importer.py b/pelican/tests/test_importer.py deleted file mode 100644 index 10b0f7f6..00000000 --- a/pelican/tests/test_importer.py +++ /dev/null @@ -1,788 +0,0 @@ -import os -import re -from posixpath import join as posix_join -from unittest.mock import patch - -from pelican.settings import DEFAULT_CONFIG -from pelican.tests.support import ( - TestCaseWithCLocale, - mute, - skipIfNoExecutable, - temporary_folder, - unittest, -) -from pelican.tools.pelican_import import ( - blogger2fields, - build_header, - build_markdown_header, - decode_wp_content, - download_attachments, - fields2pelican, - get_attachments, - medium_slug, - mediumpost2fields, - mediumposts2fields, - strip_medium_post_content, - tumblr2fields, - wp2fields, -) -from pelican.utils import path_to_file_url, slugify - -CUR_DIR = os.path.abspath(os.path.dirname(__file__)) -BLOGGER_XML_SAMPLE = os.path.join(CUR_DIR, "content", "bloggerexport.xml") -WORDPRESS_XML_SAMPLE = os.path.join(CUR_DIR, "content", "wordpressexport.xml") -WORDPRESS_ENCODED_CONTENT_SAMPLE = os.path.join( - CUR_DIR, "content", "wordpress_content_encoded" -) -WORDPRESS_DECODED_CONTENT_SAMPLE = os.path.join( - CUR_DIR, "content", "wordpress_content_decoded" -) - -try: - from bs4 import BeautifulSoup -except ImportError: - BeautifulSoup = False - -try: - import bs4.builder._lxml as LXML -except ImportError: - LXML = False - - -@skipIfNoExecutable(["pandoc", "--version"]) -@unittest.skipUnless(BeautifulSoup, "Needs BeautifulSoup module") -class TestBloggerXmlImporter(TestCaseWithCLocale): - def setUp(self): - super().setUp() - self.posts = blogger2fields(BLOGGER_XML_SAMPLE) - - def test_recognise_kind_and_title(self): - """Check that importer only outputs pages, articles and comments, - that these are correctly identified and that titles are correct. - """ - test_posts = list(self.posts) - kinds = {x[8] for x in test_posts} - self.assertEqual({"page", "article", "comment"}, kinds) - page_titles = {x[0] for x in test_posts if x[8] == "page"} - self.assertEqual({"Test page", "Test page 2"}, page_titles) - article_titles = {x[0] for x in test_posts if x[8] == "article"} - self.assertEqual( - {"Black as Egypt's Night", "The Steel Windpipe"}, article_titles - ) - comment_titles = {x[0] for x in test_posts if x[8] == "comment"} - self.assertEqual( - {"Mishka, always a pleasure to read your adventures!..."}, comment_titles - ) - - def test_recognise_status_with_correct_filename(self): - """Check that importerer outputs only statuses 'published' and 'draft', - that these are correctly identified and that filenames are correct. - """ - test_posts = list(self.posts) - statuses = {x[7] for x in test_posts} - self.assertEqual({"published", "draft"}, statuses) - - draft_filenames = {x[2] for x in test_posts if x[7] == "draft"} - # draft filenames are id-based - self.assertEqual( - {"page-4386962582497458967", "post-1276418104709695660"}, draft_filenames - ) - - published_filenames = {x[2] for x in test_posts if x[7] == "published"} - # published filenames are url-based, except comments - self.assertEqual( - {"the-steel-windpipe", "test-page", "post-5590533389087749201"}, - published_filenames, - ) - - -@skipIfNoExecutable(["pandoc", "--version"]) -@unittest.skipUnless(BeautifulSoup, "Needs BeautifulSoup module") -class TestWordpressXmlImporter(TestCaseWithCLocale): - def setUp(self): - super().setUp() - self.posts = wp2fields(WORDPRESS_XML_SAMPLE) - self.custposts = wp2fields(WORDPRESS_XML_SAMPLE, True) - - def test_ignore_empty_posts(self): - self.assertTrue(self.posts) - for ( - title, - _content, - _fname, - _date, - _author, - _categ, - _tags, - _status, - _kind, - _format, - ) in self.posts: - self.assertTrue(title.strip()) - - def test_recognise_page_kind(self): - """Check that we recognise pages in wordpress, as opposed to posts""" - self.assertTrue(self.posts) - # Collect (title, filename, kind) of non-empty posts recognised as page - pages_data = [] - for ( - title, - _content, - fname, - _date, - _author, - _categ, - _tags, - _status, - kind, - _format, - ) in self.posts: - if kind == "page": - pages_data.append((title, fname)) - self.assertEqual(2, len(pages_data)) - self.assertEqual(("Page", "contact"), pages_data[0]) - self.assertEqual(("Empty Page", "empty"), pages_data[1]) - - def test_dirpage_directive_for_page_kind(self): - silent_f2p = mute(True)(fields2pelican) - test_post = filter(lambda p: p[0].startswith("Empty Page"), self.posts) - with temporary_folder() as temp: - fname = next(iter(silent_f2p(test_post, "markdown", temp, dirpage=True))) - self.assertTrue(fname.endswith(f"pages{os.path.sep}empty.md")) - - def test_dircat(self): - silent_f2p = mute(True)(fields2pelican) - test_posts = [ - post - for post in self.posts - # check post has a category - if len(post[5]) > 0 - ] - with temporary_folder() as temp: - fnames = list(silent_f2p(test_posts, "markdown", temp, dircat=True)) - subs = DEFAULT_CONFIG["SLUG_REGEX_SUBSTITUTIONS"] - index = 0 - for post in test_posts: - name = post[2] - category = slugify(post[5][0], regex_subs=subs, preserve_case=True) - name += ".md" - filename = os.path.join(category, name) - out_name = fnames[index] - self.assertTrue(out_name.endswith(filename)) - index += 1 - - def test_unless_custom_post_all_items_should_be_pages_or_posts(self): - self.assertTrue(self.posts) - pages_data = [] - for ( - title, - _content, - fname, - _date, - _author, - _categ, - _tags, - _status, - kind, - _format, - ) in self.posts: - if kind in {"page", "article"}: - pass - else: - pages_data.append((title, fname)) - self.assertEqual(0, len(pages_data)) - - def test_recognise_custom_post_type(self): - self.assertTrue(self.custposts) - cust_data = [] - for ( - title, - _content, - _fname, - _date, - _author, - _categ, - _tags, - _status, - kind, - _format, - ) in self.custposts: - if kind in {"page", "article"}: - pass - else: - cust_data.append((title, kind)) - self.assertEqual(3, len(cust_data)) - self.assertEqual(("A custom post in category 4", "custom1"), cust_data[0]) - self.assertEqual(("A custom post in category 5", "custom1"), cust_data[1]) - self.assertEqual( - ("A 2nd custom post type also in category 5", "custom2"), cust_data[2] - ) - - def test_custom_posts_put_in_own_dir(self): - silent_f2p = mute(True)(fields2pelican) - test_posts = [] - for post in self.custposts: - # check post kind - if post[8] == "article" or post[8] == "page": - pass - else: - test_posts.append(post) - with temporary_folder() as temp: - fnames = list(silent_f2p(test_posts, "markdown", temp, wp_custpost=True)) - index = 0 - for post in test_posts: - name = post[2] - kind = post[8] - name += ".md" - filename = os.path.join(kind, name) - out_name = fnames[index] - self.assertTrue(out_name.endswith(filename)) - index += 1 - - def test_custom_posts_put_in_own_dir_and_catagory_sub_dir(self): - silent_f2p = mute(True)(fields2pelican) - test_posts = [] - for post in self.custposts: - # check post kind - if post[8] == "article" or post[8] == "page": - pass - else: - test_posts.append(post) - with temporary_folder() as temp: - fnames = list( - silent_f2p(test_posts, "markdown", temp, wp_custpost=True, dircat=True) - ) - subs = DEFAULT_CONFIG["SLUG_REGEX_SUBSTITUTIONS"] - index = 0 - for post in test_posts: - name = post[2] - kind = post[8] - category = slugify(post[5][0], regex_subs=subs, preserve_case=True) - name += ".md" - filename = os.path.join(kind, category, name) - out_name = fnames[index] - self.assertTrue(out_name.endswith(filename)) - index += 1 - - def test_wp_custpost_true_dirpage_false(self): - # pages should only be put in their own directory when dirpage = True - silent_f2p = mute(True)(fields2pelican) - test_posts = [ - post - for post in self.custposts - # check post kind - if post[8] == "page" - ] - with temporary_folder() as temp: - fnames = list( - silent_f2p( - test_posts, "markdown", temp, wp_custpost=True, dirpage=False - ) - ) - index = 0 - for post in test_posts: - name = post[2] - name += ".md" - filename = os.path.join("pages", name) - out_name = fnames[index] - self.assertFalse(out_name.endswith(filename)) - - def test_can_toggle_raw_html_code_parsing(self): - test_posts = list(self.posts) - - def r(f): - with open(f, encoding="utf-8") as infile: - return infile.read() - - silent_f2p = mute(True)(fields2pelican) - - with temporary_folder() as temp: - rst_files = (r(f) for f in silent_f2p(test_posts, "markdown", temp)) - self.assertTrue(any(" entities in " - "the title. You can't miss them.", - ) - self.assertNotIn("&", title) - - def test_decode_wp_content_returns_empty(self): - """Check that given an empty string we return an empty string.""" - self.assertEqual(decode_wp_content(""), "") - - def test_decode_wp_content(self): - """Check that we can decode a wordpress content string.""" - with open(WORDPRESS_ENCODED_CONTENT_SAMPLE) as encoded_file: - encoded_content = encoded_file.read() - with open(WORDPRESS_DECODED_CONTENT_SAMPLE) as decoded_file: - decoded_content = decoded_file.read() - self.assertEqual( - decode_wp_content(encoded_content, br=False), decoded_content - ) - - def test_preserve_verbatim_formatting(self): - def r(f): - with open(f, encoding="utf-8") as infile: - return infile.read() - - silent_f2p = mute(True)(fields2pelican) - test_post = filter(lambda p: p[0].startswith("Code in List"), self.posts) - with temporary_folder() as temp: - md = next(r(f) for f in silent_f2p(test_post, "markdown", temp)) - self.assertTrue(re.search(r"\s+a = \[1, 2, 3\]", md)) - self.assertTrue(re.search(r"\s+b = \[4, 5, 6\]", md)) - - for_line = re.search(r"\s+for i in zip\(a, b\):", md).group(0) - print_line = re.search(r"\s+print i", md).group(0) - self.assertTrue(for_line.rindex("for") < print_line.rindex("print")) - - def test_code_in_list(self): - def r(f): - with open(f, encoding="utf-8") as infile: - return infile.read() - - silent_f2p = mute(True)(fields2pelican) - test_post = filter(lambda p: p[0].startswith("Code in List"), self.posts) - with temporary_folder() as temp: - md = next(r(f) for f in silent_f2p(test_post, "markdown", temp)) - sample_line = re.search(r"- This is a code sample", md).group(0) - code_line = re.search(r"\s+a = \[1, 2, 3\]", md).group(0) - self.assertTrue(sample_line.rindex("This") < code_line.rindex("a")) - - def test_dont_use_smart_quotes(self): - def r(f): - with open(f, encoding="utf-8") as infile: - return infile.read() - - silent_f2p = mute(True)(fields2pelican) - test_post = filter(lambda p: p[0].startswith("Post with raw data"), self.posts) - with temporary_folder() as temp: - md = next(r(f) for f in silent_f2p(test_post, "markdown", temp)) - escaped_quotes = re.search(r'\\[\'"“”‘’]', md) # noqa: RUF001 - self.assertFalse(escaped_quotes) - - def test_convert_caption_to_figure(self): - def r(f): - with open(f, encoding="utf-8") as infile: - return infile.read() - - silent_f2p = mute(True)(fields2pelican) - test_post = filter(lambda p: p[0].startswith("Caption on image"), self.posts) - with temporary_folder() as temp: - md = next(r(f) for f in silent_f2p(test_post, "markdown", temp)) - - caption = re.search(r"\[caption", md) - self.assertFalse(caption) - - for occurence in [ - "/theme/img/xpelican.png.pagespeed.ic.Rjep0025-y.png", - "/theme/img/xpelican-3.png.pagespeed.ic.m-NAIdRCOM.png", - "/theme/img/xpelican.png.pagespeed.ic.Rjep0025-y.png", - "This is a pelican", - "This also a pelican", - "Yet another pelican", - ]: - # pandoc 2.x converts into ![text](src) - # pandoc 3.x converts into
    src
    text
    - self.assertIn(occurence, md) - - -class TestBuildHeader(unittest.TestCase): - def test_build_header(self): - header = build_header("test", None, None, None, None, None) - self.assertEqual(header, "test\n####\n\n") - - def test_build_header_with_fields(self): - header_data = [ - "Test Post", - "2014-11-04", - "Alexis Métaireau", - ["Programming"], - ["Pelican", "Python"], - "test-post", - ] - - expected_docutils = "\n".join( - [ - "Test Post", - "#########", - ":date: 2014-11-04", - ":author: Alexis Métaireau", - ":category: Programming", - ":tags: Pelican, Python", - ":slug: test-post", - "\n", - ] - ) - - expected_md = "\n".join( - [ - "Title: Test Post", - "Date: 2014-11-04", - "Author: Alexis Métaireau", - "Category: Programming", - "Tags: Pelican, Python", - "Slug: test-post", - "\n", - ] - ) - - self.assertEqual(build_header(*header_data), expected_docutils) - self.assertEqual(build_markdown_header(*header_data), expected_md) - - def test_build_header_with_east_asian_characters(self): - header = build_header( - "これは広い幅の文字だけで構成されたタイトルです", - None, - None, - None, - None, - None, - ) - - self.assertEqual( - header, - ( - "これは広い幅の文字だけで構成されたタイトルです\n" - "##############################################" - "\n\n" - ), - ) - - def test_galleries_added_to_header(self): - header = build_header( - "test", - None, - None, - None, - None, - None, - attachments=["output/test1", "output/test2"], - ) - self.assertEqual( - header, ("test\n####\n:attachments: output/test1, output/test2\n\n") - ) - - def test_galleries_added_to_markdown_header(self): - header = build_markdown_header( - "test", - None, - None, - None, - None, - None, - attachments=["output/test1", "output/test2"], - ) - self.assertEqual( - header, "Title: test\nAttachments: output/test1, output/test2\n\n" - ) - - -@unittest.skipUnless(BeautifulSoup, "Needs BeautifulSoup module") -@unittest.skipUnless(LXML, "Needs lxml module") -class TestWordpressXMLAttachements(TestCaseWithCLocale): - def setUp(self): - super().setUp() - self.attachments = get_attachments(WORDPRESS_XML_SAMPLE) - - def test_recognise_attachments(self): - self.assertTrue(self.attachments) - self.assertEqual(3, len(self.attachments.keys())) - - def test_attachments_associated_with_correct_post(self): - self.assertTrue(self.attachments) - for post in self.attachments.keys(): - if post is None: - expected = { - ( - "https://upload.wikimedia.org/wikipedia/commons/" - "thumb/2/2c/Pelican_lakes_entrance02.jpg/" - "240px-Pelican_lakes_entrance02.jpg" - ) - } - self.assertEqual(self.attachments[post], expected) - elif post == "with-excerpt": - expected_invalid = ( - "http://thisurlisinvalid.notarealdomain/not_an_image.jpg" - ) - expected_pelikan = ( - "http://en.wikipedia.org/wiki/File:Pelikan_Walvis_Bay.jpg" - ) - self.assertEqual( - self.attachments[post], {expected_invalid, expected_pelikan} - ) - elif post == "with-tags": - expected_invalid = "http://thisurlisinvalid.notarealdomain" - self.assertEqual(self.attachments[post], {expected_invalid}) - else: - self.fail(f"all attachments should match to a filename or None, {post}") - - def test_download_attachments(self): - real_file = os.path.join(CUR_DIR, "content/article.rst") - good_url = path_to_file_url(real_file) - bad_url = "http://localhost:1/not_a_file.txt" - silent_da = mute()(download_attachments) - with temporary_folder() as temp: - locations = list(silent_da(temp, [good_url, bad_url])) - self.assertEqual(1, len(locations)) - directory = locations[0] - self.assertTrue( - directory.endswith(posix_join("content", "article.rst")), directory - ) - - -class TestTumblrImporter(TestCaseWithCLocale): - @patch("pelican.tools.pelican_import._get_tumblr_posts") - def test_posts(self, get): - def get_posts(api_key, blogname, offset=0): - if offset > 0: - return [] - - return [ - { - "type": "photo", - "blog_name": "testy", - "date": "2019-11-07 21:26:40 UTC", - "timestamp": 1573162000, - "format": "html", - "slug": "a-slug", - "tags": ["economics"], - "state": "published", - "photos": [ - { - "caption": "", - "original_size": { - "url": "https://..fccdc2360ba7182a.jpg", - "width": 634, - "height": 789, - }, - } - ], - } - ] - - get.side_effect = get_posts - - posts = list(tumblr2fields("api_key", "blogname")) - self.assertEqual( - [ - ( - "Photo", - '\n', - "2019-11-07-a-slug", - "2019-11-07 21:26:40+0000", - "testy", - ["photo"], - ["economics"], - "published", - "article", - "html", - ) - ], - posts, - posts, - ) - - @patch("pelican.tools.pelican_import._get_tumblr_posts") - def test_video_embed(self, get): - def get_posts(api_key, blogname, offset=0): - if offset > 0: - return [] - - return [ - { - "type": "video", - "blog_name": "testy", - "slug": "the-slug", - "date": "2017-07-07 20:31:41 UTC", - "timestamp": 1499459501, - "state": "published", - "format": "html", - "tags": [], - "source_url": "https://href.li/?https://www.youtube.com/a", - "source_title": "youtube.com", - "caption": "

    Caption

    ", - "player": [ - {"width": 250, "embed_code": ""}, - {"width": 400, "embed_code": ""}, - {"width": 500, "embed_code": ""}, - ], - "video_type": "youtube", - } - ] - - get.side_effect = get_posts - - posts = list(tumblr2fields("api_key", "blogname")) - self.assertEqual( - [ - ( - "youtube.com", - '

    via

    \n

    Caption

    ' - "\n" - "\n" - "\n", - "2017-07-07-the-slug", - "2017-07-07 20:31:41+0000", - "testy", - ["video"], - [], - "published", - "article", - "html", - ) - ], - posts, - posts, - ) - - @patch("pelican.tools.pelican_import._get_tumblr_posts") - def test_broken_video_embed(self, get): - def get_posts(api_key, blogname, offset=0): - if offset > 0: - return [] - - return [ - { - "type": "video", - "blog_name": "testy", - "slug": "the-slug", - "date": "2016-08-14 16:37:35 UTC", - "timestamp": 1471192655, - "state": "published", - "format": "html", - "tags": ["interviews"], - "source_url": "https://href.li/?https://www.youtube.com/watch?v=b", - "source_title": "youtube.com", - "caption": "

    Caption

    ", - "player": [ - { - "width": 250, - # If video is gone, embed_code is False - "embed_code": False, - }, - {"width": 400, "embed_code": False}, - {"width": 500, "embed_code": False}, - ], - "video_type": "youtube", - } - ] - - get.side_effect = get_posts - - posts = list(tumblr2fields("api_key", "blogname")) - self.assertEqual( - [ - ( - "youtube.com", - '

    via

    \n

    Caption

    ' - "

    (This video isn't available anymore.)

    \n", - "2016-08-14-the-slug", - "2016-08-14 16:37:35+0000", - "testy", - ["video"], - ["interviews"], - "published", - "article", - "html", - ) - ], - posts, - posts, - ) - - -class TestMediumImporter(TestCaseWithCLocale): - def setUp(self): - super().setUp() - self.test_content_root = "pelican/tests/content" - # The content coming out of parsing is similar, but not the same. - # Beautiful soup rearranges the order of attributes, for example. - # So, we keep a copy of the content for the test. - content_filename = f"{self.test_content_root}/medium_post_content.txt" - with open(content_filename, encoding="utf-8") as the_content_file: - # Many editors and scripts add a final newline, so live with that - # in our test - the_content = the_content_file.read() - assert the_content[-1] == "\n" - the_content = the_content[:-1] - self.post_tuple = ( - "A title", - the_content, - # slug: - "2017-04-21-medium-post", - "2017-04-21 17:11", - "User Name", - None, - (), - "published", - "article", - "html", - ) - - def test_mediumpost2field(self): - """Parse one post""" - post_filename = f"{self.test_content_root}/medium_posts/2017-04-21_-medium-post--d1bf01d62ba3.html" - val = mediumpost2fields(post_filename) - self.assertEqual(self.post_tuple, val, val) - - def test_mediumposts2field(self): - """Parse all posts in an export directory""" - posts = list(mediumposts2fields(f"{self.test_content_root}/medium_posts")) - self.assertEqual(1, len(posts)) - self.assertEqual(self.post_tuple, posts[0]) - - def test_strip_content(self): - """Strip out unhelpful tags""" - html_doc = ( - "
    This keeps lots of tags, but not " - "the
    section
    tags
    " - ) - soup = BeautifulSoup(html_doc, "html.parser") - self.assertEqual( - "This keeps lots of tags, but not the section tags", - strip_medium_post_content(soup), - ) - - def test_medium_slug(self): - # Remove hex stuff at the end - self.assertEqual( - "2017-04-27_A-long-title", - medium_slug( - "medium-export/posts/2017-04-27_A-long-title--2971442227dd.html" - ), - ) - # Remove "--DRAFT" at the end - self.assertEqual( - "2017-04-27_A-long-title", - medium_slug("medium-export/posts/2017-04-27_A-long-title--DRAFT.html"), - ) - # Remove both (which happens) - self.assertEqual( - "draft_How-to-do", medium_slug("draft_How-to-do--DRAFT--87225c81dddd.html") - ) - # If no hex stuff, leave it alone - self.assertEqual( - "2017-04-27_A-long-title", - medium_slug("medium-export/posts/2017-04-27_A-long-title.html"), - ) diff --git a/pelican/tests/test_log.py b/pelican/tests/test_log.py deleted file mode 100644 index 8791fc7c..00000000 --- a/pelican/tests/test_log.py +++ /dev/null @@ -1,75 +0,0 @@ -import logging -import unittest -from collections import defaultdict -from contextlib import contextmanager - -from pelican import log -from pelican.tests.support import LogCountHandler - - -class TestLog(unittest.TestCase): - def setUp(self): - super().setUp() - self.logger = logging.getLogger(__name__) - self.handler = LogCountHandler() - self.logger.addHandler(self.handler) - - def tearDown(self): - self._reset_limit_filter() - super().tearDown() - - def _reset_limit_filter(self): - log.LimitFilter._ignore = set() - log.LimitFilter._raised_messages = set() - log.LimitFilter._threshold = 5 - log.LimitFilter._group_count = defaultdict(int) - - @contextmanager - def reset_logger(self): - try: - yield None - finally: - self._reset_limit_filter() - self.handler.flush() - - def test_log_filter(self): - def do_logging(): - for i in range(5): - self.logger.warning("Log %s", i) - self.logger.warning("Another log %s", i) - - # no filter - with self.reset_logger(): - do_logging() - self.assertEqual(self.handler.count_logs("Log \\d", logging.WARNING), 5) - self.assertEqual( - self.handler.count_logs("Another log \\d", logging.WARNING), 5 - ) - - # filter by template - with self.reset_logger(): - log.LimitFilter._ignore.add((logging.WARNING, "Log %s")) - do_logging() - self.assertEqual(self.handler.count_logs("Log \\d", logging.WARNING), 0) - self.assertEqual( - self.handler.count_logs("Another log \\d", logging.WARNING), 5 - ) - - # filter by exact message - with self.reset_logger(): - log.LimitFilter._ignore.add((logging.WARNING, "Log 3")) - do_logging() - self.assertEqual(self.handler.count_logs("Log \\d", logging.WARNING), 4) - self.assertEqual( - self.handler.count_logs("Another log \\d", logging.WARNING), 5 - ) - - # filter by both - with self.reset_logger(): - log.LimitFilter._ignore.add((logging.WARNING, "Log 3")) - log.LimitFilter._ignore.add((logging.WARNING, "Another log %s")) - do_logging() - self.assertEqual(self.handler.count_logs("Log \\d", logging.WARNING), 4) - self.assertEqual( - self.handler.count_logs("Another log \\d", logging.WARNING), 0 - ) diff --git a/pelican/tests/test_paginator.py b/pelican/tests/test_paginator.py deleted file mode 100644 index 6a7dbe02..00000000 --- a/pelican/tests/test_paginator.py +++ /dev/null @@ -1,114 +0,0 @@ -import locale - -from jinja2.utils import generate_lorem_ipsum - -from pelican.contents import Article, Author -from pelican.paginator import Paginator -from pelican.settings import DEFAULT_CONFIG -from pelican.tests.support import get_settings, unittest - -# generate one paragraph, enclosed with

    -TEST_CONTENT = str(generate_lorem_ipsum(n=1)) -TEST_SUMMARY = generate_lorem_ipsum(n=1, html=False) - - -class TestPage(unittest.TestCase): - def setUp(self): - super().setUp() - self.old_locale = locale.setlocale(locale.LC_ALL) - locale.setlocale(locale.LC_ALL, "C") - self.page_kwargs = { - "content": TEST_CONTENT, - "context": { - "localsiteurl": "", - }, - "metadata": { - "summary": TEST_SUMMARY, - "title": "foo bar", - }, - "source_path": "/path/to/file/foo.ext", - } - - def tearDown(self): - locale.setlocale(locale.LC_ALL, self.old_locale) - - def test_save_as_preservation(self): - settings = get_settings() - # fix up pagination rules - from pelican.paginator import PaginationRule - - pagination_rules = [ - PaginationRule(*r) - for r in settings.get( - "PAGINATION_PATTERNS", - DEFAULT_CONFIG["PAGINATION_PATTERNS"], - ) - ] - settings["PAGINATION_PATTERNS"] = sorted( - pagination_rules, - key=lambda r: r[0], - ) - - self.page_kwargs["metadata"]["author"] = Author("Blogger", settings) - object_list = [Article(**self.page_kwargs), Article(**self.page_kwargs)] - paginator = Paginator("foobar.foo", "foobar/foo", object_list, settings) - page = paginator.page(1) - self.assertEqual(page.save_as, "foobar.foo") - - def test_custom_pagination_pattern(self): - from pelican.paginator import PaginationRule - - settings = get_settings() - settings["PAGINATION_PATTERNS"] = [ - PaginationRule(*r) - for r in [ - (1, "/{url}", "{base_name}/index.html"), - (2, "/{url}{number}/", "{base_name}/{number}/index.html"), - ] - ] - - self.page_kwargs["metadata"]["author"] = Author("Blogger", settings) - object_list = [Article(**self.page_kwargs), Article(**self.page_kwargs)] - paginator = Paginator( - "blog/index.html", "//blog.my.site/", object_list, settings, 1 - ) - # The URL *has to* stay absolute (with // in the front), so verify that - page1 = paginator.page(1) - self.assertEqual(page1.save_as, "blog/index.html") - self.assertEqual(page1.url, "//blog.my.site/") - page2 = paginator.page(2) - self.assertEqual(page2.save_as, "blog/2/index.html") - self.assertEqual(page2.url, "//blog.my.site/2/") - - def test_custom_pagination_pattern_last_page(self): - from pelican.paginator import PaginationRule - - settings = get_settings() - settings["PAGINATION_PATTERNS"] = [ - PaginationRule(*r) - for r in [ - (1, "/{url}1/", "{base_name}/1/index.html"), - (2, "/{url}{number}/", "{base_name}/{number}/index.html"), - (-1, "/{url}", "{base_name}/index.html"), - ] - ] - - self.page_kwargs["metadata"]["author"] = Author("Blogger", settings) - object_list = [ - Article(**self.page_kwargs), - Article(**self.page_kwargs), - Article(**self.page_kwargs), - ] - paginator = Paginator( - "blog/index.html", "//blog.my.site/", object_list, settings, 1 - ) - # The URL *has to* stay absolute (with // in the front), so verify that - page1 = paginator.page(1) - self.assertEqual(page1.save_as, "blog/1/index.html") - self.assertEqual(page1.url, "//blog.my.site/1/") - page2 = paginator.page(2) - self.assertEqual(page2.save_as, "blog/2/index.html") - self.assertEqual(page2.url, "//blog.my.site/2/") - page3 = paginator.page(3) - self.assertEqual(page3.save_as, "blog/index.html") - self.assertEqual(page3.url, "//blog.my.site/") diff --git a/pelican/tests/test_pelican.py b/pelican/tests/test_pelican.py deleted file mode 100644 index a43afa3e..00000000 --- a/pelican/tests/test_pelican.py +++ /dev/null @@ -1,327 +0,0 @@ -import contextlib -import io -import locale -import logging -import os -import subprocess -import sys -import unittest -from collections.abc import Sequence -from shutil import rmtree -from tempfile import TemporaryDirectory, mkdtemp -from unittest.mock import PropertyMock, patch - -from rich.console import Console - -import pelican.readers -from pelican import Pelican, __version__, main -from pelican.generators import StaticGenerator -from pelican.settings import read_settings -from pelican.tests.support import ( - LoggedTestCase, - diff_subproc, - locale_available, - mute, - skipIfNoExecutable, -) - -CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -SAMPLES_PATH = os.path.abspath( - os.path.join(CURRENT_DIR, os.pardir, os.pardir, "samples") -) -OUTPUT_PATH = os.path.abspath(os.path.join(CURRENT_DIR, "output")) - -INPUT_PATH = os.path.join(SAMPLES_PATH, "content") -SAMPLE_CONFIG = os.path.join(SAMPLES_PATH, "pelican.conf.py") -SAMPLE_FR_CONFIG = os.path.join(SAMPLES_PATH, "pelican.conf_FR.py") - - -def recursiveDiff(dcmp): - diff = { - "diff_files": [os.path.join(dcmp.right, f) for f in dcmp.diff_files], - "left_only": [os.path.join(dcmp.right, f) for f in dcmp.left_only], - "right_only": [os.path.join(dcmp.right, f) for f in dcmp.right_only], - } - for sub_dcmp in dcmp.subdirs.values(): - for k, v in recursiveDiff(sub_dcmp).items(): - diff[k] += v - return diff - - -class TestPelican(LoggedTestCase): - # general functional testing for pelican. Basically, this test case tries - # to run pelican in different situations and see how it behaves - - def setUp(self): - super().setUp() - self.temp_path = mkdtemp(prefix="pelicantests.") - self.temp_cache = mkdtemp(prefix="pelican_cache.") - self.maxDiff = None - self.old_locale = locale.setlocale(locale.LC_ALL) - locale.setlocale(locale.LC_ALL, "C") - - def tearDown(self): - read_settings() # cleanup PYGMENTS_RST_OPTIONS - rmtree(self.temp_path) - rmtree(self.temp_cache) - locale.setlocale(locale.LC_ALL, self.old_locale) - super().tearDown() - - def assertDirsEqual(self, left_path, right_path, msg=None): - """ - Check if the files are the same (ignoring whitespace) below both paths. - """ - proc = diff_subproc(left_path, right_path) - - out, err = proc.communicate() - if proc.returncode != 0: - msg = self._formatMessage( - msg, - f"{left_path} and {right_path} differ:\nstdout:\n{out}\nstderr\n{err}", - ) - raise self.failureException(msg) - - def test_order_of_generators(self): - # StaticGenerator must run last, so it can identify files that - # were skipped by the other generators, and so static files can - # have their output paths overridden by the {attach} link syntax. - - pelican = Pelican(settings=read_settings(path=None)) - generator_classes = pelican._get_generator_classes() - - self.assertTrue( - generator_classes[-1] is StaticGenerator, - "StaticGenerator must be the last generator, but it isn't!", - ) - self.assertIsInstance( - generator_classes, - Sequence, - "_get_generator_classes() must return a Sequence to preserve order", - ) - - @skipIfNoExecutable(["git", "--version"]) - def test_basic_generation_works(self): - # when running pelican without settings, it should pick up the default - # ones and generate correct output without raising any exception - settings = read_settings( - path=None, - override={ - "PATH": INPUT_PATH, - "OUTPUT_PATH": self.temp_path, - "CACHE_PATH": self.temp_cache, - "LOCALE": locale.normalize("en_US"), - }, - ) - pelican = Pelican(settings=settings) - mute(True)(pelican.run)() - self.assertDirsEqual(self.temp_path, os.path.join(OUTPUT_PATH, "basic")) - self.assertLogCountEqual( - count=1, - msg="Unable to find.*skipping url replacement", - level=logging.WARNING, - ) - - @skipIfNoExecutable(["git", "--version"]) - def test_custom_generation_works(self): - # the same thing with a specified set of settings should work - settings = read_settings( - path=SAMPLE_CONFIG, - override={ - "PATH": INPUT_PATH, - "OUTPUT_PATH": self.temp_path, - "CACHE_PATH": self.temp_cache, - "LOCALE": locale.normalize("en_US.UTF-8"), - }, - ) - pelican = Pelican(settings=settings) - mute(True)(pelican.run)() - self.assertDirsEqual(self.temp_path, os.path.join(OUTPUT_PATH, "custom")) - - @skipIfNoExecutable(["git", "--version"]) - @unittest.skipUnless( - locale_available("fr_FR.UTF-8") or locale_available("French"), - "French locale needed", - ) - def test_custom_locale_generation_works(self): - """Test that generation with fr_FR.UTF-8 locale works""" - if sys.platform == "win32": - our_locale = "French" - else: - our_locale = "fr_FR.UTF-8" - - settings = read_settings( - path=SAMPLE_FR_CONFIG, - override={ - "PATH": INPUT_PATH, - "OUTPUT_PATH": self.temp_path, - "CACHE_PATH": self.temp_cache, - "LOCALE": our_locale, - }, - ) - pelican = Pelican(settings=settings) - mute(True)(pelican.run)() - self.assertDirsEqual(self.temp_path, os.path.join(OUTPUT_PATH, "custom_locale")) - - def test_theme_static_paths_copy(self): - # the same thing with a specified set of settings should work - settings = read_settings( - path=SAMPLE_CONFIG, - override={ - "PATH": INPUT_PATH, - "OUTPUT_PATH": self.temp_path, - "CACHE_PATH": self.temp_cache, - "THEME_STATIC_PATHS": [ - os.path.join(SAMPLES_PATH, "very"), - os.path.join(SAMPLES_PATH, "kinda"), - os.path.join(SAMPLES_PATH, "theme_standard"), - ], - }, - ) - pelican = Pelican(settings=settings) - mute(True)(pelican.run)() - theme_output = os.path.join(self.temp_path, "theme") - extra_path = os.path.join(theme_output, "exciting", "new", "files") - - for file in ["a_stylesheet", "a_template"]: - self.assertTrue(os.path.exists(os.path.join(theme_output, file))) - - for file in ["wow!", "boom!", "bap!", "zap!"]: - self.assertTrue(os.path.exists(os.path.join(extra_path, file))) - - def test_theme_static_paths_copy_single_file(self): - # the same thing with a specified set of settings should work - settings = read_settings( - path=SAMPLE_CONFIG, - override={ - "PATH": INPUT_PATH, - "OUTPUT_PATH": self.temp_path, - "CACHE_PATH": self.temp_cache, - "THEME_STATIC_PATHS": [os.path.join(SAMPLES_PATH, "theme_standard")], - }, - ) - - pelican = Pelican(settings=settings) - mute(True)(pelican.run)() - theme_output = os.path.join(self.temp_path, "theme") - - for file in ["a_stylesheet", "a_template"]: - self.assertTrue(os.path.exists(os.path.join(theme_output, file))) - - def test_cyclic_intersite_links_no_warnings(self): - settings = read_settings( - path=None, - override={ - "PATH": os.path.join(CURRENT_DIR, "cyclic_intersite_links"), - "OUTPUT_PATH": self.temp_path, - "CACHE_PATH": self.temp_cache, - }, - ) - pelican = Pelican(settings=settings) - mute(True)(pelican.run)() - # There are four different intersite links: - # - one pointing to the second article from first and third - # - one pointing to the first article from second and third - # - one pointing to the third article from first and second - # - one pointing to a nonexistent from each - # If everything goes well, only the warning about the nonexistent - # article should be printed. Only two articles are not sufficient, - # since the first will always have _context['generated_content'] empty - # (thus skipping the link resolving) and the second will always have it - # non-empty, containing the first, thus always succeeding. - self.assertLogCountEqual( - count=1, - msg="Unable to find '.*\\.rst', skipping url replacement.", - level=logging.WARNING, - ) - - def test_md_extensions_deprecation(self): - """Test that a warning is issued if MD_EXTENSIONS is used""" - settings = read_settings( - path=None, - override={ - "PATH": INPUT_PATH, - "OUTPUT_PATH": self.temp_path, - "CACHE_PATH": self.temp_cache, - "MD_EXTENSIONS": {}, - }, - ) - pelican = Pelican(settings=settings) - mute(True)(pelican.run)() - self.assertLogCountEqual( - count=1, - msg="MD_EXTENSIONS is deprecated use MARKDOWN instead.", - level=logging.WARNING, - ) - - def test_parse_errors(self): - # Verify that just an error is printed and the application doesn't - # abort, exit or something. - settings = read_settings( - path=None, - override={ - "PATH": os.path.abspath(os.path.join(CURRENT_DIR, "parse_error")), - "OUTPUT_PATH": self.temp_path, - "CACHE_PATH": self.temp_cache, - }, - ) - pelican = Pelican(settings=settings) - mute(True)(pelican.run)() - self.assertLogCountEqual( - count=1, msg="Could not process .*parse_error.rst", level=logging.ERROR - ) - - def test_module_load(self): - """Test loading via python -m pelican --help displays the help""" - output = subprocess.check_output( - [sys.executable, "-m", "pelican", "--help"] - ).decode("ascii", "replace") - assert "usage:" in output - - def test_main_version(self): - """Run main --version.""" - out = io.StringIO() - with contextlib.redirect_stdout(out): - with self.assertRaises(SystemExit): - main(["--version"]) - self.assertEqual(f"{__version__}\n", out.getvalue()) - - def test_main_help(self): - """Run main --help.""" - out = io.StringIO() - with contextlib.redirect_stdout(out): - with self.assertRaises(SystemExit): - main(["--help"]) - self.assertIn("A tool to generate a static blog", out.getvalue()) - - def test_main_on_content(self): - """Invoke main on simple_content directory.""" - out, err = io.StringIO(), io.StringIO() - with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err): - with TemporaryDirectory() as temp_dir: - # Don't highlight anything. - # See https://rich.readthedocs.io/en/stable/highlighting.html - with patch("pelican.console", new=Console(highlight=False)): - main(["-o", temp_dir, "pelican/tests/simple_content"]) - self.assertIn("Processed 1 article", out.getvalue()) - self.assertEqual("", err.getvalue()) - - def test_main_on_content_markdown_disabled(self): - """Invoke main on simple_content directory.""" - with patch.object( - pelican.readers.MarkdownReader, "enabled", new_callable=PropertyMock - ) as attr_mock: - attr_mock.return_value = False - out, err = io.StringIO(), io.StringIO() - with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err): - with TemporaryDirectory() as temp_dir: - # Don't highlight anything. - # See https://rich.readthedocs.io/en/stable/highlighting.html - with patch("pelican.console", new=Console(highlight=False)): - main(["-o", temp_dir, "pelican/tests/simple_content"]) - self.assertIn("Processed 0 articles", out.getvalue()) - self.assertLogCountEqual( - 1, - ".*article_with_md_extension.md: " - "Could not import 'markdown.Markdown'. " - "Have you installed the 'markdown' package?", - ) diff --git a/pelican/tests/test_plugins.py b/pelican/tests/test_plugins.py deleted file mode 100644 index 69a0384c..00000000 --- a/pelican/tests/test_plugins.py +++ /dev/null @@ -1,286 +0,0 @@ -import os -from contextlib import contextmanager - -from pelican.plugins._utils import ( - get_namespace_plugins, - get_plugin_name, - load_plugins, - plugin_enabled, -) -from pelican.plugins.signals import signal -from pelican.tests.dummy_plugins.normal_plugin import normal_plugin -from pelican.tests.support import unittest - - -@contextmanager -def tmp_namespace_path(path): - """Context manager for temporarily appending namespace plugin packages - - path: path containing the `pelican` folder - - This modifies the `pelican.__path__` and lets the `pelican.plugins` - namespace package resolve it from that. - """ - # This avoids calls to internal `pelican.plugins.__path__._recalculate()` - # as it should not be necessary - import pelican - - old_path = pelican.__path__[:] - try: - pelican.__path__.append(os.path.join(path, "pelican")) - yield - finally: - pelican.__path__ = old_path - - -class PluginTest(unittest.TestCase): - _PLUGIN_FOLDER = os.path.join( - os.path.abspath(os.path.dirname(__file__)), "dummy_plugins" - ) - _NS_PLUGIN_FOLDER = os.path.join(_PLUGIN_FOLDER, "namespace_plugin") - _NORMAL_PLUGIN_FOLDER = os.path.join(_PLUGIN_FOLDER, "normal_plugin") - - def test_namespace_path_modification(self): - import pelican - import pelican.plugins - - old_path = pelican.__path__[:] - - # not existing path - path = os.path.join(self._PLUGIN_FOLDER, "foo") - with tmp_namespace_path(path): - self.assertIn(os.path.join(path, "pelican"), pelican.__path__) - # foo/pelican does not exist, so it won't propagate - self.assertNotIn( - os.path.join(path, "pelican", "plugins"), pelican.plugins.__path__ - ) - # verify that we restored path back - self.assertEqual(pelican.__path__, old_path) - - # existing path - with tmp_namespace_path(self._NS_PLUGIN_FOLDER): - self.assertIn( - os.path.join(self._NS_PLUGIN_FOLDER, "pelican"), pelican.__path__ - ) - # /namespace_plugin/pelican exists, so it should be in - self.assertIn( - os.path.join(self._NS_PLUGIN_FOLDER, "pelican", "plugins"), - pelican.plugins.__path__, - ) - self.assertEqual(pelican.__path__, old_path) - - def test_get_namespace_plugins(self): - # existing namespace plugins - existing_ns_plugins = get_namespace_plugins() - - # with plugin - with tmp_namespace_path(self._NS_PLUGIN_FOLDER): - ns_plugins = get_namespace_plugins() - self.assertEqual(len(ns_plugins), len(existing_ns_plugins) + 1) - self.assertIn("pelican.plugins.ns_plugin", ns_plugins) - self.assertEqual( - ns_plugins["pelican.plugins.ns_plugin"].NAME, "namespace plugin" - ) - - # should be back to existing namespace plugins outside `with` - ns_plugins = get_namespace_plugins() - self.assertEqual(ns_plugins, existing_ns_plugins) - - def test_load_plugins(self): - def get_plugin_names(plugins): - return {get_plugin_name(p) for p in plugins} - - # existing namespace plugins - existing_ns_plugins = load_plugins({}) - - with tmp_namespace_path(self._NS_PLUGIN_FOLDER): - # with no `PLUGINS` setting, load namespace plugins - plugins = load_plugins({}) - self.assertEqual(len(plugins), len(existing_ns_plugins) + 1, plugins) - self.assertEqual( - {"pelican.plugins.ns_plugin"} | get_plugin_names(existing_ns_plugins), - get_plugin_names(plugins), - ) - - # disable namespace plugins with `PLUGINS = []` - SETTINGS = {"PLUGINS": []} - plugins = load_plugins(SETTINGS) - self.assertEqual(len(plugins), 0, plugins) - - # with `PLUGINS`, load only specified plugins - - # normal plugin - SETTINGS = { - "PLUGINS": ["normal_plugin"], - "PLUGIN_PATHS": [self._NORMAL_PLUGIN_FOLDER], - } - plugins = load_plugins(SETTINGS) - self.assertEqual(len(plugins), 1, plugins) - self.assertEqual({"normal_plugin"}, get_plugin_names(plugins)) - - # normal submodule/subpackage plugins - SETTINGS = { - "PLUGINS": [ - "normal_submodule_plugin.subplugin", - "normal_submodule_plugin.subpackage.subpackage", - ], - "PLUGIN_PATHS": [self._NORMAL_PLUGIN_FOLDER], - } - plugins = load_plugins(SETTINGS) - self.assertEqual(len(plugins), 2, plugins) - self.assertEqual( - { - "normal_submodule_plugin.subplugin", - "normal_submodule_plugin.subpackage.subpackage", - }, - get_plugin_names(plugins), - ) - - # ensure normal plugins are loaded only once - SETTINGS = { - "PLUGINS": ["normal_plugin"], - "PLUGIN_PATHS": [self._NORMAL_PLUGIN_FOLDER], - } - plugins = load_plugins(SETTINGS) - for plugin in load_plugins(SETTINGS): - # The second load_plugins() should return the same plugin - # objects as the first one - self.assertIn(plugin, plugins) - - # namespace plugin short - SETTINGS = {"PLUGINS": ["ns_plugin"]} - plugins = load_plugins(SETTINGS) - self.assertEqual(len(plugins), 1, plugins) - self.assertEqual({"pelican.plugins.ns_plugin"}, get_plugin_names(plugins)) - - # namespace plugin long - SETTINGS = {"PLUGINS": ["pelican.plugins.ns_plugin"]} - plugins = load_plugins(SETTINGS) - self.assertEqual(len(plugins), 1, plugins) - self.assertEqual({"pelican.plugins.ns_plugin"}, get_plugin_names(plugins)) - - # normal and namespace plugin - SETTINGS = { - "PLUGINS": ["normal_plugin", "ns_plugin"], - "PLUGIN_PATHS": [self._NORMAL_PLUGIN_FOLDER], - } - plugins = load_plugins(SETTINGS) - self.assertEqual(len(plugins), 2, plugins) - self.assertEqual( - {"normal_plugin", "pelican.plugins.ns_plugin"}, - get_plugin_names(plugins), - ) - - def test_get_plugin_name(self): - self.assertEqual( - get_plugin_name(normal_plugin), - "pelican.tests.dummy_plugins.normal_plugin.normal_plugin", - ) - - class NoopPlugin: - def register(self): - pass - - self.assertEqual( - get_plugin_name(NoopPlugin), - "PluginTest.test_get_plugin_name..NoopPlugin", - ) - self.assertEqual( - get_plugin_name(NoopPlugin()), - "PluginTest.test_get_plugin_name..NoopPlugin", - ) - - def test_plugin_enabled(self): - def get_plugin_names(plugins): - return [get_plugin_name(p) for p in plugins] - - with tmp_namespace_path(self._NS_PLUGIN_FOLDER): - # with no `PLUGINS` setting, load namespace plugins - SETTINGS = {} - plugins = get_plugin_names(load_plugins(SETTINGS)) - self.assertTrue(plugin_enabled("ns_plugin", plugins)) - self.assertTrue(plugin_enabled("pelican.plugins.ns_plugin", plugins)) - self.assertFalse(plugin_enabled("normal_plugin", plugins)) - self.assertFalse(plugin_enabled("unknown", plugins)) - - # disable namespace plugins with `PLUGINS = []` - SETTINGS = {"PLUGINS": []} - plugins = get_plugin_names(load_plugins(SETTINGS)) - self.assertFalse(plugin_enabled("ns_plugin", plugins)) - self.assertFalse(plugin_enabled("pelican.plugins.ns_plugin", plugins)) - self.assertFalse(plugin_enabled("normal_plugin", plugins)) - self.assertFalse(plugin_enabled("unknown", plugins)) - - # with `PLUGINS`, load only specified plugins - - # normal plugin - SETTINGS = { - "PLUGINS": ["normal_plugin"], - "PLUGIN_PATHS": [self._NORMAL_PLUGIN_FOLDER], - } - plugins = get_plugin_names(load_plugins(SETTINGS)) - self.assertFalse(plugin_enabled("ns_plugin", plugins)) - self.assertFalse(plugin_enabled("pelican.plugins.ns_plugin", plugins)) - self.assertTrue(plugin_enabled("normal_plugin", plugins)) - self.assertFalse(plugin_enabled("unknown", plugins)) - - # normal submodule/subpackage plugins - SETTINGS = { - "PLUGINS": [ - "normal_submodule_plugin.subplugin", - "normal_submodule_plugin.subpackage.subpackage", - ], - "PLUGIN_PATHS": [self._NORMAL_PLUGIN_FOLDER], - } - plugins = get_plugin_names(load_plugins(SETTINGS)) - self.assertFalse(plugin_enabled("ns_plugin", plugins)) - self.assertFalse(plugin_enabled("pelican.plugins.ns_plugin", plugins)) - self.assertFalse(plugin_enabled("normal_plugin", plugins)) - self.assertFalse(plugin_enabled("unknown", plugins)) - - # namespace plugin short - SETTINGS = {"PLUGINS": ["ns_plugin"]} - plugins = get_plugin_names(load_plugins(SETTINGS)) - self.assertTrue(plugin_enabled("ns_plugin", plugins)) - self.assertTrue(plugin_enabled("pelican.plugins.ns_plugin", plugins)) - self.assertFalse(plugin_enabled("normal_plugin", plugins)) - self.assertFalse(plugin_enabled("unknown", plugins)) - - # namespace plugin long - SETTINGS = {"PLUGINS": ["pelican.plugins.ns_plugin"]} - plugins = get_plugin_names(load_plugins(SETTINGS)) - self.assertTrue(plugin_enabled("ns_plugin", plugins)) - self.assertTrue(plugin_enabled("pelican.plugins.ns_plugin", plugins)) - self.assertFalse(plugin_enabled("normal_plugin", plugins)) - self.assertFalse(plugin_enabled("unknown", plugins)) - - # normal and namespace plugin - SETTINGS = { - "PLUGINS": ["normal_plugin", "ns_plugin"], - "PLUGIN_PATHS": [self._NORMAL_PLUGIN_FOLDER], - } - plugins = get_plugin_names(load_plugins(SETTINGS)) - self.assertTrue(plugin_enabled("ns_plugin", plugins)) - self.assertTrue(plugin_enabled("pelican.plugins.ns_plugin", plugins)) - self.assertTrue(plugin_enabled("normal_plugin", plugins)) - self.assertFalse(plugin_enabled("unknown", plugins)) - - def test_blinker_is_ordered(self): - """ensure that call order is connetion order""" - dummy_signal = signal("dummpy_signal") - - functions = [] - expected = [] - for i in range(50): - # function appends value of i to a list - def func(input, i=i): - input.append(i) - - functions.append(func) - # we expect functions to be run in the connection order - dummy_signal.connect(func) - expected.append(i) - - input = [] - dummy_signal.send(input) - self.assertEqual(input, expected) diff --git a/pelican/tests/test_readers.py b/pelican/tests/test_readers.py deleted file mode 100644 index 68938a83..00000000 --- a/pelican/tests/test_readers.py +++ /dev/null @@ -1,944 +0,0 @@ -import os -from unittest.mock import PropertyMock, patch - -from pelican import readers -from pelican.tests.support import get_settings, unittest -from pelican.utils import SafeDatetime - -CUR_DIR = os.path.dirname(__file__) -CONTENT_PATH = os.path.join(CUR_DIR, "content") - - -def _path(*args): - return os.path.join(CONTENT_PATH, *args) - - -class ReaderTest(unittest.TestCase): - def read_file(self, path, **kwargs): - # Isolate from future API changes to readers.read_file - - r = readers.Readers(settings=get_settings(**kwargs)) - return r.read_file(base_path=CONTENT_PATH, path=path) - - def assertDictHasSubset(self, dictionary, subset): - for key, value in subset.items(): - if key in dictionary: - real_value = dictionary.get(key) - self.assertEqual( - value, - real_value, - f"Expected {key} to have value {value}, but was {real_value}", - ) - else: - self.fail(f"Expected {key} to have value {value}, but was not in Dict") - - def test_markdown_disabled(self): - with patch.object( - readers.MarkdownReader, "enabled", new_callable=PropertyMock - ) as attr_mock: - attr_mock.return_value = False - readrs = readers.Readers(settings=get_settings()) - self.assertEqual( - set(readers.MarkdownReader.file_extensions), - readrs.disabled_readers.keys(), - ) - for val in readrs.disabled_readers.values(): - self.assertEqual(readers.MarkdownReader, val.__class__) - - -class TestAssertDictHasSubset(ReaderTest): - def setUp(self): - self.dictionary = {"key-a": "val-a", "key-b": "val-b"} - - def tearDown(self): - self.dictionary = None - - def test_subset(self): - self.assertDictHasSubset(self.dictionary, {"key-a": "val-a"}) - - def test_equal(self): - self.assertDictHasSubset(self.dictionary, self.dictionary) - - def test_fail_not_set(self): - self.assertRaisesRegex( - AssertionError, - r"Expected.*key-c.*to have value.*val-c.*but was not in Dict", - self.assertDictHasSubset, - self.dictionary, - {"key-c": "val-c"}, - ) - - def test_fail_wrong_val(self): - self.assertRaisesRegex( - AssertionError, - r"Expected .*key-a.* to have value .*val-b.* but was .*val-a.*", - self.assertDictHasSubset, - self.dictionary, - {"key-a": "val-b"}, - ) - - -class DefaultReaderTest(ReaderTest): - def test_readfile_unknown_extension(self): - with self.assertRaises(TypeError): - self.read_file(path="article_with_metadata.unknownextension") - - def test_readfile_path_metadata_implicit_dates(self): - test_file = "article_with_metadata_implicit_dates.html" - page = self.read_file(path=test_file, DEFAULT_DATE="fs") - expected = { - "date": SafeDatetime.fromtimestamp(os.stat(_path(test_file)).st_mtime), - "modified": SafeDatetime.fromtimestamp(os.stat(_path(test_file)).st_mtime), - } - - self.assertDictHasSubset(page.metadata, expected) - - def test_readfile_path_metadata_explicit_dates(self): - test_file = "article_with_metadata_explicit_dates.html" - page = self.read_file(path=test_file, DEFAULT_DATE="fs") - expected = { - "date": SafeDatetime(2010, 12, 2, 10, 14), - "modified": SafeDatetime(2010, 12, 31, 23, 59), - } - - self.assertDictHasSubset(page.metadata, expected) - - def test_readfile_path_metadata_implicit_date_explicit_modified(self): - test_file = "article_with_metadata_implicit_date_explicit_modified.html" - page = self.read_file(path=test_file, DEFAULT_DATE="fs") - expected = { - "date": SafeDatetime.fromtimestamp(os.stat(_path(test_file)).st_mtime), - "modified": SafeDatetime(2010, 12, 2, 10, 14), - } - - self.assertDictHasSubset(page.metadata, expected) - - def test_readfile_path_metadata_explicit_date_implicit_modified(self): - test_file = "article_with_metadata_explicit_date_implicit_modified.html" - page = self.read_file(path=test_file, DEFAULT_DATE="fs") - expected = { - "date": SafeDatetime(2010, 12, 2, 10, 14), - "modified": SafeDatetime.fromtimestamp(os.stat(_path(test_file)).st_mtime), - } - - self.assertDictHasSubset(page.metadata, expected) - - def test_find_empty_alt(self): - with patch("pelican.readers.logger") as log_mock: - content = [ - '', - '', - ] - - for tag in content: - readers.find_empty_alt(tag, "/test/path") - log_mock.warning.assert_called_with( - "Empty alt attribute for image %s in %s", - "test-image.png", - "/test/path", - extra={"limit_msg": "Other images have empty alt attributes"}, - ) - - -class RstReaderTest(ReaderTest): - def test_article_with_metadata(self): - page = self.read_file(path="article_with_metadata.rst") - expected = { - "category": "yeah", - "author": "Alexis Métaireau", - "title": "This is a super article !", - "summary": '

    Multi-line metadata should be' - " supported\nas well as inline" - " markup and stuff to "typogrify" - ""...

    \n", - "date": SafeDatetime(2010, 12, 2, 10, 14), - "modified": SafeDatetime(2010, 12, 2, 10, 20), - "tags": ["foo", "bar", "foobar"], - "custom_field": "http://notmyidea.org", - } - - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_capitalized_metadata(self): - page = self.read_file(path="article_with_capitalized_metadata.rst") - expected = { - "category": "yeah", - "author": "Alexis Métaireau", - "title": "This is a super article !", - "summary": '

    Multi-line metadata should be' - " supported\nas well as inline" - " markup and stuff to "typogrify" - ""...

    \n", - "date": SafeDatetime(2010, 12, 2, 10, 14), - "modified": SafeDatetime(2010, 12, 2, 10, 20), - "tags": ["foo", "bar", "foobar"], - "custom_field": "http://notmyidea.org", - } - - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_filename_metadata(self): - page = self.read_file( - path="2012-11-29_rst_w_filename_meta#foo-bar.rst", FILENAME_METADATA=None - ) - expected = { - "category": "yeah", - "author": "Alexis Métaireau", - "title": "Rst with filename metadata", - "reader": "rst", - } - self.assertDictHasSubset(page.metadata, expected) - - page = self.read_file( - path="2012-11-29_rst_w_filename_meta#foo-bar.rst", - FILENAME_METADATA=r"(?P\d{4}-\d{2}-\d{2}).*", - ) - expected = { - "category": "yeah", - "author": "Alexis Métaireau", - "title": "Rst with filename metadata", - "date": SafeDatetime(2012, 11, 29), - "reader": "rst", - } - self.assertDictHasSubset(page.metadata, expected) - - page = self.read_file( - path="2012-11-29_rst_w_filename_meta#foo-bar.rst", - FILENAME_METADATA=( - r"(?P\d{4}-\d{2}-\d{2})" - r"_(?P.*)" - r"#(?P.*)-(?P.*)" - ), - ) - expected = { - "category": "yeah", - "author": "Alexis Métaireau", - "title": "Rst with filename metadata", - "date": SafeDatetime(2012, 11, 29), - "slug": "rst_w_filename_meta", - "mymeta": "foo", - "reader": "rst", - } - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_optional_filename_metadata(self): - page = self.read_file( - path="2012-11-29_rst_w_filename_meta#foo-bar.rst", - FILENAME_METADATA=r"(?P\d{4}-\d{2}-\d{2})?", - ) - expected = { - "date": SafeDatetime(2012, 11, 29), - "reader": "rst", - } - self.assertDictHasSubset(page.metadata, expected) - - page = self.read_file( - path="article.rst", FILENAME_METADATA=r"(?P\d{4}-\d{2}-\d{2})?" - ) - expected = { - "reader": "rst", - } - self.assertDictHasSubset(page.metadata, expected) - self.assertNotIn("date", page.metadata, "Date should not be set.") - - def test_article_metadata_key_lowercase(self): - # Keys of metadata should be lowercase. - reader = readers.RstReader(settings=get_settings()) - content, metadata = reader.read(_path("article_with_uppercase_metadata.rst")) - - self.assertIn("category", metadata, "Key should be lowercase.") - self.assertEqual("Yeah", metadata.get("category"), "Value keeps case.") - - def test_article_extra_path_metadata(self): - input_with_metadata = "2012-11-29_rst_w_filename_meta#foo-bar.rst" - page_metadata = self.read_file( - path=input_with_metadata, - FILENAME_METADATA=( - r"(?P\d{4}-\d{2}-\d{2})" - r"_(?P.*)" - r"#(?P.*)-(?P.*)" - ), - EXTRA_PATH_METADATA={ - input_with_metadata: {"key-1a": "value-1a", "key-1b": "value-1b"} - }, - ) - expected_metadata = { - "category": "yeah", - "author": "Alexis Métaireau", - "title": "Rst with filename metadata", - "date": SafeDatetime(2012, 11, 29), - "slug": "rst_w_filename_meta", - "mymeta": "foo", - "reader": "rst", - "key-1a": "value-1a", - "key-1b": "value-1b", - } - self.assertDictHasSubset(page_metadata.metadata, expected_metadata) - - input_file_path_without_metadata = "article.rst" - page_without_metadata = self.read_file( - path=input_file_path_without_metadata, - EXTRA_PATH_METADATA={ - input_file_path_without_metadata: {"author": "Charlès Overwrite"} - }, - ) - expected_without_metadata = { - "category": "misc", - "author": "Charlès Overwrite", - "title": "Article title", - "reader": "rst", - } - self.assertDictHasSubset( - page_without_metadata.metadata, expected_without_metadata - ) - - def test_article_extra_path_metadata_dont_overwrite(self): - # EXTRA_PATH_METADATA['author'] should get ignored - # since we don't overwrite already set values - input_file_path = "2012-11-29_rst_w_filename_meta#foo-bar.rst" - page = self.read_file( - path=input_file_path, - FILENAME_METADATA=( - r"(?P\d{4}-\d{2}-\d{2})" - r"_(?P.*)" - r"#(?P.*)-(?P.*)" - ), - EXTRA_PATH_METADATA={ - input_file_path: {"author": "Charlès Overwrite", "key-1b": "value-1b"} - }, - ) - expected = { - "category": "yeah", - "author": "Alexis Métaireau", - "title": "Rst with filename metadata", - "date": SafeDatetime(2012, 11, 29), - "slug": "rst_w_filename_meta", - "mymeta": "foo", - "reader": "rst", - "key-1b": "value-1b", - } - self.assertDictHasSubset(page.metadata, expected) - - def test_article_extra_path_metadata_recurse(self): - parent = "TestCategory" - notparent = "TestCategory/article" - path = "TestCategory/article_without_category.rst" - - epm = { - parent: { - "epmr_inherit": parent, - "epmr_override": parent, - }, - notparent: {"epmr_bogus": notparent}, - path: { - "epmr_override": path, - }, - } - expected_metadata = { - "epmr_inherit": parent, - "epmr_override": path, - } - - page = self.read_file(path=path, EXTRA_PATH_METADATA=epm) - self.assertDictHasSubset(page.metadata, expected_metadata) - - # Make sure vars aren't getting "inherited" by mistake... - path = "article.rst" - page = self.read_file(path=path, EXTRA_PATH_METADATA=epm) - for k in expected_metadata.keys(): - self.assertNotIn(k, page.metadata) - - # Same, but for edge cases where one file's name is a prefix of - # another. - path = "TestCategory/article_without_category.rst" - page = self.read_file(path=path, EXTRA_PATH_METADATA=epm) - for k in epm[notparent].keys(): - self.assertNotIn(k, page.metadata) - - def test_typogrify(self): - # if nothing is specified in the settings, the content should be - # unmodified - page = self.read_file(path="article.rst") - expected = ( - "

    THIS is some content. With some stuff to " - ""typogrify"...

    \n

    Now with added " - 'support for ' - "TLA.

    \n" - ) - - self.assertEqual(page.content, expected) - - try: - # otherwise, typogrify should be applied - page = self.read_file(path="article.rst", TYPOGRIFY=True) - expected = ( - '

    THIS is some content. ' - "With some stuff to “typogrify”…

    \n" - '

    Now with added support for TLA.

    \n' - ) - - self.assertEqual(page.content, expected) - except ImportError: - return unittest.skip("need the typogrify distribution") - - def test_typogrify_summary(self): - # if nothing is specified in the settings, the summary should be - # unmodified - page = self.read_file(path="article_with_metadata.rst") - expected = ( - '

    Multi-line metadata should be' - " supported\nas well as inline" - " markup and stuff to "typogrify" - ""...

    \n" - ) - - self.assertEqual(page.metadata["summary"], expected) - - try: - # otherwise, typogrify should be applied - page = self.read_file(path="article_with_metadata.rst", TYPOGRIFY=True) - expected = ( - '

    Multi-line metadata should be' - " supported\nas well as inline" - " markup and stuff to “typogrify" - "”…

    \n" - ) - - self.assertEqual(page.metadata["summary"], expected) - except ImportError: - return unittest.skip("need the typogrify distribution") - - def test_typogrify_ignore_tags(self): - try: - # typogrify should be able to ignore user specified tags, - # but tries to be clever with widont extension - page = self.read_file( - path="article.rst", TYPOGRIFY=True, TYPOGRIFY_IGNORE_TAGS=["p"] - ) - expected = ( - "

    THIS is some content. With some stuff to " - ""typogrify"...

    \n

    Now with added " - 'support for ' - "TLA.

    \n" - ) - - self.assertEqual(page.content, expected) - - # typogrify should ignore code blocks by default because - # code blocks are composed inside the pre tag - page = self.read_file(path="article_with_code_block.rst", TYPOGRIFY=True) - - expected = ( - "

    An article with some code

    \n" - '
    '
    -                'x'
    -                ' &'
    -                ' y\n
    \n' - "

    A block quote:

    \n
    \nx " - '& y
    \n' - "

    Normal:\nx" - ' &' - " y" - "

    \n" - ) - - self.assertEqual(page.content, expected) - - # instruct typogrify to also ignore blockquotes - page = self.read_file( - path="article_with_code_block.rst", - TYPOGRIFY=True, - TYPOGRIFY_IGNORE_TAGS=["blockquote"], - ) - - expected = ( - "

    An article with some code

    \n" - '
    '
    -                'x'
    -                ' &'
    -                ' y\n
    \n' - "

    A block quote:

    \n
    \nx " - "& y
    \n" - "

    Normal:\nx" - ' &' - " y" - "

    \n" - ) - - self.assertEqual(page.content, expected) - except ImportError: - return unittest.skip("need the typogrify distribution") - except TypeError: - return unittest.skip("need typogrify version 2.0.4 or later") - - def test_article_with_multiple_authors(self): - page = self.read_file(path="article_with_multiple_authors.rst") - expected = {"authors": ["First Author", "Second Author"]} - - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_multiple_authors_semicolon(self): - page = self.read_file(path="article_with_multiple_authors_semicolon.rst") - expected = {"authors": ["Author, First", "Author, Second"]} - - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_multiple_authors_list(self): - page = self.read_file(path="article_with_multiple_authors_list.rst") - expected = {"authors": ["Author, First", "Author, Second"]} - - self.assertDictHasSubset(page.metadata, expected) - - def test_default_date_formats(self): - tuple_date = self.read_file(path="article.rst", DEFAULT_DATE=(2012, 5, 1)) - string_date = self.read_file(path="article.rst", DEFAULT_DATE="2012-05-01") - - self.assertEqual(tuple_date.metadata["date"], string_date.metadata["date"]) - - def test_parse_error(self): - # Verify that it raises an Exception, not nothing and not SystemExit or - # some such - with self.assertRaisesRegex(Exception, "underline too short"): - self.read_file(path="../parse_error/parse_error.rst") - - def test_typogrify_dashes_config(self): - # Test default config - page = self.read_file( - path="article_with_typogrify_dashes.rst", - TYPOGRIFY=True, - TYPOGRIFY_DASHES="default", - ) - expected = "

    One: -; Two: —; Three: —-

    \n" - expected_title = "One -, two —, three —- dashes!" - - self.assertEqual(page.content, expected) - self.assertEqual(page.title, expected_title) - - # Test 'oldschool' variant - page = self.read_file( - path="article_with_typogrify_dashes.rst", - TYPOGRIFY=True, - TYPOGRIFY_DASHES="oldschool", - ) - expected = "

    One: -; Two: –; Three: —

    \n" - expected_title = "One -, two –, three — dashes!" - - self.assertEqual(page.content, expected) - self.assertEqual(page.title, expected_title) - - # Test 'oldschool_inverted' variant - page = self.read_file( - path="article_with_typogrify_dashes.rst", - TYPOGRIFY=True, - TYPOGRIFY_DASHES="oldschool_inverted", - ) - expected = "

    One: -; Two: —; Three: –

    \n" - expected_title = "One -, two —, three – dashes!" - - self.assertEqual(page.content, expected) - self.assertEqual(page.title, expected_title) - - -@unittest.skipUnless(readers.Markdown, "markdown isn't installed") -class MdReaderTest(ReaderTest): - def test_article_with_metadata(self): - reader = readers.MarkdownReader(settings=get_settings()) - content, metadata = reader.read(_path("article_with_md_extension.md")) - expected = { - "category": "test", - "title": "Test md File", - "summary": "

    I have a lot to test

    ", - "date": SafeDatetime(2010, 12, 2, 10, 14), - "modified": SafeDatetime(2010, 12, 2, 10, 20), - "tags": ["foo", "bar", "foobar"], - } - self.assertDictHasSubset(metadata, expected) - - content, metadata = reader.read( - _path("article_with_markdown_and_nonascii_summary.md") - ) - expected = { - "title": "マックOS X 10.8でパイソンとVirtualenvをインストールと設定", - "summary": "

    パイソンとVirtualenvをまっくでインストールする方法について明確に説明します。

    ", - "category": "指導書", - "date": SafeDatetime(2012, 12, 20), - "modified": SafeDatetime(2012, 12, 22), - "tags": ["パイソン", "マック"], - "slug": "python-virtualenv-on-mac-osx-mountain-lion-10.8", - } - self.assertDictHasSubset(metadata, expected) - - def test_article_with_footnote(self): - settings = get_settings() - ec = settings["MARKDOWN"]["extension_configs"] - ec["markdown.extensions.footnotes"] = {"SEPARATOR": "-"} - reader = readers.MarkdownReader(settings) - content, metadata = reader.read(_path("article_with_markdown_and_footnote.md")) - expected_content = ( - "

    This is some content" - '1" - " with some footnotes" - '2

    \n' - '
    \n' - '
    \n
      \n
    1. \n' - "

      Numbered footnote " - '

      \n' - '
    2. \n
    3. \n' - "

      Named footnote " - '

      \n' - "
    4. \n
    \n
    " - ) - expected_metadata = { - "title": "Article with markdown containing footnotes", - "summary": ( - "

    Summary with inline markup " - "should be supported.

    " - ), - "date": SafeDatetime(2012, 10, 31), - "modified": SafeDatetime(2012, 11, 1), - "multiline": [ - "Line Metadata should be handle properly.", - "See syntax of Meta-Data extension of Python Markdown package:", - "If a line is indented by 4 or more spaces,", - "that line is assumed to be an additional line of the value", - "for the previous keyword.", - "A keyword may have as many lines as desired.", - ], - } - self.assertEqual(content, expected_content) - self.assertDictHasSubset(metadata, expected_metadata) - - def test_article_with_file_extensions(self): - reader = readers.MarkdownReader(settings=get_settings()) - # test to ensure the md file extension is being processed by the - # correct reader - content, metadata = reader.read(_path("article_with_md_extension.md")) - expected = ( - "

    Test Markdown File Header

    \n" - "

    Used for pelican test

    \n" - "

    The quick brown fox jumped over the lazy dog's back.

    " - ) - self.assertEqual(content, expected) - # test to ensure the mkd file extension is being processed by the - # correct reader - content, metadata = reader.read(_path("article_with_mkd_extension.mkd")) - expected = ( - "

    Test Markdown File Header

    \n

    Used for pelican" - " test

    \n

    This is another markdown test file. Uses" - " the mkd extension.

    " - ) - self.assertEqual(content, expected) - # test to ensure the markdown file extension is being processed by the - # correct reader - content, metadata = reader.read( - _path("article_with_markdown_extension.markdown") - ) - expected = ( - "

    Test Markdown File Header

    \n

    Used for pelican" - " test

    \n

    This is another markdown test file. Uses" - " the markdown extension.

    " - ) - self.assertEqual(content, expected) - # test to ensure the mdown file extension is being processed by the - # correct reader - content, metadata = reader.read(_path("article_with_mdown_extension.mdown")) - expected = ( - "

    Test Markdown File Header

    \n

    Used for pelican" - " test

    \n

    This is another markdown test file. Uses" - " the mdown extension.

    " - ) - self.assertEqual(content, expected) - - def test_article_with_markdown_markup_extension(self): - # test to ensure the markdown markup extension is being processed as - # expected - page = self.read_file( - path="article_with_markdown_markup_extensions.md", - MARKDOWN={ - "extension_configs": { - "markdown.extensions.toc": {}, - "markdown.extensions.codehilite": {}, - "markdown.extensions.extra": {}, - } - }, - ) - expected = ( - '
    \n' - "\n" - "
    \n" - '

    Level1

    \n' - '

    Level2

    ' - ) - - self.assertEqual(page.content, expected) - - def test_article_with_filename_metadata(self): - page = self.read_file( - path="2012-11-30_md_w_filename_meta#foo-bar.md", FILENAME_METADATA=None - ) - expected = { - "category": "yeah", - "author": "Alexis Métaireau", - } - self.assertDictHasSubset(page.metadata, expected) - - page = self.read_file( - path="2012-11-30_md_w_filename_meta#foo-bar.md", - FILENAME_METADATA=r"(?P\d{4}-\d{2}-\d{2}).*", - ) - expected = { - "category": "yeah", - "author": "Alexis Métaireau", - "date": SafeDatetime(2012, 11, 30), - } - self.assertDictHasSubset(page.metadata, expected) - - page = self.read_file( - path="2012-11-30_md_w_filename_meta#foo-bar.md", - FILENAME_METADATA=( - r"(?P\d{4}-\d{2}-\d{2})" - r"_(?P.*)" - r"#(?P.*)-(?P.*)" - ), - ) - expected = { - "category": "yeah", - "author": "Alexis Métaireau", - "date": SafeDatetime(2012, 11, 30), - "slug": "md_w_filename_meta", - "mymeta": "foo", - } - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_optional_filename_metadata(self): - page = self.read_file( - path="2012-11-30_md_w_filename_meta#foo-bar.md", - FILENAME_METADATA=r"(?P\d{4}-\d{2}-\d{2})?", - ) - expected = { - "date": SafeDatetime(2012, 11, 30), - "reader": "markdown", - } - self.assertDictHasSubset(page.metadata, expected) - - page = self.read_file( - path="empty.md", FILENAME_METADATA=r"(?P\d{4}-\d{2}-\d{2})?" - ) - expected = { - "reader": "markdown", - } - self.assertDictHasSubset(page.metadata, expected) - self.assertNotIn("date", page.metadata, "Date should not be set.") - - def test_duplicate_tags_or_authors_are_removed(self): - reader = readers.MarkdownReader(settings=get_settings()) - content, metadata = reader.read(_path("article_with_duplicate_tags_authors.md")) - expected = { - "tags": ["foo", "bar", "foobar"], - "authors": ["Author, First", "Author, Second"], - } - self.assertDictHasSubset(metadata, expected) - - def test_metadata_not_parsed_for_metadata(self): - settings = get_settings() - settings["FORMATTED_FIELDS"] = ["summary"] - - reader = readers.MarkdownReader(settings=settings) - content, metadata = reader.read( - _path("article_with_markdown_and_nested_metadata.md") - ) - expected = { - "title": "Article with markdown and nested summary metadata", - "summary": "

    Test: This metadata value looks like metadata

    ", - } - self.assertDictHasSubset(metadata, expected) - - def test_empty_file(self): - reader = readers.MarkdownReader(settings=get_settings()) - content, metadata = reader.read(_path("empty.md")) - - self.assertEqual(metadata, {}) - self.assertEqual(content, "") - - def test_empty_file_with_bom(self): - reader = readers.MarkdownReader(settings=get_settings()) - content, metadata = reader.read(_path("empty_with_bom.md")) - - self.assertEqual(metadata, {}) - self.assertEqual(content, "") - - def test_typogrify_dashes_config(self): - # Test default config - page = self.read_file( - path="article_with_typogrify_dashes.md", - TYPOGRIFY=True, - TYPOGRIFY_DASHES="default", - ) - expected = "

    One: -; Two: —; Three: —-

    " - expected_title = "One -, two —, three —- dashes!" - - self.assertEqual(page.content, expected) - self.assertEqual(page.title, expected_title) - - # Test 'oldschool' variant - page = self.read_file( - path="article_with_typogrify_dashes.md", - TYPOGRIFY=True, - TYPOGRIFY_DASHES="oldschool", - ) - expected = "

    One: -; Two: –; Three: —

    " - expected_title = "One -, two –, three — dashes!" - - self.assertEqual(page.content, expected) - self.assertEqual(page.title, expected_title) - - # Test 'oldschool_inverted' variant - page = self.read_file( - path="article_with_typogrify_dashes.md", - TYPOGRIFY=True, - TYPOGRIFY_DASHES="oldschool_inverted", - ) - expected = "

    One: -; Two: —; Three: –

    " - expected_title = "One -, two —, three – dashes!" - - self.assertEqual(page.content, expected) - self.assertEqual(page.title, expected_title) - - def test_metadata_has_no_discarded_data(self): - md_filename = "article_with_markdown_and_empty_tags.md" - - r = readers.Readers( - cache_name="cache", settings=get_settings(CACHE_CONTENT=True) - ) - page = r.read_file(base_path=CONTENT_PATH, path=md_filename) - - __, cached_metadata = r.get_cached_data(_path(md_filename), (None, None)) - - expected = {"title": "Article with markdown and empty tags"} - self.assertEqual(cached_metadata, expected) - self.assertNotIn("tags", page.metadata) - self.assertDictHasSubset(page.metadata, expected) - - -class HTMLReaderTest(ReaderTest): - def test_article_with_comments(self): - page = self.read_file(path="article_with_comments.html") - - self.assertEqual( - """ - Body content - - """, - page.content, - ) - - def test_article_with_keywords(self): - page = self.read_file(path="article_with_keywords.html") - expected = { - "tags": ["foo", "bar", "foobar"], - } - - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_metadata(self): - page = self.read_file(path="article_with_metadata.html") - expected = { - "category": "yeah", - "author": "Alexis Métaireau", - "title": "This is a super article !", - "summary": "Summary and stuff", - "date": SafeDatetime(2010, 12, 2, 10, 14), - "tags": ["foo", "bar", "foobar"], - "custom_field": "http://notmyidea.org", - } - - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_multiple_similar_metadata_tags(self): - page = self.read_file(path="article_with_multiple_metadata_tags.html") - expected = { - "custom_field": ["https://getpelican.com", "https://www.eff.org"], - } - - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_multiple_authors(self): - page = self.read_file(path="article_with_multiple_authors.html") - expected = {"authors": ["First Author", "Second Author"]} - - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_metadata_and_contents_attrib(self): - page = self.read_file(path="article_with_metadata_and_contents.html") - expected = { - "category": "yeah", - "author": "Alexis Métaireau", - "title": "This is a super article !", - "summary": "Summary and stuff", - "date": SafeDatetime(2010, 12, 2, 10, 14), - "tags": ["foo", "bar", "foobar"], - "custom_field": "http://notmyidea.org", - } - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_null_attributes(self): - page = self.read_file(path="article_with_null_attributes.html") - - self.assertEqual( - """ - Ensure that empty attributes are copied properly. - - """, - page.content, - ) - - def test_article_with_attributes_containing_double_quotes(self): - page = self.read_file( - path="article_with_attributes_containing_" + "double_quotes.html" - ) - self.assertEqual( - """ - Ensure that if an attribute value contains a double quote, it is - surrounded with single quotes, otherwise with double quotes. - Span content - Span content - Span content - """, - page.content, - ) - - def test_article_metadata_key_lowercase(self): - # Keys of metadata should be lowercase. - page = self.read_file(path="article_with_uppercase_metadata.html") - - # Key should be lowercase - self.assertIn("category", page.metadata, "Key should be lowercase.") - - # Value should keep cases - self.assertEqual("Yeah", page.metadata.get("category")) - - def test_article_with_nonconformant_meta_tags(self): - page = self.read_file(path="article_with_nonconformant_meta_tags.html") - expected = { - "summary": "Summary and stuff", - "title": "Article with Nonconformant HTML meta tags", - } - - self.assertDictHasSubset(page.metadata, expected) - - def test_article_with_inline_svg(self): - page = self.read_file(path="article_with_inline_svg.html") - expected = { - "title": "Article with an inline SVG", - } - self.assertDictHasSubset(page.metadata, expected) diff --git a/pelican/tests/test_rstdirectives.py b/pelican/tests/test_rstdirectives.py deleted file mode 100644 index 46ed6f49..00000000 --- a/pelican/tests/test_rstdirectives.py +++ /dev/null @@ -1,31 +0,0 @@ -from unittest.mock import Mock - -from pelican.tests.support import unittest - - -class Test_abbr_role(unittest.TestCase): - def call_it(self, text): - from pelican.rstdirectives import abbr_role - - rawtext = text - lineno = 42 - inliner = Mock(name="inliner") - nodes, system_messages = abbr_role("abbr", rawtext, text, lineno, inliner) - self.assertEqual(system_messages, []) - self.assertEqual(len(nodes), 1) - return nodes[0] - - def test(self): - node = self.call_it("Abbr (Abbreviation)") - self.assertEqual(node.astext(), "Abbr") - self.assertEqual(node["explanation"], "Abbreviation") - - def test_newlines_in_explanation(self): - node = self.call_it("CUL (See you\nlater)") - self.assertEqual(node.astext(), "CUL") - self.assertEqual(node["explanation"], "See you\nlater") - - def test_newlines_in_abbr(self): - node = self.call_it("US of\nA \n (USA)") - self.assertEqual(node.astext(), "US of\nA") - self.assertEqual(node["explanation"], "USA") diff --git a/pelican/tests/test_server.py b/pelican/tests/test_server.py deleted file mode 100644 index fd616ef7..00000000 --- a/pelican/tests/test_server.py +++ /dev/null @@ -1,60 +0,0 @@ -import os -from io import BytesIO -from shutil import rmtree -from tempfile import mkdtemp - -from pelican.server import ComplexHTTPRequestHandler -from pelican.tests.support import unittest - - -class MockRequest: - def makefile(self, *args, **kwargs): - return BytesIO(b"") - - -class MockServer: - pass - - -class TestServer(unittest.TestCase): - def setUp(self): - self.server = MockServer() - self.temp_output = mkdtemp(prefix="pelicantests.") - self.old_cwd = os.getcwd() - os.chdir(self.temp_output) - - def tearDown(self): - os.chdir(self.old_cwd) - rmtree(self.temp_output) - - def test_get_path_that_exists(self): - handler = ComplexHTTPRequestHandler( - MockRequest(), ("0.0.0.0", 8888), self.server - ) - handler.base_path = self.temp_output - - open(os.path.join(self.temp_output, "foo.html"), "a").close() - os.mkdir(os.path.join(self.temp_output, "foo")) - open(os.path.join(self.temp_output, "foo", "index.html"), "a").close() - - os.mkdir(os.path.join(self.temp_output, "bar")) - open(os.path.join(self.temp_output, "bar", "index.html"), "a").close() - - os.mkdir(os.path.join(self.temp_output, "baz")) - - for suffix in ["", "/"]: - # foo.html has precedence over foo/index.html - path = handler.get_path_that_exists("foo" + suffix) - self.assertEqual(path, "foo.html") - - # folder with index.html should return folder/index.html - path = handler.get_path_that_exists("bar" + suffix) - self.assertEqual(path, "bar/index.html") - - # folder without index.html should return same as input - path = handler.get_path_that_exists("baz" + suffix) - self.assertEqual(path, "baz" + suffix) - - # not existing path should return None - path = handler.get_path_that_exists("quux" + suffix) - self.assertIsNone(path) diff --git a/pelican/tests/test_settings.py b/pelican/tests/test_settings.py deleted file mode 100644 index 84f7a5c9..00000000 --- a/pelican/tests/test_settings.py +++ /dev/null @@ -1,323 +0,0 @@ -import copy -import locale -import os -from os.path import abspath, dirname, join - -from pelican.settings import ( - DEFAULT_CONFIG, - DEFAULT_THEME, - _printf_s_to_format_field, - configure_settings, - handle_deprecated_settings, - read_settings, -) -from pelican.tests.support import unittest - - -class TestSettingsConfiguration(unittest.TestCase): - """Provided a file, it should read it, replace the default values, - append new values to the settings (if any), and apply basic settings - optimizations. - """ - - def setUp(self): - self.old_locale = locale.setlocale(locale.LC_ALL) - locale.setlocale(locale.LC_ALL, "C") - self.PATH = abspath(dirname(__file__)) - default_conf = join(self.PATH, "default_conf.py") - self.settings = read_settings(default_conf) - - def tearDown(self): - locale.setlocale(locale.LC_ALL, self.old_locale) - - def test_overwrite_existing_settings(self): - self.assertEqual(self.settings.get("SITENAME"), "Alexis' log") - self.assertEqual(self.settings.get("SITEURL"), "http://blog.notmyidea.org") - - def test_keep_default_settings(self): - # Keep default settings if not defined. - self.assertEqual( - self.settings.get("DEFAULT_CATEGORY"), DEFAULT_CONFIG["DEFAULT_CATEGORY"] - ) - - def test_dont_copy_small_keys(self): - # Do not copy keys not in caps. - self.assertNotIn("foobar", self.settings) - - def test_read_empty_settings(self): - # Ensure an empty settings file results in default settings. - settings = read_settings(None) - expected = copy.deepcopy(DEFAULT_CONFIG) - # Added by configure settings - expected["FEED_DOMAIN"] = "" - expected["ARTICLE_EXCLUDES"] = ["pages"] - expected["PAGE_EXCLUDES"] = [""] - self.maxDiff = None - self.assertDictEqual(settings, expected) - - def test_settings_return_independent(self): - # Make sure that the results from one settings call doesn't - # effect past or future instances. - self.PATH = abspath(dirname(__file__)) - default_conf = join(self.PATH, "default_conf.py") - settings = read_settings(default_conf) - settings["SITEURL"] = "new-value" - new_settings = read_settings(default_conf) - self.assertNotEqual(new_settings["SITEURL"], settings["SITEURL"]) - - def test_defaults_not_overwritten(self): - # This assumes 'SITENAME': 'A Pelican Blog' - settings = read_settings(None) - settings["SITENAME"] = "Not a Pelican Blog" - self.assertNotEqual(settings["SITENAME"], DEFAULT_CONFIG["SITENAME"]) - - def test_static_path_settings_safety(self): - # Disallow static paths from being strings - settings = { - "STATIC_PATHS": "foo/bar", - "THEME_STATIC_PATHS": "bar/baz", - # These 4 settings are required to run configure_settings - "PATH": ".", - "THEME": DEFAULT_THEME, - "SITEURL": "http://blog.notmyidea.org/", - "LOCALE": "", - } - configure_settings(settings) - self.assertEqual(settings["STATIC_PATHS"], DEFAULT_CONFIG["STATIC_PATHS"]) - self.assertEqual( - settings["THEME_STATIC_PATHS"], DEFAULT_CONFIG["THEME_STATIC_PATHS"] - ) - - def test_configure_settings(self): - # Manipulations to settings should be applied correctly. - settings = { - "SITEURL": "http://blog.notmyidea.org/", - "LOCALE": "", - "PATH": os.curdir, - "THEME": DEFAULT_THEME, - } - configure_settings(settings) - - # SITEURL should not have a trailing slash - self.assertEqual(settings["SITEURL"], "http://blog.notmyidea.org") - - # FEED_DOMAIN, if undefined, should default to SITEURL - self.assertEqual(settings["FEED_DOMAIN"], "http://blog.notmyidea.org") - - settings["FEED_DOMAIN"] = "http://feeds.example.com" - configure_settings(settings) - self.assertEqual(settings["FEED_DOMAIN"], "http://feeds.example.com") - - def test_theme_settings_exceptions(self): - settings = self.settings - - # Check that theme lookup in "pelican/themes" functions as expected - settings["THEME"] = os.path.split(settings["THEME"])[1] - configure_settings(settings) - self.assertEqual(settings["THEME"], DEFAULT_THEME) - - # Check that non-existent theme raises exception - settings["THEME"] = "foo" - self.assertRaises(Exception, configure_settings, settings) - - def test_deprecated_dir_setting(self): - settings = self.settings - - settings["ARTICLE_DIR"] = "foo" - settings["PAGE_DIR"] = "bar" - - settings = handle_deprecated_settings(settings) - - self.assertEqual(settings["ARTICLE_PATHS"], ["foo"]) - self.assertEqual(settings["PAGE_PATHS"], ["bar"]) - - with self.assertRaises(KeyError): - settings["ARTICLE_DIR"] - settings["PAGE_DIR"] - - def test_default_encoding(self): - # Test that the user locale is set if not specified in settings - - locale.setlocale(locale.LC_ALL, "C") - # empty string = user system locale - self.assertEqual(self.settings["LOCALE"], [""]) - - configure_settings(self.settings) - lc_time = locale.getlocale(locale.LC_TIME) # should be set to user locale - - # explicitly set locale to user pref and test - locale.setlocale(locale.LC_TIME, "") - self.assertEqual(lc_time, locale.getlocale(locale.LC_TIME)) - - def test_invalid_settings_throw_exception(self): - # Test that the path name is valid - - # test that 'PATH' is set - settings = {} - - self.assertRaises(Exception, configure_settings, settings) - - # Test that 'PATH' is valid - settings["PATH"] = "" - self.assertRaises(Exception, configure_settings, settings) - - # Test nonexistent THEME - settings["PATH"] = os.curdir - settings["THEME"] = "foo" - - self.assertRaises(Exception, configure_settings, settings) - - def test__printf_s_to_format_field(self): - for s in ("%s", "{%s}", "{%s"): - option = f"foo/{s}/bar.baz" - result = _printf_s_to_format_field(option, "slug") - expected = option % "qux" - found = result.format(slug="qux") - self.assertEqual(expected, found) - - def test_deprecated_extra_templates_paths(self): - settings = self.settings - settings["EXTRA_TEMPLATES_PATHS"] = ["/foo/bar", "/ha"] - - settings = handle_deprecated_settings(settings) - - self.assertEqual(settings["THEME_TEMPLATES_OVERRIDES"], ["/foo/bar", "/ha"]) - self.assertNotIn("EXTRA_TEMPLATES_PATHS", settings) - - def test_deprecated_paginated_direct_templates(self): - settings = self.settings - settings["PAGINATED_DIRECT_TEMPLATES"] = ["index", "archives"] - settings["PAGINATED_TEMPLATES"] = {"index": 10, "category": None} - settings = handle_deprecated_settings(settings) - self.assertEqual( - settings["PAGINATED_TEMPLATES"], - {"index": 10, "category": None, "archives": None}, - ) - self.assertNotIn("PAGINATED_DIRECT_TEMPLATES", settings) - - def test_deprecated_paginated_direct_templates_from_file(self): - # This is equivalent to reading a settings file that has - # PAGINATED_DIRECT_TEMPLATES defined but no PAGINATED_TEMPLATES. - settings = read_settings( - None, override={"PAGINATED_DIRECT_TEMPLATES": ["index", "archives"]} - ) - self.assertEqual( - settings["PAGINATED_TEMPLATES"], - { - "archives": None, - "author": None, - "index": None, - "category": None, - "tag": None, - }, - ) - self.assertNotIn("PAGINATED_DIRECT_TEMPLATES", settings) - - def test_theme_and_extra_templates_exception(self): - settings = self.settings - settings["EXTRA_TEMPLATES_PATHS"] = ["/ha"] - settings["THEME_TEMPLATES_OVERRIDES"] = ["/foo/bar"] - - self.assertRaises(Exception, handle_deprecated_settings, settings) - - def test_slug_and_slug_regex_substitutions_exception(self): - settings = {} - settings["SLUG_REGEX_SUBSTITUTIONS"] = [("C++", "cpp")] - settings["TAG_SUBSTITUTIONS"] = [("C#", "csharp")] - - self.assertRaises(Exception, handle_deprecated_settings, settings) - - def test_deprecated_slug_substitutions(self): - default_slug_regex_subs = self.settings["SLUG_REGEX_SUBSTITUTIONS"] - - # If no deprecated setting is set, don't set new ones - settings = {} - settings = handle_deprecated_settings(settings) - self.assertNotIn("SLUG_REGEX_SUBSTITUTIONS", settings) - self.assertNotIn("TAG_REGEX_SUBSTITUTIONS", settings) - self.assertNotIn("CATEGORY_REGEX_SUBSTITUTIONS", settings) - self.assertNotIn("AUTHOR_REGEX_SUBSTITUTIONS", settings) - - # If SLUG_SUBSTITUTIONS is set, set {SLUG, AUTHOR}_REGEX_SUBSTITUTIONS - # correctly, don't set {CATEGORY, TAG}_REGEX_SUBSTITUTIONS - settings = {} - settings["SLUG_SUBSTITUTIONS"] = [("C++", "cpp")] - settings = handle_deprecated_settings(settings) - self.assertEqual( - settings.get("SLUG_REGEX_SUBSTITUTIONS"), - [(r"C\+\+", "cpp")] + default_slug_regex_subs, - ) - self.assertNotIn("TAG_REGEX_SUBSTITUTIONS", settings) - self.assertNotIn("CATEGORY_REGEX_SUBSTITUTIONS", settings) - self.assertEqual( - settings.get("AUTHOR_REGEX_SUBSTITUTIONS"), default_slug_regex_subs - ) - - # If {CATEGORY, TAG, AUTHOR}_SUBSTITUTIONS are set, set - # {CATEGORY, TAG, AUTHOR}_REGEX_SUBSTITUTIONS correctly, don't set - # SLUG_REGEX_SUBSTITUTIONS - settings = {} - settings["TAG_SUBSTITUTIONS"] = [("C#", "csharp")] - settings["CATEGORY_SUBSTITUTIONS"] = [("C#", "csharp")] - settings["AUTHOR_SUBSTITUTIONS"] = [("Alexander Todorov", "atodorov")] - settings = handle_deprecated_settings(settings) - self.assertNotIn("SLUG_REGEX_SUBSTITUTIONS", settings) - self.assertEqual( - settings["TAG_REGEX_SUBSTITUTIONS"], - [(r"C\#", "csharp")] + default_slug_regex_subs, - ) - self.assertEqual( - settings["CATEGORY_REGEX_SUBSTITUTIONS"], - [(r"C\#", "csharp")] + default_slug_regex_subs, - ) - self.assertEqual( - settings["AUTHOR_REGEX_SUBSTITUTIONS"], - [(r"Alexander\ Todorov", "atodorov")] + default_slug_regex_subs, - ) - - # If {SLUG, CATEGORY, TAG, AUTHOR}_SUBSTITUTIONS are set, set - # {SLUG, CATEGORY, TAG, AUTHOR}_REGEX_SUBSTITUTIONS correctly - settings = {} - settings["SLUG_SUBSTITUTIONS"] = [("C++", "cpp")] - settings["TAG_SUBSTITUTIONS"] = [("C#", "csharp")] - settings["CATEGORY_SUBSTITUTIONS"] = [("C#", "csharp")] - settings["AUTHOR_SUBSTITUTIONS"] = [("Alexander Todorov", "atodorov")] - settings = handle_deprecated_settings(settings) - self.assertEqual( - settings["TAG_REGEX_SUBSTITUTIONS"], - [(r"C\+\+", "cpp")] + [(r"C\#", "csharp")] + default_slug_regex_subs, - ) - self.assertEqual( - settings["CATEGORY_REGEX_SUBSTITUTIONS"], - [(r"C\+\+", "cpp")] + [(r"C\#", "csharp")] + default_slug_regex_subs, - ) - self.assertEqual( - settings["AUTHOR_REGEX_SUBSTITUTIONS"], - [(r"Alexander\ Todorov", "atodorov")] + default_slug_regex_subs, - ) - - # Handle old 'skip' flags correctly - settings = {} - settings["SLUG_SUBSTITUTIONS"] = [("C++", "cpp", True)] - settings["AUTHOR_SUBSTITUTIONS"] = [("Alexander Todorov", "atodorov", False)] - settings = handle_deprecated_settings(settings) - self.assertEqual( - settings.get("SLUG_REGEX_SUBSTITUTIONS"), - [(r"C\+\+", "cpp")] + [(r"(?u)\A\s*", ""), (r"(?u)\s*\Z", "")], - ) - self.assertEqual( - settings["AUTHOR_REGEX_SUBSTITUTIONS"], - [(r"Alexander\ Todorov", "atodorov")] + default_slug_regex_subs, - ) - - def test_deprecated_slug_substitutions_from_file(self): - # This is equivalent to reading a settings file that has - # SLUG_SUBSTITUTIONS defined but no SLUG_REGEX_SUBSTITUTIONS. - settings = read_settings( - None, override={"SLUG_SUBSTITUTIONS": [("C++", "cpp")]} - ) - self.assertEqual( - settings["SLUG_REGEX_SUBSTITUTIONS"], - [(r"C\+\+", "cpp")] + self.settings["SLUG_REGEX_SUBSTITUTIONS"], - ) - self.assertNotIn("SLUG_SUBSTITUTIONS", settings) diff --git a/pelican/tests/test_testsuite.py b/pelican/tests/test_testsuite.py deleted file mode 100644 index 938d2bdf..00000000 --- a/pelican/tests/test_testsuite.py +++ /dev/null @@ -1,9 +0,0 @@ -import warnings - -from pelican.tests.support import unittest - - -class TestSuiteTest(unittest.TestCase): - def test_error_on_warning(self): - with self.assertRaises(UserWarning): - warnings.warn("test warning") # noqa: B028 diff --git a/pelican/tests/test_urlwrappers.py b/pelican/tests/test_urlwrappers.py deleted file mode 100644 index 13632e3a..00000000 --- a/pelican/tests/test_urlwrappers.py +++ /dev/null @@ -1,96 +0,0 @@ -from pelican.tests.support import unittest -from pelican.urlwrappers import Author, Category, Tag, URLWrapper - - -class TestURLWrapper(unittest.TestCase): - def test_ordering(self): - # URLWrappers are sorted by name - wrapper_a = URLWrapper(name="first", settings={}) - wrapper_b = URLWrapper(name="last", settings={}) - self.assertFalse(wrapper_a > wrapper_b) - self.assertFalse(wrapper_a >= wrapper_b) - self.assertFalse(wrapper_a == wrapper_b) - self.assertTrue(wrapper_a != wrapper_b) - self.assertTrue(wrapper_a <= wrapper_b) - self.assertTrue(wrapper_a < wrapper_b) - wrapper_b.name = "first" - self.assertFalse(wrapper_a > wrapper_b) - self.assertTrue(wrapper_a >= wrapper_b) - self.assertTrue(wrapper_a == wrapper_b) - self.assertFalse(wrapper_a != wrapper_b) - self.assertTrue(wrapper_a <= wrapper_b) - self.assertFalse(wrapper_a < wrapper_b) - wrapper_a.name = "last" - self.assertTrue(wrapper_a > wrapper_b) - self.assertTrue(wrapper_a >= wrapper_b) - self.assertFalse(wrapper_a == wrapper_b) - self.assertTrue(wrapper_a != wrapper_b) - self.assertFalse(wrapper_a <= wrapper_b) - self.assertFalse(wrapper_a < wrapper_b) - - def test_equality(self): - tag = Tag("test", settings={}) - cat = Category("test", settings={}) - author = Author("test", settings={}) - - # same name, but different class - self.assertNotEqual(tag, cat) - self.assertNotEqual(tag, author) - - # should be equal vs text representing the same name - self.assertEqual(tag, "test") - - # should not be equal vs binary - self.assertNotEqual(tag, b"test") - - # Tags describing the same should be equal - tag_equal = Tag("Test", settings={}) - self.assertEqual(tag, tag_equal) - - # Author describing the same should be equal - author_equal = Author("Test", settings={}) - self.assertEqual(author, author_equal) - - cat_ascii = Category("指導書", settings={}) - self.assertEqual(cat_ascii, "zhi dao shu") - - def test_slugify_with_substitutions_and_dots(self): - tag = Tag( - "Tag Dot", - settings={ - "TAG_REGEX_SUBSTITUTIONS": [ - ("Tag Dot", "tag.dot"), - ] - }, - ) - cat = Category( - "Category Dot", - settings={ - "CATEGORY_REGEX_SUBSTITUTIONS": [ - ("Category Dot", "cat.dot"), - ] - }, - ) - - self.assertEqual(tag.slug, "tag.dot") - self.assertEqual(cat.slug, "cat.dot") - - def test_author_slug_substitutions(self): - settings = { - "AUTHOR_REGEX_SUBSTITUTIONS": [ - ("Alexander Todorov", "atodorov"), - ("Krasimir Tsonev", "krasimir"), - (r"[^\w\s-]", ""), - (r"(?u)\A\s*", ""), - (r"(?u)\s*\Z", ""), - (r"[-\s]+", "-"), - ] - } - - author1 = Author("Mr. Senko", settings=settings) - author2 = Author("Alexander Todorov", settings=settings) - author3 = Author("Krasimir Tsonev", settings=settings) - - self.assertEqual(author1.slug, "mr-senko") - self.assertEqual(author2.slug, "atodorov") - self.assertEqual(author3.slug, "krasimir") diff --git a/pelican/tests/test_utils.py b/pelican/tests/test_utils.py deleted file mode 100644 index c35b756c..00000000 --- a/pelican/tests/test_utils.py +++ /dev/null @@ -1,992 +0,0 @@ -import locale -import logging -import os -import shutil -from datetime import timezone -from sys import platform -from tempfile import mkdtemp - -try: - from zoneinfo import ZoneInfo -except ModuleNotFoundError: - from backports.zoneinfo import ZoneInfo - -from pelican import utils -from pelican.generators import TemplatePagesGenerator -from pelican.settings import read_settings -from pelican.tests.support import ( - LoggedTestCase, - get_article, - locale_available, - unittest, -) -from pelican.writers import Writer - - -class ClassDeprAttr: - _new_attribute = "new_value" - - @utils.deprecated_attribute( - old="_old_attribute", new="_new_attribute", since=(3, 1, 0), remove=(4, 1, 3) - ) - def _old_attribute(): - return None - - -class TestUtils(LoggedTestCase): - def setUp(self): - super().setUp() - self.temp_output = mkdtemp(prefix="pelicantests.") - - def tearDown(self): - super().tearDown() - shutil.rmtree(self.temp_output) - - def test_deprecated_attribute(self): - test_class = ClassDeprAttr() - value = test_class._old_attribute - self.assertEqual(value, test_class._new_attribute) - self.assertLogCountEqual( - count=1, - msg=( - "_old_attribute has been deprecated since 3.1.0 and will be " - "removed by version 4.1.3. Use _new_attribute instead" - ), - level=logging.WARNING, - ) - - def test_get_date(self): - # valid ones - date = utils.SafeDatetime(year=2012, month=11, day=22) - date_hour = utils.SafeDatetime(year=2012, month=11, day=22, hour=22, minute=11) - date_hour_z = utils.SafeDatetime( - year=2012, month=11, day=22, hour=22, minute=11, tzinfo=timezone.utc - ) - date_hour_est = utils.SafeDatetime( - year=2012, month=11, day=22, hour=22, minute=11, tzinfo=ZoneInfo("EST") - ) - date_hour_sec = utils.SafeDatetime( - year=2012, month=11, day=22, hour=22, minute=11, second=10 - ) - date_hour_sec_z = utils.SafeDatetime( - year=2012, - month=11, - day=22, - hour=22, - minute=11, - second=10, - tzinfo=timezone.utc, - ) - date_hour_sec_est = utils.SafeDatetime( - year=2012, - month=11, - day=22, - hour=22, - minute=11, - second=10, - tzinfo=ZoneInfo("EST"), - ) - date_hour_sec_frac_z = utils.SafeDatetime( - year=2012, - month=11, - day=22, - hour=22, - minute=11, - second=10, - microsecond=123000, - tzinfo=timezone.utc, - ) - dates = { - "2012-11-22": date, - "2012/11/22": date, - "2012-11-22 22:11": date_hour, - "2012/11/22 22:11": date_hour, - "22-11-2012": date, - "22/11/2012": date, - "22.11.2012": date, - "22.11.2012 22:11": date_hour, - "2012-11-22T22:11Z": date_hour_z, - "2012-11-22T22:11-0500": date_hour_est, - "2012-11-22 22:11:10": date_hour_sec, - "2012-11-22T22:11:10Z": date_hour_sec_z, - "2012-11-22T22:11:10-0500": date_hour_sec_est, - "2012-11-22T22:11:10.123Z": date_hour_sec_frac_z, - } - - # examples from http://www.w3.org/TR/NOTE-datetime - iso_8601_date = utils.SafeDatetime(year=1997, month=7, day=16) - iso_8601_date_hour_tz = utils.SafeDatetime( - year=1997, - month=7, - day=16, - hour=19, - minute=20, - tzinfo=ZoneInfo("Europe/London"), - ) - iso_8601_date_hour_sec_tz = utils.SafeDatetime( - year=1997, - month=7, - day=16, - hour=19, - minute=20, - second=30, - tzinfo=ZoneInfo("Europe/London"), - ) - iso_8601_date_hour_sec_ms_tz = utils.SafeDatetime( - year=1997, - month=7, - day=16, - hour=19, - minute=20, - second=30, - microsecond=450000, - tzinfo=ZoneInfo("Europe/London"), - ) - iso_8601 = { - "1997-07-16": iso_8601_date, - "1997-07-16T19:20+01:00": iso_8601_date_hour_tz, - "1997-07-16T19:20:30+01:00": iso_8601_date_hour_sec_tz, - "1997-07-16T19:20:30.45+01:00": iso_8601_date_hour_sec_ms_tz, - } - - # invalid ones - invalid_dates = ["2010-110-12", "yay"] - - for value, expected in dates.items(): - self.assertEqual(utils.get_date(value), expected, value) - - for value, expected in iso_8601.items(): - self.assertEqual(utils.get_date(value), expected, value) - - for item in invalid_dates: - self.assertRaises(ValueError, utils.get_date, item) - - def test_slugify(self): - samples = ( - ("this is a test", "this-is-a-test"), - ("this is a test", "this-is-a-test"), - ("this → is ← a ↑ test", "this-is-a-test"), - ("this--is---a test", "this-is-a-test"), - ( - "unicode測試許功蓋,你看到了嗎?", - "unicodece-shi-xu-gong-gai-ni-kan-dao-liao-ma", - ), - ( - "大飯原発4号機、18日夜起動へ", - "da-fan-yuan-fa-4hao-ji-18ri-ye-qi-dong-he", - ), - ) - - settings = read_settings() - subs = settings["SLUG_REGEX_SUBSTITUTIONS"] - - for value, expected in samples: - self.assertEqual(utils.slugify(value, regex_subs=subs), expected) - - self.assertEqual(utils.slugify("Cat", regex_subs=subs), "cat") - self.assertEqual( - utils.slugify("Cat", regex_subs=subs, preserve_case=False), "cat" - ) - self.assertEqual( - utils.slugify("Cat", regex_subs=subs, preserve_case=True), "Cat" - ) - - def test_slugify_use_unicode(self): - samples = ( - ("this is a test", "this-is-a-test"), - ("this is a test", "this-is-a-test"), - ("this → is ← a ↑ test", "this-is-a-test"), - ("this--is---a test", "this-is-a-test"), - ("unicode測試許功蓋,你看到了嗎?", "unicode測試許功蓋你看到了嗎"), - ("Çığ", "çığ"), - ) - - settings = read_settings() - subs = settings["SLUG_REGEX_SUBSTITUTIONS"] - - for value, expected in samples: - self.assertEqual( - utils.slugify(value, regex_subs=subs, use_unicode=True), expected - ) - - # check with preserve case - self.assertEqual( - utils.slugify("Çığ", regex_subs=subs, preserve_case=True, use_unicode=True), - "Çığ", - ) - - # check normalization - samples = ( - ("大飯原発4号機、18日夜起動へ", "大飯原発4号機18日夜起動へ"), - ( - "\N{LATIN SMALL LETTER C}\N{COMBINING CEDILLA}", - "\N{LATIN SMALL LETTER C WITH CEDILLA}", - ), - ) - for value, expected in samples: - self.assertEqual( - utils.slugify(value, regex_subs=subs, use_unicode=True), expected - ) - - def test_slugify_substitute(self): - samples = ( - ("C++ is based on C", "cpp-is-based-on-c"), - ("C+++ test C+ test", "cpp-test-c-test"), - ("c++, c#, C#, C++", "cpp-c-sharp-c-sharp-cpp"), - ("c++-streams", "cpp-streams"), - ) - - settings = read_settings() - subs = [ - (r"C\+\+", "CPP"), - (r"C#", "C-SHARP"), - ] + settings["SLUG_REGEX_SUBSTITUTIONS"] - for value, expected in samples: - self.assertEqual(utils.slugify(value, regex_subs=subs), expected) - - def test_slugify_substitute_and_keeping_non_alphanum(self): - samples = ( - ("Fedora QA", "fedora.qa"), - ("C++ is used by Fedora QA", "cpp is used by fedora.qa"), - ("C++ is based on C", "cpp is based on c"), - ("C+++ test C+ test", "cpp+ test c+ test"), - ) - - subs = [ - (r"Fedora QA", "fedora.qa"), - (r"c\+\+", "cpp"), - ] - for value, expected in samples: - self.assertEqual(utils.slugify(value, regex_subs=subs), expected) - - def test_get_relative_path(self): - samples = ( - (os.path.join("test", "test.html"), os.pardir), - ( - os.path.join("test", "test", "test.html"), - os.path.join(os.pardir, os.pardir), - ), - ("test.html", os.curdir), - (os.path.join("/test", "test.html"), os.pardir), - ( - os.path.join("/test", "test", "test.html"), - os.path.join(os.pardir, os.pardir), - ), - ("/test.html", os.curdir), - ) - - for value, expected in samples: - self.assertEqual(utils.get_relative_path(value), expected) - - def test_truncate_html_words(self): - # Plain text. - self.assertEqual(utils.truncate_html_words("short string", 20), "short string") - self.assertEqual( - utils.truncate_html_words("word " * 100, 20), "word " * 20 + "…" - ) - - # Plain text with Unicode content. - self.assertEqual( - utils.truncate_html_words( - "我愿意这样,朋友——我独自远行,不但没有你,\ - 并且再没有别的影在黑暗里。", - 12, - ), - "我愿意这样,朋友——我独自远行" + " …", - ) - self.assertEqual( - utils.truncate_html_words( - "Ты мелькнула, ты предстала, Снова сердце задрожало,", 3 - ), - "Ты мелькнула, ты" + " …", - ) - self.assertEqual( - utils.truncate_html_words("Trong đầm gì đẹp bằng sen", 4), - "Trong đầm gì đẹp" + " …", - ) - - # Words enclosed or intervaled by HTML tags. - self.assertEqual( - utils.truncate_html_words("

    " + "word " * 100 + "

    ", 20), - "

    " + "word " * 20 + "…

    ", - ) - self.assertEqual( - utils.truncate_html_words( - '' + "word " * 100 + "", 20 - ), - '' + "word " * 20 + "…", - ) - self.assertEqual( - utils.truncate_html_words("
    " + "word " * 100, 20), - "
    " + "word " * 20 + "…", - ) - self.assertEqual( - utils.truncate_html_words("" + "word " * 100, 20), - "" + "word " * 20 + "…", - ) - - # Words enclosed or intervaled by HTML tags with a custom end - # marker containing HTML tags. - self.assertEqual( - utils.truncate_html_words( - "

    " + "word " * 100 + "

    ", 20, "marker" - ), - "

    " + "word " * 20 + "marker

    ", - ) - self.assertEqual( - utils.truncate_html_words( - '' + "word " * 100 + "", - 20, - "marker", - ), - '' + "word " * 20 + "marker", - ) - self.assertEqual( - utils.truncate_html_words( - "
    " + "word " * 100, 20, "marker" - ), - "
    " + "word " * 20 + "marker", - ) - self.assertEqual( - utils.truncate_html_words( - "" + "word " * 100, 20, "marker" - ), - "" + "word " * 20 + "marker", - ) - - # Words with hypens and apostrophes. - self.assertEqual(utils.truncate_html_words("a-b " * 100, 20), "a-b " * 20 + "…") - self.assertEqual( - utils.truncate_html_words("it's " * 100, 20), "it's " * 20 + "…" - ) - - # Words with HTML entity references. - self.assertEqual( - utils.truncate_html_words("é " * 100, 20), "é " * 20 + "…" - ) - self.assertEqual( - utils.truncate_html_words("café " * 100, 20), - "café " * 20 + "…", - ) - self.assertEqual( - utils.truncate_html_words("èlite " * 100, 20), - "èlite " * 20 + "…", - ) - self.assertEqual( - utils.truncate_html_words("cafetiére " * 100, 20), - "cafetiére " * 20 + "…", - ) - self.assertEqual( - utils.truncate_html_words("∫dx " * 100, 20), "∫dx " * 20 + "…" - ) - - # Words with HTML character references inside and outside - # the ASCII range. - self.assertEqual( - utils.truncate_html_words("é " * 100, 20), "é " * 20 + "…" - ) - self.assertEqual( - utils.truncate_html_words("∫dx " * 100, 20), "∫dx " * 20 + "…" - ) - - # Words with invalid or broken HTML references. - self.assertEqual(utils.truncate_html_words("&invalid;", 20), "&invalid;") - self.assertEqual( - utils.truncate_html_words("�", 20), "�" - ) - self.assertEqual( - utils.truncate_html_words("�", 20), "�" - ) - self.assertEqual(utils.truncate_html_words("&mdash text", 20), "&mdash text") - self.assertEqual(utils.truncate_html_words("Ӓ text", 20), "Ӓ text") - self.assertEqual(utils.truncate_html_words("઼ text", 20), "઼ text") - - def test_truncate_html_paragraphs(self): - one = "

    one

    " - - self.assertEqual(utils.truncate_html_paragraphs(one, 0), "") - self.assertEqual(utils.truncate_html_paragraphs(one, 1), one) - self.assertEqual(utils.truncate_html_paragraphs(one, 2), one) - - two = one + "

    two

    " - self.assertEqual(utils.truncate_html_paragraphs(two, 1), one) - self.assertEqual(utils.truncate_html_paragraphs(two, 2), two) - - three = two + "

    three

    " - self.assertEqual(utils.truncate_html_paragraphs(three, 1), one) - self.assertEqual(utils.truncate_html_paragraphs(three, 2), two) - self.assertEqual(utils.truncate_html_paragraphs(three, 3), three) - self.assertEqual(utils.truncate_html_paragraphs(three, 4), three) - - def test_process_translations(self): - fr_articles = [] - en_articles = [] - - # create a bunch of articles - # 0: no translation metadata - fr_articles.append( - get_article(lang="fr", slug="yay0", title="Titre", content="en français") - ) - en_articles.append( - get_article(lang="en", slug="yay0", title="Title", content="in english") - ) - # 1: translation metadata on default lang - fr_articles.append( - get_article(lang="fr", slug="yay1", title="Titre", content="en français") - ) - en_articles.append( - get_article( - lang="en", - slug="yay1", - title="Title", - content="in english", - translation="true", - ) - ) - # 2: translation metadata not on default lang - fr_articles.append( - get_article( - lang="fr", - slug="yay2", - title="Titre", - content="en français", - translation="true", - ) - ) - en_articles.append( - get_article(lang="en", slug="yay2", title="Title", content="in english") - ) - # 3: back to default language detection if all items have the - # translation metadata - fr_articles.append( - get_article( - lang="fr", - slug="yay3", - title="Titre", - content="en français", - translation="yep", - ) - ) - en_articles.append( - get_article( - lang="en", - slug="yay3", - title="Title", - content="in english", - translation="yes", - ) - ) - # 4-5: translation pairs with the same slug but different category - fr_articles.append( - get_article( - lang="fr", - slug="yay4", - title="Titre", - content="en français", - category="foo", - ) - ) - en_articles.append( - get_article( - lang="en", - slug="yay4", - title="Title", - content="in english", - category="foo", - ) - ) - fr_articles.append( - get_article( - lang="fr", - slug="yay4", - title="Titre", - content="en français", - category="bar", - ) - ) - en_articles.append( - get_article( - lang="en", - slug="yay4", - title="Title", - content="in english", - category="bar", - ) - ) - - # try adding articles in both orders - for lang0_articles, lang1_articles in ( - (fr_articles, en_articles), - (en_articles, fr_articles), - ): - articles = lang0_articles + lang1_articles - - # test process_translations with falsy translation_id - index, trans = utils.process_translations(articles, translation_id=None) - for i in range(6): - for lang_articles in [en_articles, fr_articles]: - self.assertIn(lang_articles[i], index) - self.assertNotIn(lang_articles[i], trans) - - # test process_translations with simple and complex translation_id - for translation_id in ["slug", {"slug", "category"}]: - index, trans = utils.process_translations( - articles, translation_id=translation_id - ) - - for a in [ - en_articles[0], - fr_articles[1], - en_articles[2], - en_articles[3], - en_articles[4], - en_articles[5], - ]: - self.assertIn(a, index) - self.assertNotIn(a, trans) - - for a in [ - fr_articles[0], - en_articles[1], - fr_articles[2], - fr_articles[3], - fr_articles[4], - fr_articles[5], - ]: - self.assertIn(a, trans) - self.assertNotIn(a, index) - - for i in range(6): - self.assertIn(en_articles[i], fr_articles[i].translations) - self.assertIn(fr_articles[i], en_articles[i].translations) - - for a_arts in [en_articles, fr_articles]: - for b_arts in [en_articles, fr_articles]: - if translation_id == "slug": - self.assertIn(a_arts[4], b_arts[5].translations) - self.assertIn(a_arts[5], b_arts[4].translations) - elif translation_id == {"slug", "category"}: - self.assertNotIn(a_arts[4], b_arts[5].translations) - self.assertNotIn(a_arts[5], b_arts[4].translations) - - def test_clean_output_dir(self): - retention = () - test_directory = os.path.join(self.temp_output, "clean_output") - content = os.path.join(os.path.dirname(__file__), "content") - shutil.copytree(content, test_directory) - utils.clean_output_dir(test_directory, retention) - self.assertTrue(os.path.isdir(test_directory)) - self.assertListEqual([], os.listdir(test_directory)) - shutil.rmtree(test_directory) - - def test_clean_output_dir_not_there(self): - retention = () - test_directory = os.path.join(self.temp_output, "does_not_exist") - utils.clean_output_dir(test_directory, retention) - self.assertFalse(os.path.exists(test_directory)) - - def test_clean_output_dir_is_file(self): - retention = () - test_directory = os.path.join(self.temp_output, "this_is_a_file") - f = open(test_directory, "w") - f.write("") - f.close() - utils.clean_output_dir(test_directory, retention) - self.assertFalse(os.path.exists(test_directory)) - - def test_strftime(self): - d = utils.SafeDatetime(2012, 8, 29) - - # simple formatting - self.assertEqual(utils.strftime(d, "%d/%m/%y"), "29/08/12") - self.assertEqual(utils.strftime(d, "%d/%m/%Y"), "29/08/2012") - - # RFC 3339 - self.assertEqual( - utils.strftime(d, "%Y-%m-%dT%H:%M:%SZ"), "2012-08-29T00:00:00Z" - ) - - # % escaped - self.assertEqual(utils.strftime(d, "%d%%%m%%%y"), "29%08%12") - self.assertEqual(utils.strftime(d, "%d %% %m %% %y"), "29 % 08 % 12") - # not valid % formatter - self.assertEqual( - utils.strftime(d, "10% reduction in %Y"), "10% reduction in 2012" - ) - self.assertEqual( - utils.strftime(d, "%10 reduction in %Y"), "%10 reduction in 2012" - ) - - # with text - self.assertEqual( - utils.strftime(d, "Published in %d-%m-%Y"), "Published in 29-08-2012" - ) - - # with non-ascii text - self.assertEqual( - utils.strftime(d, "%d/%m/%Y Øl trinken beim Besäufnis"), - "29/08/2012 Øl trinken beim Besäufnis", - ) - - # alternative formatting options - self.assertEqual(utils.strftime(d, "%-d/%-m/%y"), "29/8/12") - self.assertEqual(utils.strftime(d, "%-H:%-M:%-S"), "0:0:0") - - d = utils.SafeDatetime(2012, 8, 9) - self.assertEqual(utils.strftime(d, "%-d/%-m/%y"), "9/8/12") - - d = utils.SafeDatetime(2021, 1, 8) - self.assertEqual(utils.strftime(d, "%G - %-V - %u"), "2021 - 1 - 5") - - # test the output of utils.strftime in a different locale - # Turkish locale - @unittest.skipUnless( - locale_available("tr_TR.UTF-8") or locale_available("Turkish"), - "Turkish locale needed", - ) - def test_strftime_locale_dependent_turkish(self): - temp_locale = "Turkish" if platform == "win32" else "tr_TR.UTF-8" - - with utils.temporary_locale(temp_locale): - d = utils.SafeDatetime(2012, 8, 29) - - # simple - self.assertEqual(utils.strftime(d, "%d %B %Y"), "29 Ağustos 2012") - self.assertEqual( - utils.strftime(d, "%A, %d %B %Y"), "Çarşamba, 29 Ağustos 2012" - ) - - # with text - self.assertEqual( - utils.strftime(d, "Yayınlanma tarihi: %A, %d %B %Y"), - "Yayınlanma tarihi: Çarşamba, 29 Ağustos 2012", - ) - - # non-ascii format candidate (someone might pass it… for some reason) - self.assertEqual( - utils.strftime(d, "%Y yılında %üretim artışı"), - "2012 yılında %üretim artışı", - ) - - # test the output of utils.strftime in a different locale - # French locale - @unittest.skipUnless( - locale_available("fr_FR.UTF-8") or locale_available("French"), - "French locale needed", - ) - def test_strftime_locale_dependent_french(self): - temp_locale = "French" if platform == "win32" else "fr_FR.UTF-8" - - with utils.temporary_locale(temp_locale): - d = utils.SafeDatetime(2012, 8, 29) - - # simple - self.assertEqual(utils.strftime(d, "%d %B %Y"), "29 août 2012") - - # depending on OS, the first letter is m or M - self.assertTrue(utils.strftime(d, "%A") in ("mercredi", "Mercredi")) - - # with text - self.assertEqual( - utils.strftime(d, "Écrit le %d %B %Y"), "Écrit le 29 août 2012" - ) - - # non-ascii format candidate (someone might pass it… for some reason) - self.assertEqual(utils.strftime(d, "%écrits en %Y"), "%écrits en 2012") - - def test_maybe_pluralize(self): - self.assertEqual(utils.maybe_pluralize(0, "Article", "Articles"), "0 Articles") - self.assertEqual(utils.maybe_pluralize(1, "Article", "Articles"), "1 Article") - self.assertEqual(utils.maybe_pluralize(2, "Article", "Articles"), "2 Articles") - - def test_temporary_locale(self): - # test with default LC category - orig_locale = locale.setlocale(locale.LC_ALL) - - with utils.temporary_locale("C"): - self.assertEqual(locale.setlocale(locale.LC_ALL), "C") - - self.assertEqual(locale.setlocale(locale.LC_ALL), orig_locale) - - # test with custom LC category - orig_locale = locale.setlocale(locale.LC_TIME) - - with utils.temporary_locale("C", locale.LC_TIME): - self.assertEqual(locale.setlocale(locale.LC_TIME), "C") - - self.assertEqual(locale.setlocale(locale.LC_TIME), orig_locale) - - -class TestCopy(unittest.TestCase): - """Tests the copy utility""" - - def setUp(self): - self.root_dir = mkdtemp(prefix="pelicantests.") - self.old_locale = locale.setlocale(locale.LC_ALL) - locale.setlocale(locale.LC_ALL, "C") - - def tearDown(self): - shutil.rmtree(self.root_dir) - locale.setlocale(locale.LC_ALL, self.old_locale) - - def _create_file(self, *path): - with open(os.path.join(self.root_dir, *path), "w") as f: - f.write("42\n") - - def _create_dir(self, *path): - os.makedirs(os.path.join(self.root_dir, *path)) - - def _exist_file(self, *path): - path = os.path.join(self.root_dir, *path) - self.assertTrue(os.path.isfile(path), f"File does not exist: {path}") - - def _exist_dir(self, *path): - path = os.path.join(self.root_dir, *path) - self.assertTrue(os.path.exists(path), f"Directory does not exist: {path}") - - def test_copy_file_same_path(self): - self._create_file("a.txt") - utils.copy( - os.path.join(self.root_dir, "a.txt"), os.path.join(self.root_dir, "b.txt") - ) - self._exist_file("b.txt") - - def test_copy_file_different_path(self): - self._create_dir("a") - self._create_dir("b") - self._create_file("a", "a.txt") - utils.copy( - os.path.join(self.root_dir, "a", "a.txt"), - os.path.join(self.root_dir, "b", "b.txt"), - ) - self._exist_dir("b") - self._exist_file("b", "b.txt") - - def test_copy_file_create_dirs(self): - self._create_file("a.txt") - utils.copy( - os.path.join(self.root_dir, "a.txt"), - os.path.join(self.root_dir, "b0", "b1", "b2", "b3", "b.txt"), - ) - self._exist_dir("b0") - self._exist_dir("b0", "b1") - self._exist_dir("b0", "b1", "b2") - self._exist_dir("b0", "b1", "b2", "b3") - self._exist_file("b0", "b1", "b2", "b3", "b.txt") - - def test_copy_dir_same_path(self): - self._create_dir("a") - self._create_file("a", "a.txt") - utils.copy(os.path.join(self.root_dir, "a"), os.path.join(self.root_dir, "b")) - self._exist_dir("b") - self._exist_file("b", "a.txt") - - def test_copy_dir_different_path(self): - self._create_dir("a0") - self._create_dir("a0", "a1") - self._create_file("a0", "a1", "a.txt") - self._create_dir("b0") - utils.copy( - os.path.join(self.root_dir, "a0", "a1"), - os.path.join(self.root_dir, "b0", "b1"), - ) - self._exist_dir("b0", "b1") - self._exist_file("b0", "b1", "a.txt") - - def test_copy_dir_create_dirs(self): - self._create_dir("a") - self._create_file("a", "a.txt") - utils.copy( - os.path.join(self.root_dir, "a"), - os.path.join(self.root_dir, "b0", "b1", "b2", "b3", "b"), - ) - self._exist_dir("b0") - self._exist_dir("b0", "b1") - self._exist_dir("b0", "b1", "b2") - self._exist_dir("b0", "b1", "b2", "b3") - self._exist_dir("b0", "b1", "b2", "b3", "b") - self._exist_file("b0", "b1", "b2", "b3", "b", "a.txt") - - -class TestDateFormatter(unittest.TestCase): - """Tests that the output of DateFormatter jinja filter is same as - utils.strftime""" - - def setUp(self): - # prepare a temp content and output folder - self.temp_content = mkdtemp(prefix="pelicantests.") - self.temp_output = mkdtemp(prefix="pelicantests.") - - # prepare a template file - template_dir = os.path.join(self.temp_content, "template") - template_path = os.path.join(template_dir, "source.html") - os.makedirs(template_dir) - with open(template_path, "w") as template_file: - template_file.write('date = {{ date|strftime("%A, %d %B %Y") }}') - self.date = utils.SafeDatetime(2012, 8, 29) - - def tearDown(self): - shutil.rmtree(self.temp_content) - shutil.rmtree(self.temp_output) - # reset locale to default - locale.setlocale(locale.LC_ALL, "") - - @unittest.skipUnless( - locale_available("fr_FR.UTF-8") or locale_available("French"), - "French locale needed", - ) - def test_french_strftime(self): - # This test tries to reproduce an issue that - # occurred with python3.3 under macos10 only - temp_locale = "French" if platform == "win32" else "fr_FR.UTF-8" - - with utils.temporary_locale(temp_locale): - date = utils.SafeDatetime(2014, 8, 14) - # we compare the lower() dates since macos10 returns - # "Jeudi" for %A whereas linux reports "jeudi" - self.assertEqual( - "jeudi, 14 août 2014", - utils.strftime(date, date_format="%A, %d %B %Y").lower(), - ) - df = utils.DateFormatter() - self.assertEqual( - "jeudi, 14 août 2014", df(date, date_format="%A, %d %B %Y").lower() - ) - - # Let us now set the global locale to C: - with utils.temporary_locale("C"): - # DateFormatter should still work as expected - # since it is the whole point of DateFormatter - # (This is where pre-2014/4/15 code fails on macos10) - df_date = df(date, date_format="%A, %d %B %Y").lower() - self.assertEqual("jeudi, 14 août 2014", df_date) - - @unittest.skipUnless( - locale_available("fr_FR.UTF-8") or locale_available("French"), - "French locale needed", - ) - def test_french_locale(self): - if platform == "win32": - locale_string = "French" - else: - locale_string = "fr_FR.UTF-8" - settings = read_settings( - override={ - "LOCALE": locale_string, - "TEMPLATE_PAGES": {"template/source.html": "generated/file.html"}, - } - ) - - generator = TemplatePagesGenerator( - {"date": self.date}, settings, self.temp_content, "", self.temp_output - ) - generator.env.filters.update({"strftime": utils.DateFormatter()}) - - writer = Writer(self.temp_output, settings=settings) - generator.generate_output(writer) - - output_path = os.path.join(self.temp_output, "generated", "file.html") - - # output file has been generated - self.assertTrue(os.path.exists(output_path)) - - # output content is correct - with utils.pelican_open(output_path) as output_file: - self.assertEqual( - output_file, utils.strftime(self.date, "date = %A, %d %B %Y") - ) - - @unittest.skipUnless( - locale_available("tr_TR.UTF-8") or locale_available("Turkish"), - "Turkish locale needed", - ) - def test_turkish_locale(self): - if platform == "win32": - locale_string = "Turkish" - else: - locale_string = "tr_TR.UTF-8" - settings = read_settings( - override={ - "LOCALE": locale_string, - "TEMPLATE_PAGES": {"template/source.html": "generated/file.html"}, - } - ) - - generator = TemplatePagesGenerator( - {"date": self.date}, settings, self.temp_content, "", self.temp_output - ) - generator.env.filters.update({"strftime": utils.DateFormatter()}) - - writer = Writer(self.temp_output, settings=settings) - generator.generate_output(writer) - - output_path = os.path.join(self.temp_output, "generated", "file.html") - - # output file has been generated - self.assertTrue(os.path.exists(output_path)) - - # output content is correct - with utils.pelican_open(output_path) as output_file: - self.assertEqual( - output_file, utils.strftime(self.date, "date = %A, %d %B %Y") - ) - - -class TestSanitisedJoin(unittest.TestCase): - def test_detect_parent_breakout(self): - with self.assertRaisesRegex( - RuntimeError, - "Attempted to break out of output directory to (.*?:)?/foo/test", - ): # (.*?:)? accounts for Windows root - utils.sanitised_join("/foo/bar", "../test") - - def test_detect_root_breakout(self): - with self.assertRaisesRegex( - RuntimeError, - "Attempted to break out of output directory to (.*?:)?/test", - ): # (.*?:)? accounts for Windows root - utils.sanitised_join("/foo/bar", "/test") - - def test_pass_deep_subpaths(self): - self.assertEqual( - utils.sanitised_join("/foo/bar", "test"), - utils.posixize_path(os.path.abspath(os.path.join("/foo/bar", "test"))), - ) - - -class TestMemoized(unittest.TestCase): - def test_memoized(self): - class Container: - def _get(self, key): - pass - - @utils.memoized - def get(self, key): - return self._get(key) - - container = Container() - - with unittest.mock.patch.object( - container, "_get", side_effect=lambda x: x - ) as get_mock: - self.assertEqual("foo", container.get("foo")) - get_mock.assert_called_once_with("foo") - - get_mock.reset_mock() - self.assertEqual("foo", container.get("foo")) - get_mock.assert_not_called() - - self.assertEqual("bar", container.get("bar")) - get_mock.assert_called_once_with("bar") - - get_mock.reset_mock() - container.get.cache.clear() - self.assertEqual("bar", container.get("bar")) - get_mock.assert_called_once_with("bar") - - -class TestStringUtils(unittest.TestCase): - def test_file_suffix(self): - self.assertEqual("", utils.file_suffix("")) - self.assertEqual("", utils.file_suffix("foo")) - self.assertEqual("md", utils.file_suffix("foo.md")) diff --git a/pelican/tests/theme_overrides/level1/article.html b/pelican/tests/theme_overrides/level1/article.html deleted file mode 100644 index 12f6b7bf..00000000 --- a/pelican/tests/theme_overrides/level1/article.html +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/pelican/tests/theme_overrides/level2/article.html b/pelican/tests/theme_overrides/level2/article.html deleted file mode 100644 index 12f6b7bf..00000000 --- a/pelican/tests/theme_overrides/level2/article.html +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/pelican/tests/theme_overrides/level2/authors.html b/pelican/tests/theme_overrides/level2/authors.html deleted file mode 100644 index 12f6b7bf..00000000 --- a/pelican/tests/theme_overrides/level2/authors.html +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/pelican/themes/notmyidea/static/css/fonts.css b/pelican/themes/notmyidea/static/css/fonts.css deleted file mode 100644 index 7c69215e..00000000 --- a/pelican/themes/notmyidea/static/css/fonts.css +++ /dev/null @@ -1,12 +0,0 @@ -@font-face { - font-family: 'Yanone Kaffeesatz'; - font-style: normal; - font-weight: 400; - src: - local('Yanone Kaffeesatz Regular'), - local('YanoneKaffeesatz-Regular'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff */ - url('../fonts/Yanone_Kaffeesatz_400.woff') format('woff'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLfGwxTS8d1Q9KiDNCMKLFUM.woff2 */ - url('../fonts/Yanone_Kaffeesatz_400.woff2') format('woff2'); -} diff --git a/pelican/themes/notmyidea/static/css/main.css b/pelican/themes/notmyidea/static/css/main.css deleted file mode 100644 index c1d86950..00000000 --- a/pelican/themes/notmyidea/static/css/main.css +++ /dev/null @@ -1,439 +0,0 @@ -/* - Name: Smashing HTML5 - Date: July 2009 - Description: Sample layout for HTML5 and CSS3 goodness. - Version: 1.0 - License: MIT - Licensed by: Smashing Media GmbH - Original author: Enrique Ramírez -*/ - -/* Imports */ -@import url("reset.css"); -@import url("pygment.css"); -@import url("typogrify.css"); -@import url("fonts.css"); - -/***** Global *****/ -/* Body */ -body { - background: #F5F4EF; - color: #000305; - font-size: 87.5%; /* Base font size: 14px */ - font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; - line-height: 1.429; - margin: 0; - padding: 0; - text-align: left; -} - -/* Headings */ -h1 {font-size: 2em } -h2 {font-size: 1.571em} /* 22px */ -h3 {font-size: 1.429em} /* 20px */ -h4 {font-size: 1.286em} /* 18px */ -h5 {font-size: 1.143em} /* 16px */ -h6 {font-size: 1em} /* 14px */ - -h1, h2, h3, h4, h5, h6 { - font-weight: 400; - line-height: 1.1; - margin-bottom: .8em; - font-family: 'Yanone Kaffeesatz', arial, serif; -} - -h3, h4, h5, h6 { margin-top: .8em; } - -hr { border: 2px solid #EEEEEE; } - -/* Anchors */ -a {outline: 0;} -a img {border: 0px; text-decoration: none;} -a:link, a:visited { - color: #C74350; - padding: 0 1px; - text-decoration: underline; -} -a:hover, a:active { - background-color: #C74350; - color: #fff; - text-decoration: none; - text-shadow: 1px 1px 1px #333; -} - -h1 a:hover { - background-color: inherit -} - -/* Paragraphs */ -div.line-block, -p { margin-top: 1em; - margin-bottom: 1em;} - -strong, b {font-weight: bold;} -em, i {font-style: italic;} - -/* Lists */ -ul { - list-style: outside disc; - margin: 0em 0 0 1.5em; -} - -ol { - list-style: outside decimal; - margin: 0em 0 0 1.5em; -} - -li { margin-top: 0.5em; - margin-bottom: 1em; } - -.post-info { - float:right; - margin:10px; - padding:5px; -} - -.post-info p{ - margin-top: 1px; - margin-bottom: 1px; -} - -.readmore { float: right } - -dl {margin: 0 0 1.5em 0;} -dt {font-weight: bold;} -dd {margin-left: 1.5em;} - -pre{background-color: rgb(238, 238, 238); padding: 10px; margin: 10px; overflow: auto;} - -/* Quotes */ -blockquote { - margin: 20px; - font-style: italic; -} -cite {} - -q {} - -div.note { - float: right; - margin: 5px; - font-size: 85%; - max-width: 300px; -} - -/* Tables */ -table {margin: .5em auto 1.5em auto; width: 98%;} - - /* Thead */ -thead th {padding: .5em .4em; text-align: left;} -thead td {} - - /* Tbody */ -tbody td {padding: .5em .4em;} -tbody th {} - -tbody .alt td {} -tbody .alt th {} - - /* Tfoot */ -tfoot th {} -tfoot td {} - -/* HTML5 tags */ -header, section, footer, -aside, nav, article, figure { - display: block; -} - -/***** Layout *****/ -.body {clear: both; margin: 0 auto; max-width: 800px;} -img { max-width: 100%; } -img.right, figure.right, div.figure.align-right { - float: right; - margin: 0 0 2em 2em; -} -img.left, figure.left, div.figure.align-left { - float: left; - margin: 0 2em 2em 0; -} - -/* .rst support */ -div.figure img, figure img { /* to fill figure exactly */ - max-width: 100%; -} -div.figure p.caption, figure p.caption { /* margin provided by figure */ - margin-top: 0; - margin-bottom: 0; -} - -/* - Header -*****************/ -#banner { - margin: 0 auto; - padding: 0.8em 0 0 0; -} - - /* Banner */ -#banner h1 { - font-size: 3.571em; - line-height: 1.0; - margin-bottom: .3em; -} - -#banner h1 a:link, #banner h1 a:visited { - color: #000305; - display: block; - font-weight: bold; - margin: 0 0 0 .2em; - text-decoration: none; -} -#banner h1 a:hover, #banner h1 a:active { - background: none; - color: #C74350; - text-shadow: none; -} - -#banner h1 strong {font-size: 0.36em; font-weight: normal;} - - /* Main Nav */ -#banner nav { - background: #000305; - font-size: 1.143em; - overflow: auto; - line-height: 30px; - margin: 0 auto 2em auto; - padding: 0; - text-align: center; - max-width: 800px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} - -#banner nav ul {list-style: none; margin: 0 auto; max-width: 800px;} -#banner nav li {float: left; display: inline; margin: 0;} - -#banner nav a:link, #banner nav a:visited { - color: #fff; - display: inline-block; - height: 30px; - padding: 5px 1.5em; - text-decoration: none; -} -#banner nav a:hover, #banner nav a:active, -#banner nav .active a:link, #banner nav .active a:visited { - background: #C74451; - color: #fff; - text-shadow: none !important; -} - -#banner nav li:first-child a { - border-top-left-radius: 5px; - -moz-border-radius-topleft: 5px; - -webkit-border-top-left-radius: 5px; - - border-bottom-left-radius: 5px; - -moz-border-radius-bottomleft: 5px; - -webkit-border-bottom-left-radius: 5px; -} - -/* - Featured -*****************/ -#featured { - background: #fff; - margin-bottom: 2em; - overflow: hidden; - padding: 20px; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -#featured figure { - border: 2px solid #eee; - float: right; - margin: 0.786em 2em 0 5em; - max-width: 248px; -} -#featured figure img {display: block; float: right;} - -#featured h2 {color: #C74451; font-size: 1.714em; margin-bottom: 0.333em;} -#featured h3 {font-size: 1.429em; margin-bottom: .5em;} - -#featured h3 a:link, #featured h3 a:visited {color: #000305; text-decoration: none;} -#featured h3 a:hover, #featured h3 a:active {color: #fff;} - -/* - Body -*****************/ -#content { - background: #fff; - margin-bottom: 2em; - overflow: hidden; - padding: 20px 20px; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -/* - Extras -*****************/ -#extras {margin: 0 auto 3em auto; overflow: hidden;} - -#extras ul {list-style: none; margin: 0;} -#extras li {border-bottom: 1px solid #fff;} -#extras h2 { - color: #C74350; - font-size: 1.429em; - margin-bottom: .25em; - padding: 0 3px; -} - -#extras a:link, #extras a:visited { - color: #444; - display: block; - border-bottom: 1px solid #F4E3E3; - text-decoration: none; - padding: .3em .25em; -} - -#extras a:hover, #extras a:active {color: #fff;} - - /* Blogroll */ -#extras .blogroll { - float: left; - max-width: 615px; -} - -#extras .blogroll li {float: left; margin: 0 20px 0 0; max-width: 185px;} - - /* Social */ -#extras .social { - float: right; - max-width: 175px; -} - -/* - About -*****************/ -#about { - background: #fff; - font-style: normal; - margin-bottom: 2em; - overflow: hidden; - padding: 20px; - text-align: left; - max-width: 760px; - - border-radius: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -#about .primary {float: left; max-width: 165px;} -#about .primary strong {color: #C64350; display: block; font-size: 1.286em;} -#about .photo {float: left; margin: 5px 20px;} - -#about .url:link, #about .url:visited {text-decoration: none;} - -#about .bio {float: right; max-width: 500px;} - -/* - Footer -*****************/ -#contentinfo {padding-bottom: 2em; text-align: right;} - -/***** Sections *****/ -/* Blog */ -.hentry { - display: block; - clear: both; - border-top: 1px solid #eee; - padding: 1.5em 0; -} -li:first-child .hentry, #content > .hentry {border: 0; margin: 0;} -#content > .hentry {padding: 1em 0;} -.hentry img{display : none ;} -.entry-title {font-size: 3em; margin-bottom: 10px; margin-top: 0;} -.entry-title a:link, .entry-title a:visited {text-decoration: none; color: #333;} -.entry-title a:visited {background-color: #fff;} - -.hentry .post-info * {font-style: normal;} - - /* Content */ -.hentry footer {margin-bottom: 2em;} -.hentry footer address {display: inline;} -#posts-list footer address {display: block;} - - /* Blog Index */ -#posts-list {list-style: none; margin: 0;} -#posts-list .hentry {padding-left: 10px; position: relative;} - -#posts-list footer { - left: 10px; - position: relative; - float: left; - top: 0.5em; - max-width: 190px; -} - - /* About the Author */ -#about-author { - background: #f9f9f9; - clear: both; - font-style: normal; - margin: 2em 0; - padding: 10px 20px 15px 20px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} - -#about-author strong { - color: #C64350; - clear: both; - display: block; - font-size: 1.429em; -} - -#about-author .photo {border: 1px solid #ddd; float: left; margin: 5px 1em 0 0;} - - /* Comments */ -#comments-list {list-style: none; margin: 0 1em;} -#comments-list blockquote { - background: #f8f8f8; - clear: both; - font-style: normal; - margin: 0; - padding: 15px 20px; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} -#comments-list footer {color: #888; padding: .5em 1em 0 0; text-align: right;} - -#comments-list li:nth-child(2n) blockquote {background: #F5f5f5;} - - /* Add a Comment */ -#add-comment label {clear: left; float: left; text-align: left; max-width: 150px;} -#add-comment input[type='text'], -#add-comment input[type='email'], -#add-comment input[type='url'] {float: left; max-width: 200px;} - -#add-comment textarea {float: left; height: 150px; max-width: 495px;} - -#add-comment p.req {clear: both; margin: 0 .5em 1em 0; text-align: right;} - -#add-comment input[type='submit'] {float: right; margin: 0 .5em;} -#add-comment * {margin-bottom: .5em;} diff --git a/pelican/themes/notmyidea/static/css/pygment.css b/pelican/themes/notmyidea/static/css/pygment.css deleted file mode 100644 index a3877a83..00000000 --- a/pelican/themes/notmyidea/static/css/pygment.css +++ /dev/null @@ -1,205 +0,0 @@ -.hll { - background-color:#eee; -} -.c { - color:#408090; - font-style:italic; -} -.err { - border:1px solid #FF0000; -} -.k { - color:#007020; - font-weight:bold; -} -.o { - color:#666666; -} -.cm { - color:#408090; - font-style:italic; -} -.cp { - color:#007020; -} -.c1 { - color:#408090; - font-style:italic; -} -.cs { - background-color:#FFF0F0; - color:#408090; -} -.gd { - color:#A00000; -} -.ge { - font-style:italic; -} -.gr { - color:#FF0000; -} -.gh { - color:#000080; - font-weight:bold; -} -.gi { - color:#00A000; -} -.go { - color:#303030; -} -.gp { - color:#C65D09; - font-weight:bold; -} -.gs { - font-weight:bold; -} -.gu { - color:#800080; - font-weight:bold; -} -.gt { - color:#0040D0; -} -.kc { - color:#007020; - font-weight:bold; -} -.kd { - color:#007020; - font-weight:bold; -} -.kn { - color:#007020; - font-weight:bold; -} -.kp { - color:#007020; -} -.kr { - color:#007020; - font-weight:bold; -} -.kt { - color:#902000; -} -.m { - color:#208050; -} -.s { - color:#4070A0; -} -.na { - color:#4070A0; -} -.nb { - color:#007020; -} -.nc { - color:#0E84B5; - font-weight:bold; -} -.no { - color:#60ADD5; -} -.nd { - color:#555555; - font-weight:bold; -} -.ni { - color:#D55537; - font-weight:bold; -} -.ne { - color:#007020; -} -.nf { - color:#06287E; -} -.nl { - color:#002070; - font-weight:bold; -} -.nn { - color:#0E84B5; - font-weight:bold; -} -.nt { - color:#062873; - font-weight:bold; -} -.nv { - color:#BB60D5; -} -.ow { - color:#007020; - font-weight:bold; -} -.w { - color:#BBBBBB; -} -.mf { - color:#208050; -} -.mh { - color:#208050; -} -.mi { - color:#208050; -} -.mo { - color:#208050; -} -.sb { - color:#4070A0; -} -.sc { - color:#4070A0; -} -.sd { - color:#4070A0; - font-style:italic; -} -.s2 { - color:#4070A0; -} -.se { - color:#4070A0; - font-weight:bold; -} -.sh { - color:#4070A0; -} -.si { - color:#70A0D0; - font-style:italic; -} -.sx { - color:#C65D09; -} -.sr { - color:#235388; -} -.s1 { - color:#4070A0; -} -.ss { - color:#517918; -} -.bp { - color:#007020; -} -.vc { - color:#BB60D5; -} -.vg { - color:#BB60D5; -} -.vi { - color:#BB60D5; -} -.il { - color:#208050; -} diff --git a/pelican/themes/notmyidea/static/css/reset.css b/pelican/themes/notmyidea/static/css/reset.css deleted file mode 100644 index 10b3fde2..00000000 --- a/pelican/themes/notmyidea/static/css/reset.css +++ /dev/null @@ -1,52 +0,0 @@ -/* - Name: Reset Stylesheet - Description: Resets browser's default CSS - Author: Eric Meyer - Author URI: https://meyerweb.com/eric/tools/css/reset/ -*/ - -/* v1.0 | 20080212 */ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, font, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td { - background: transparent; - border: 0; - font-size: 100%; - margin: 0; - outline: 0; - padding: 0; - vertical-align: baseline; -} - -body {line-height: 1;} - -ol, ul {list-style: none;} - -blockquote, q {quotes: none;} - -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} - -/* remember to define focus styles! */ -:focus { - outline: 0; -} - -/* remember to highlight inserts somehow! */ -ins {text-decoration: none;} -del {text-decoration: line-through;} - -/* tables still need 'cellspacing="0"' in the markup */ -table { - border-collapse: collapse; - border-spacing: 0; -} diff --git a/pelican/themes/notmyidea/static/css/typogrify.css b/pelican/themes/notmyidea/static/css/typogrify.css deleted file mode 100644 index 3bae4976..00000000 --- a/pelican/themes/notmyidea/static/css/typogrify.css +++ /dev/null @@ -1,3 +0,0 @@ -.caps {font-size:.92em;} -.amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;} -.dquo {margin-left:-.38em;} diff --git a/pelican/themes/notmyidea/static/css/wide.css b/pelican/themes/notmyidea/static/css/wide.css deleted file mode 100644 index 88fd59ce..00000000 --- a/pelican/themes/notmyidea/static/css/wide.css +++ /dev/null @@ -1,48 +0,0 @@ -@import url("main.css"); - -body { - font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif; -} - -.post-info{ - display: none; -} - -#banner nav { - display: none; - -moz-border-radius: 0px; - margin-bottom: 20px; - overflow: hidden; - font-size: 1em; - background: #F5F4EF; -} - -#banner nav ul{ - padding-right: 50px; -} - -#banner nav li{ - float: right; - color: #000; -} - -#banner nav li a { - color: #000; -} - -#banner h1 { - margin-bottom: -18px; -} - -#featured, #extras { - padding: 50px; -} - -#featured { - padding-top: 20px; -} - -#extras { - padding-top: 0px; - padding-bottom: 0px; -} diff --git a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.eot b/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.eot deleted file mode 100644 index b3b90dbc..00000000 Binary files a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.eot and /dev/null differ diff --git a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.svg b/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.svg deleted file mode 100644 index a69669b5..00000000 --- a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.svg +++ /dev/null @@ -1,407 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.ttf b/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.ttf deleted file mode 100644 index 6f4feb02..00000000 Binary files a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.ttf and /dev/null differ diff --git a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.woff b/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.woff deleted file mode 100644 index ddccf765..00000000 Binary files a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.woff and /dev/null differ diff --git a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.woff2 b/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.woff2 deleted file mode 100644 index 7b18f7ea..00000000 Binary files a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_400.woff2 and /dev/null differ diff --git a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_LICENSE.txt b/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_LICENSE.txt deleted file mode 100644 index c70bcad3..00000000 --- a/pelican/themes/notmyidea/static/fonts/Yanone_Kaffeesatz_LICENSE.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2010 The Yanone Kaffeesatz Project Authors (https://github.com/alexeiva/yanone-kaffeesatz) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/pelican/themes/notmyidea/static/fonts/font.css b/pelican/themes/notmyidea/static/fonts/font.css deleted file mode 100644 index cf623603..00000000 --- a/pelican/themes/notmyidea/static/fonts/font.css +++ /dev/null @@ -1,12 +0,0 @@ -@font-face { - font-family: 'Yanone Kaffeesatz'; - font-style: normal; - font-weight: 400; - src: - local('Yanone Kaffeesatz Regular'), - local('YanoneKaffeesatz-Regular'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLRTHiN2BPBirwIkMLKUspj4.woff */ - url('Yanone_Kaffeesatz_400.woff') format('woff'), - /* from https://fonts.gstatic.com/s/yanonekaffeesatz/v8/YDAoLskQQ5MOAgvHUQCcLfGwxTS8d1Q9KiDNCMKLFUM.woff2 */ - url('Yanone_Kaffeesatz_400.woff2') format('woff2'); -} diff --git a/pelican/themes/notmyidea/templates/analytics.html b/pelican/themes/notmyidea/templates/analytics.html deleted file mode 100644 index d247e3ed..00000000 --- a/pelican/themes/notmyidea/templates/analytics.html +++ /dev/null @@ -1,3 +0,0 @@ -{% if ANALYTICS %} - {{ ANALYTICS }} -{% endif %} diff --git a/pelican/themes/notmyidea/templates/archives.html b/pelican/themes/notmyidea/templates/archives.html deleted file mode 100644 index ffc3627f..00000000 --- a/pelican/themes/notmyidea/templates/archives.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "base.html" %} -{% block content %} -
    -

    Archives for {{ SITENAME }}

    - -
    - {% for article in dates %} -
    {{ article.locale_date }}
    -
    {{ article.title }}
    - {% endfor %} -
    -
    -{% endblock %} diff --git a/pelican/themes/notmyidea/templates/article.html b/pelican/themes/notmyidea/templates/article.html deleted file mode 100644 index c0c1ebc3..00000000 --- a/pelican/themes/notmyidea/templates/article.html +++ /dev/null @@ -1,53 +0,0 @@ -{% extends "base.html" %} -{% block html_lang %}{{ article.lang }}{% endblock %} -{% block head -%} - {{ super() -}} - {% if article.summary %} - - {% endif %} -{% endblock %} - -{% block title %}{{ article.title|striptags }}{% endblock %} - -{% block extra_head %} - {% import 'translations.html' as translations with context %} - {% if translations.entry_hreflang(article) %} - {{ translations.entry_hreflang(article) }} - {% endif %} -{% endblock %} - -{% block content %} -
    -
    -
    -

    - {{ article.title }}

    - {% include 'twitter.html' %} -
    - -
    - {% include 'article_infos.html' %} - {{ article.content }} -
    - {% if DISQUS_SITENAME and SITEURL and article.status != "draft" %} -
    -

    Comments !

    -
    - - -
    - {% endif %} - -
    -
    -{% endblock %} diff --git a/pelican/themes/notmyidea/templates/article_infos.html b/pelican/themes/notmyidea/templates/article_infos.html deleted file mode 100644 index 335dcbb1..00000000 --- a/pelican/themes/notmyidea/templates/article_infos.html +++ /dev/null @@ -1,23 +0,0 @@ -
    - - Published: {{ article.locale_date }} - - {% if article.modified %} -
    - - Updated: {{ article.locale_modified }} - - {% endif %} - - {% if article.authors %} -
    - By {% for author in article.authors %} - {{ author }} - {% endfor %} -
    - {% endif %} -

    In {{ article.category }}.

    - {% include 'taglist.html' %} - {% import 'translations.html' as translations with context %} - {{ translations.translations_for(article) }} -
    diff --git a/pelican/themes/notmyidea/templates/author.html b/pelican/themes/notmyidea/templates/author.html deleted file mode 100644 index 536ac50d..00000000 --- a/pelican/themes/notmyidea/templates/author.html +++ /dev/null @@ -1,2 +0,0 @@ -{% extends "index.html" %} -{% block title %}{{ SITENAME|striptags }} - {{ author }}{% endblock %} diff --git a/pelican/themes/notmyidea/templates/authors.html b/pelican/themes/notmyidea/templates/authors.html deleted file mode 100644 index e7c1e3e4..00000000 --- a/pelican/themes/notmyidea/templates/authors.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "base.html" %} - -{% block title %}{{ SITENAME|striptags }} - Authors{% endblock %} - -{% block content %} - -
    -

    Authors on {{ SITENAME }}

    -
      - {% for author, articles in authors|sort %} -
    • {{ author }} ({{ articles|count }})
    • - {% endfor %} -
    -
    - -{% endblock %} diff --git a/pelican/themes/notmyidea/templates/base.html b/pelican/themes/notmyidea/templates/base.html deleted file mode 100644 index e5fabb09..00000000 --- a/pelican/themes/notmyidea/templates/base.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - {% block head %} - - - - {% block title %}{{ SITENAME|striptags }}{%endblock%} - - {% if FEED_ALL_ATOM %} - - {% endif %} - {% if FEED_ALL_RSS %} - - {% endif %} - {% block extra_head %}{% endblock extra_head %} - {% endblock head %} - - - - {% include 'github.html' %} - - {% block content %} - {% endblock %} -
    - {% if LINKS %} -
    -

    {{ LINKS_WIDGET_NAME | default('links') }}

    -
      - {% for name, link in LINKS %} -
    • {{ name }}
    • - {% endfor %} -
    -
    - {% endif %} - {% if SOCIAL or FEED_ALL_ATOM or FEED_ALL_RSS %} - - {% endif %} -
    - - - - {% include 'analytics.html' %} - {% include 'disqus_script.html' %} - - diff --git a/pelican/themes/notmyidea/templates/categories.html b/pelican/themes/notmyidea/templates/categories.html deleted file mode 100644 index 033f892a..00000000 --- a/pelican/themes/notmyidea/templates/categories.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "base.html" %} - -{% block title %}{{ SITENAME|striptags }} - Categories{% endblock %} - -{% block content %} - -
    -

    Categories for {{ SITENAME }}

    -
      - {% for category, articles in categories|sort %} -
    • {{ category }} ({{ articles|count }})
    • - {% endfor %} -
    -
    - -{% endblock %} diff --git a/pelican/themes/notmyidea/templates/category.html b/pelican/themes/notmyidea/templates/category.html deleted file mode 100644 index ff14ed76..00000000 --- a/pelican/themes/notmyidea/templates/category.html +++ /dev/null @@ -1,2 +0,0 @@ -{% extends "index.html" %} -{% block title %}{{ SITENAME|striptags }} - {{ category }}{% endblock %} diff --git a/pelican/themes/notmyidea/templates/comments.html b/pelican/themes/notmyidea/templates/comments.html deleted file mode 100644 index bb033c0f..00000000 --- a/pelican/themes/notmyidea/templates/comments.html +++ /dev/null @@ -1 +0,0 @@ -{% if DISQUS_SITENAME %}

    There are comments.

    {% endif %} diff --git a/pelican/themes/notmyidea/templates/disqus_script.html b/pelican/themes/notmyidea/templates/disqus_script.html deleted file mode 100644 index ef8823c1..00000000 --- a/pelican/themes/notmyidea/templates/disqus_script.html +++ /dev/null @@ -1,11 +0,0 @@ -{% if DISQUS_SITENAME %} - -{% endif %} diff --git a/pelican/themes/notmyidea/templates/github.html b/pelican/themes/notmyidea/templates/github.html deleted file mode 100644 index 8e256af7..00000000 --- a/pelican/themes/notmyidea/templates/github.html +++ /dev/null @@ -1,9 +0,0 @@ -{% if GITHUB_URL %} - - {% if GITHUB_POSITION != "left" %} - Fork me on GitHub - {% else %} - Fork me on GitHub - {% endif %} - -{% endif %} diff --git a/pelican/themes/notmyidea/templates/index.html b/pelican/themes/notmyidea/templates/index.html deleted file mode 100644 index 7a5c24ba..00000000 --- a/pelican/themes/notmyidea/templates/index.html +++ /dev/null @@ -1,65 +0,0 @@ -{% extends "base.html" %} -{% block content_title %}{% endblock %} -{% block content %} - {% if articles %} - {% for article in articles_page.object_list %} - - {# First item #} - {% if loop.first and not articles_page.has_previous() %} - - {% if loop.length > 1 %} -
    -

    Other articles

    -
    -
      - {% endif %} - {# other items #} - {% else %} - {% if loop.first %} -
      -
        - {% endif %} -
      1. -
        -

        {{ article.title }}

        -
        - -
        - {% include 'article_infos.html' %} - {{ article.summary }} - read more - {% include 'comments.html' %} -
        -
      2. - {% endif %} - {% if loop.last %} - {% if loop.length > 1 or articles_page.has_other_pages() %} -
      - {% if articles_page.has_other_pages() %} - {% include 'pagination.html' %} - {% endif %} -
      - {% endif %} - {% endif %} - {% endfor %} - {% else %} -
      - {% if pages %} -

      Pages

      - - {% else %} -

      This site currently has no content.

      - {% endif %} -
      - {% endif %} -{% endblock content %} diff --git a/pelican/themes/notmyidea/templates/page.html b/pelican/themes/notmyidea/templates/page.html deleted file mode 100644 index af3004e7..00000000 --- a/pelican/themes/notmyidea/templates/page.html +++ /dev/null @@ -1,19 +0,0 @@ -{% extends "base.html" %} -{% block html_lang %}{{ page.lang }}{% endblock %} -{% block title %}{{ page.title|striptags }}{% endblock %} - -{% block extra_head %} - {% import 'translations.html' as translations with context %} - {% if translations.entry_hreflang(page) %} - {{ translations.entry_hreflang(page) }} - {% endif %} -{% endblock %} - -{% block content %} -
      -

      {{ page.title }}

      - {% import 'translations.html' as translations with context %} - {{ translations.translations_for(page) }} - {{ page.content }} -
      -{% endblock %} diff --git a/pelican/themes/notmyidea/templates/period_archives.html b/pelican/themes/notmyidea/templates/period_archives.html deleted file mode 100644 index 6db49ed0..00000000 --- a/pelican/themes/notmyidea/templates/period_archives.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "base.html" %} -{% block content %} -
      -

      Archives for {{ period | reverse | join(' ') }}

      - -
      - {% for article in dates %} -
      {{ article.locale_date }}
      -
      {{ article.title }}
      - {% endfor %} -
      -
      -{% endblock %} diff --git a/pelican/themes/notmyidea/templates/tag.html b/pelican/themes/notmyidea/templates/tag.html deleted file mode 100644 index 1e32857b..00000000 --- a/pelican/themes/notmyidea/templates/tag.html +++ /dev/null @@ -1,2 +0,0 @@ -{% extends "index.html" %} -{% block title %}{{ SITENAME|striptags }} - {{ tag }}{% endblock %} diff --git a/pelican/themes/notmyidea/templates/taglist.html b/pelican/themes/notmyidea/templates/taglist.html deleted file mode 100644 index 58f35576..00000000 --- a/pelican/themes/notmyidea/templates/taglist.html +++ /dev/null @@ -1 +0,0 @@ -{% if article.tags %}

      tags: {% for tag in article.tags %}{{ tag | escape }} {% endfor %}

      {% endif %} diff --git a/pelican/themes/notmyidea/templates/tags.html b/pelican/themes/notmyidea/templates/tags.html deleted file mode 100644 index a9cce026..00000000 --- a/pelican/themes/notmyidea/templates/tags.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "base.html" %} - -{% block title %}{{ SITENAME|striptags }} - Tags{% endblock %} - -{% block content %} - -
      -

      Tags for {{ SITENAME }}

      -
        - {% for tag, articles in tags|sort %} -
      • {{ tag }} ({{ articles|count }})
      • - {% endfor %} -
      -
      - -{% endblock %} diff --git a/pelican/themes/notmyidea/templates/translations.html b/pelican/themes/notmyidea/templates/translations.html deleted file mode 100644 index eed0703d..00000000 --- a/pelican/themes/notmyidea/templates/translations.html +++ /dev/null @@ -1,16 +0,0 @@ -{% macro translations_for(article) %} - {% if article.translations %} - Translations: - {% for translation in article.translations %} - {{ translation.lang }} - {% endfor %} - {% endif %} -{% endmacro %} - -{% macro entry_hreflang(entry) %} - {% if entry.translations %} - {% for translation in entry.translations %} - - {% endfor %} - {% endif %} -{% endmacro %} diff --git a/pelican/themes/notmyidea/templates/twitter.html b/pelican/themes/notmyidea/templates/twitter.html deleted file mode 100644 index da1dddd9..00000000 --- a/pelican/themes/notmyidea/templates/twitter.html +++ /dev/null @@ -1,3 +0,0 @@ -{% if TWITTER_USERNAME %} - -{% endif %} diff --git a/pelican/themes/simple/.gitignore b/pelican/themes/simple/.gitignore deleted file mode 100644 index c2658d7d..00000000 --- a/pelican/themes/simple/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ diff --git a/pelican/themes/simple/static/css/highlight-rp-dawn.css b/pelican/themes/simple/static/css/highlight-rp-dawn.css deleted file mode 100644 index 1f38d01e..00000000 --- a/pelican/themes/simple/static/css/highlight-rp-dawn.css +++ /dev/null @@ -1,112 +0,0 @@ -/*! - Theme: Rose Pine - Origin: https://rosepinetheme.com/ -*/ - -/* Comment */ -.hljs-meta, -.hljs-comment { - color: #9893a5; -} - -/* Red */ -/*INFO: This keyword, HTML elements, Regex group symbol, CSS units, Terminal Red */ -.hljs-tag, -.hljs-doctag, -.hljs-selector-id, -.hljs-selector-class, -.hljs-regexp, -.hljs-template-tag, -.hljs-selector-pseudo, -.hljs-selector-attr, -.hljs-variable.language_, -.hljs-deletion { - color: #b4637a; -} - -/*Orange */ -/*INFO: Number and Boolean constants, Language support constants */ -.hljs-variable, -.hljs-template-variable, -.hljs-number, -.hljs-literal, -.hljs-type, -.hljs-params, -.hljs-link { - color: #d7827e; -} - -/* Yellow */ -/* INFO: Function parameters, Regex character sets, Terminal Yellow */ -.hljs-built_in, -.hljs-attribute { - color: #ea9d34; -} -/* cyan */ -/* INFO: Language support functions, CSS HTML elements */ -.hljs-selector-tag { - color: #286983; -} - -/* light blue */ -/* INFO: Object properties, Regex quantifiers and flags, Markdown headings, Terminal Cyan, Markdown code, Import/export keywords */ -.hljs-keyword, -.hljs-title.function_, -.hljs-title, -.hljs-title.class_, -.hljs-title.class_.inherited__, -.hljs-subst, -.hljs-property { - color: #56949f; -} - -/*Green*/ -/* INFO: Object literal keys, Markdown links, Terminal Green */ -.hljs-selector-tag { - color: #56949f; -} - -/*Green(er) */ -/* INFO: Strings, CSS class names */ -.hljs-quote, -.hljs-string, -.hljs-symbol, -.hljs-bullet, -.hljs-addition { - color: #286983; -} - -/* INFO: Function names, CSS property names, Terminal Blue */ -.hljs-code, -.hljs-formula, -.hljs-section { - color: #d7827e; -} - -/* Magenta */ -/*INFO: Control Keywords, Storage Types, Regex symbols and operators, HTML Attributes, Terminal Magenta */ -.hljs-name, -.hljs-keyword, -.hljs-operator, -.hljs-keyword, -.hljs-char.escape_, -.hljs-attr { - color: #907aa9; -} - -.hljs-punctuation { - color: #575279; -} - -.hljs { - background: #faf4ed; - color: #575279; -} - -.hljs-emphasis { - font-style: italic; -} - -.hljs-strong { - font-weight: bold; -} diff --git a/pelican/themes/simple/static/css/highlight-rp-moon.css b/pelican/themes/simple/static/css/highlight-rp-moon.css deleted file mode 100644 index c87aea3a..00000000 --- a/pelican/themes/simple/static/css/highlight-rp-moon.css +++ /dev/null @@ -1,114 +0,0 @@ -/*! - Theme: Rose Pine - Origin: https://rosepinetheme.com/ -*/ - -/* Comment */ -.hljs-meta, -.hljs-comment { - color: #6e6a86; -} - -/* Red */ -/*INFO: This keyword, HTML elements, Regex group symbol, CSS units, Terminal Red */ -.hljs-tag, -.hljs-doctag, -.hljs-selector-id, -.hljs-selector-class, -.hljs-regexp, -.hljs-template-tag, -.hljs-selector-pseudo, -.hljs-selector-attr, -.hljs-variable.language_, -.hljs-deletion { - color: #eb6f92; -} - -/*Orange */ -/*INFO: Number and Boolean constants, Language support constants */ -.hljs-variable, -.hljs-template-variable, -.hljs-number, -.hljs-literal, -.hljs-type, -.hljs-params, -.hljs-link { - color: #ea9a97; -} - -/* Yellow */ -/* INFO: Function parameters, Regex character sets, Terminal Yellow */ -.hljs-built_in, -.hljs-attribute { - color: #f6c177; -} -/* cyan */ -/* INFO: Language support functions, CSS HTML elements */ -.hljs-selector-tag { - color: #3e8fb0; -} - -/* light blue */ -/* INFO: Object properties, Regex quantifiers and flags, Markdown headings, Terminal Cyan, Markdown code, Import/export keywords */ -.hljs-keyword, -.hljs-title.function_, -.hljs-title, -.hljs-title.class_, -.hljs-title.class_.inherited__, -.hljs-subst, -.hljs-property { - color: #9ccfd8; -} - -/*Green*/ -/* INFO: Object literal keys, Markdown links, Terminal Green */ -.hljs-selector-tag { - color: #9ccfd8; -} - -/*Green(er) */ -/* INFO: Strings, CSS class names */ -.hljs-quote, -.hljs-string, -.hljs-symbol, -.hljs-bullet, -.hljs-addition { - color: #3e8fb0; -} - -/* INFO: Function names, CSS property names, Terminal Blue */ -.hljs-code, -.hljs-formula, -.hljs-section { - color: #ea9a97; -} - -/* Magenta */ -/*INFO: Control Keywords, Storage Types, Regex symbols and operators, HTML Attributes, Terminal Magenta */ -.hljs-name, -.hljs-keyword, -.hljs-operator, -.hljs-keyword, -.hljs-char.escape_, -.hljs-attr { - color: #c4a7e7; -} - -/* white*/ -/* INFO: Variables, Class names, Terminal White */ -.hljs-punctuation { - color: #e0def4; -} - -.hljs { - background: #232136; - color: #6e6a86; -} - -.hljs-emphasis { - font-style: italic; -} - -.hljs-strong { - font-weight: bold; -} diff --git a/pelican/themes/simple/static/css/in.css b/pelican/themes/simple/static/css/in.css deleted file mode 100644 index a9426390..00000000 --- a/pelican/themes/simple/static/css/in.css +++ /dev/null @@ -1,32 +0,0 @@ -@tailwind base; /* Preflight is injected here */ -@tailwind components; -@tailwind utilities; - -@layer base { - html { - /* use serif font style as default */ - /*@apply font-serif;*/ - @apply font-sans; - } - a { - @apply text-rp-moon-iris underline decoration-4 underline-offset-4; - } - h1 { - @apply font-sans text-7xl text-rp-moon-gold prose prose-h1:text-rp-moon-gold; - } - h2 { - @apply font-sans text-5xl text-rp-moon-gold prose prose-h1:text-rp-moon-gold; - } - h3 { - @apply font-sans text-4xl text-rp-moon-gold prose prose-h1:text-rp-moon-gold; - } - h4 { - @apply font-sans text-3xl text-rp-moon-gold prose prose-h1:text-rp-moon-gold; - } - h5 { - @apply font-sans text-2xl mb-6 mt-4; - } - h6 { - @apply font-sans text-xl mb-6 mt-4; - } -} diff --git a/pelican/themes/simple/static/css/out.css b/pelican/themes/simple/static/css/out.css deleted file mode 100644 index 1882c378..00000000 --- a/pelican/themes/simple/static/css/out.css +++ /dev/null @@ -1,3965 +0,0 @@ -*, ::before, ::after { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - -/* -! tailwindcss v3.4.13 | MIT License | https://tailwindcss.com -*/ - -/* -1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) -2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) -*/ - -*, -::before, -::after { - box-sizing: border-box; - /* 1 */ - border-width: 0; - /* 2 */ - border-style: solid; - /* 2 */ - border-color: #e5e7eb; - /* 2 */ -} - -::before, -::after { - --tw-content: ''; -} - -/* -1. Use a consistent sensible line-height in all browsers. -2. Prevent adjustments of font size after orientation changes in iOS. -3. Use a more readable tab size. -4. Use the user's configured `sans` font-family by default. -5. Use the user's configured `sans` font-feature-settings by default. -6. Use the user's configured `sans` font-variation-settings by default. -7. Disable tap highlights on iOS -*/ - -html, -:host { - line-height: 1.5; - /* 1 */ - -webkit-text-size-adjust: 100%; - /* 2 */ - -moz-tab-size: 4; - /* 3 */ - -o-tab-size: 4; - tab-size: 4; - /* 3 */ - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - /* 4 */ - font-feature-settings: normal; - /* 5 */ - font-variation-settings: normal; - /* 6 */ - -webkit-tap-highlight-color: transparent; - /* 7 */ -} - -/* -1. Remove the margin in all browsers. -2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. -*/ - -body { - margin: 0; - /* 1 */ - line-height: inherit; - /* 2 */ -} - -/* -1. Add the correct height in Firefox. -2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) -3. Ensure horizontal rules are visible by default. -*/ - -hr { - height: 0; - /* 1 */ - color: inherit; - /* 2 */ - border-top-width: 1px; - /* 3 */ -} - -/* -Add the correct text decoration in Chrome, Edge, and Safari. -*/ - -abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; -} - -/* -Remove the default font size and weight for headings. -*/ - -h1, -h2, -h3, -h4, -h5, -h6 { - font-size: inherit; - font-weight: inherit; -} - -/* -Reset links to optimize for opt-in styling instead of opt-out. -*/ - -a { - color: inherit; - text-decoration: inherit; -} - -/* -Add the correct font weight in Edge and Safari. -*/ - -b, -strong { - font-weight: bolder; -} - -/* -1. Use the user's configured `mono` font-family by default. -2. Use the user's configured `mono` font-feature-settings by default. -3. Use the user's configured `mono` font-variation-settings by default. -4. Correct the odd `em` font sizing in all browsers. -*/ - -code, -kbd, -samp, -pre { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - /* 1 */ - font-feature-settings: normal; - /* 2 */ - font-variation-settings: normal; - /* 3 */ - font-size: 1em; - /* 4 */ -} - -/* -Add the correct font size in all browsers. -*/ - -small { - font-size: 80%; -} - -/* -Prevent `sub` and `sup` elements from affecting the line height in all browsers. -*/ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* -1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) -2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) -3. Remove gaps between table borders by default. -*/ - -table { - text-indent: 0; - /* 1 */ - border-color: inherit; - /* 2 */ - border-collapse: collapse; - /* 3 */ -} - -/* -1. Change the font styles in all browsers. -2. Remove the margin in Firefox and Safari. -3. Remove default padding in all browsers. -*/ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; - /* 1 */ - font-feature-settings: inherit; - /* 1 */ - font-variation-settings: inherit; - /* 1 */ - font-size: 100%; - /* 1 */ - font-weight: inherit; - /* 1 */ - line-height: inherit; - /* 1 */ - letter-spacing: inherit; - /* 1 */ - color: inherit; - /* 1 */ - margin: 0; - /* 2 */ - padding: 0; - /* 3 */ -} - -/* -Remove the inheritance of text transform in Edge and Firefox. -*/ - -button, -select { - text-transform: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Remove default button styles. -*/ - -button, -input:where([type='button']), -input:where([type='reset']), -input:where([type='submit']) { - -webkit-appearance: button; - /* 1 */ - background-color: transparent; - /* 2 */ - background-image: none; - /* 2 */ -} - -/* -Use the modern Firefox focus style for all focusable elements. -*/ - -:-moz-focusring { - outline: auto; -} - -/* -Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) -*/ - -:-moz-ui-invalid { - box-shadow: none; -} - -/* -Add the correct vertical alignment in Chrome and Firefox. -*/ - -progress { - vertical-align: baseline; -} - -/* -Correct the cursor style of increment and decrement buttons in Safari. -*/ - -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} - -/* -1. Correct the odd appearance in Chrome and Safari. -2. Correct the outline style in Safari. -*/ - -[type='search'] { - -webkit-appearance: textfield; - /* 1 */ - outline-offset: -2px; - /* 2 */ -} - -/* -Remove the inner padding in Chrome and Safari on macOS. -*/ - -::-webkit-search-decoration { - -webkit-appearance: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Change font properties to `inherit` in Safari. -*/ - -::-webkit-file-upload-button { - -webkit-appearance: button; - /* 1 */ - font: inherit; - /* 2 */ -} - -/* -Add the correct display in Chrome and Safari. -*/ - -summary { - display: list-item; -} - -/* -Removes the default spacing and border for appropriate elements. -*/ - -blockquote, -dl, -dd, -h1, -h2, -h3, -h4, -h5, -h6, -hr, -figure, -p, -pre { - margin: 0; -} - -fieldset { - margin: 0; - padding: 0; -} - -legend { - padding: 0; -} - -ol, -ul, -menu { - list-style: none; - margin: 0; - padding: 0; -} - -/* -Reset default styling for dialogs. -*/ - -dialog { - padding: 0; -} - -/* -Prevent resizing textareas horizontally by default. -*/ - -textarea { - resize: vertical; -} - -/* -1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) -2. Set the default placeholder color to the user's configured gray 400 color. -*/ - -input::-moz-placeholder, textarea::-moz-placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -input::placeholder, -textarea::placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -/* -Set the default cursor for buttons. -*/ - -button, -[role="button"] { - cursor: pointer; -} - -/* -Make sure disabled buttons don't get the pointer cursor. -*/ - -:disabled { - cursor: default; -} - -/* -1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) -2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) - This can trigger a poorly considered lint error in some tools but is included by design. -*/ - -img, -svg, -video, -canvas, -audio, -iframe, -embed, -object { - display: block; - /* 1 */ - vertical-align: middle; - /* 2 */ -} - -/* -Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) -*/ - -img, -video { - max-width: 100%; - height: auto; -} - -/* Make elements with the HTML hidden attribute stay hidden by default */ - -[hidden] { - display: none; -} - -html { - /* use serif font style as default */ - /*@apply font-serif;*/ - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; -} - -a { - --tw-text-opacity: 1; - color: rgb(144 122 169 / var(--tw-text-opacity)); - text-decoration-line: underline; - text-decoration-thickness: 4px; - text-underline-offset: 4px; -} - -h1 { - color: var(--tw-prose-body); - max-width: 65ch; -} - -h1 :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -h1 :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-lead); - font-size: 1.25em; - line-height: 1.6; - margin-top: 1.2em; - margin-bottom: 1.2em; -} - -h1 :where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-links); - text-decoration: underline; - font-weight: 500; -} - -h1 :where(strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-bold); - font-weight: 600; -} - -h1 :where(a strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h1 :where(blockquote strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h1 :where(thead th strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h1 :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -h1 :where(ol[type="A"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -h1 :where(ol[type="a"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -h1 :where(ol[type="A" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -h1 :where(ol[type="a" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -h1 :where(ol[type="I"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -h1 :where(ol[type="i"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -h1 :where(ol[type="I" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -h1 :where(ol[type="i" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -h1 :where(ol[type="1"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; -} - -h1 :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: disc; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -h1 :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - font-weight: 400; - color: var(--tw-prose-counters); -} - -h1 :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - color: var(--tw-prose-bullets); -} - -h1 :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - margin-top: 1.25em; -} - -h1 :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-color: var(--tw-prose-hr); - border-top-width: 1px; - margin-top: 3em; - margin-bottom: 3em; -} - -h1 :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-style: italic; - color: var(--tw-prose-quotes); - border-inline-start-width: 0.25rem; - border-inline-start-color: var(--tw-prose-quote-borders); - quotes: "\201C""\201D""\2018""\2019"; - margin-top: 1.6em; - margin-bottom: 1.6em; - padding-inline-start: 1em; -} - -h1 :where(blockquote p:first-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: open-quote; -} - -h1 :where(blockquote p:last-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: close-quote; -} - -h1 :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 800; - font-size: 2.25em; - margin-top: 0; - margin-bottom: 0.8888889em; - line-height: 1.1111111; -} - -h1 :where(h1 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 900; - color: inherit; -} - -h1 :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 700; - font-size: 1.5em; - margin-top: 2em; - margin-bottom: 1em; - line-height: 1.3333333; -} - -h1 :where(h2 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 800; - color: inherit; -} - -h1 :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - font-size: 1.25em; - margin-top: 1.6em; - margin-bottom: 0.6em; - line-height: 1.6; -} - -h1 :where(h3 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -h1 :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - margin-top: 1.5em; - margin-bottom: 0.5em; - line-height: 1.5; -} - -h1 :where(h4 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -h1 :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h1 :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - display: block; - margin-top: 2em; - margin-bottom: 2em; -} - -h1 :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h1 :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-family: inherit; - color: var(--tw-prose-kbd); - box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%); - font-size: 0.875em; - border-radius: 0.3125rem; - padding-top: 0.1875em; - padding-inline-end: 0.375em; - padding-bottom: 0.1875em; - padding-inline-start: 0.375em; -} - -h1 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-code); - font-weight: 600; - font-size: 0.875em; -} - -h1 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: ""; -} - -h1 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: ""; -} - -h1 :where(a code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h1 :where(h1 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h1 :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.875em; -} - -h1 :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.9em; -} - -h1 :where(h4 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h1 :where(blockquote code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h1 :where(thead th code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h1 :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-pre-code); - background-color: var(--tw-prose-pre-bg); - overflow-x: auto; - font-weight: 400; - font-size: 0.875em; - line-height: 1.7142857; - margin-top: 1.7142857em; - margin-bottom: 1.7142857em; - border-radius: 0.375rem; - padding-top: 0.8571429em; - padding-inline-end: 1.1428571em; - padding-bottom: 0.8571429em; - padding-inline-start: 1.1428571em; -} - -h1 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - background-color: transparent; - border-width: 0; - border-radius: 0; - padding: 0; - font-weight: inherit; - color: inherit; - font-size: inherit; - font-family: inherit; - line-height: inherit; -} - -h1 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: none; -} - -h1 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: none; -} - -h1 :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - width: 100%; - table-layout: auto; - margin-top: 2em; - margin-bottom: 2em; - font-size: 0.875em; - line-height: 1.7142857; -} - -h1 :where(thead):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-th-borders); -} - -h1 :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - vertical-align: bottom; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -h1 :where(tbody tr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-td-borders); -} - -h1 :where(tbody tr:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 0; -} - -h1 :where(tbody td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: baseline; -} - -h1 :where(tfoot):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-top-width: 1px; - border-top-color: var(--tw-prose-th-borders); -} - -h1 :where(tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: top; -} - -h1 :where(th, td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - text-align: start; -} - -h1 :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -h1 :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-captions); - font-size: 0.875em; - line-height: 1.4285714; - margin-top: 0.8571429em; -} - -h1 { - --tw-prose-body: #374151; - --tw-prose-headings: #111827; - --tw-prose-lead: #4b5563; - --tw-prose-links: #111827; - --tw-prose-bold: #111827; - --tw-prose-counters: #6b7280; - --tw-prose-bullets: #d1d5db; - --tw-prose-hr: #e5e7eb; - --tw-prose-quotes: #111827; - --tw-prose-quote-borders: #e5e7eb; - --tw-prose-captions: #6b7280; - --tw-prose-kbd: #111827; - --tw-prose-kbd-shadows: 17 24 39; - --tw-prose-code: #111827; - --tw-prose-pre-code: #e5e7eb; - --tw-prose-pre-bg: #1f2937; - --tw-prose-th-borders: #d1d5db; - --tw-prose-td-borders: #e5e7eb; - --tw-prose-invert-body: #d1d5db; - --tw-prose-invert-headings: #fff; - --tw-prose-invert-lead: #9ca3af; - --tw-prose-invert-links: #fff; - --tw-prose-invert-bold: #fff; - --tw-prose-invert-counters: #9ca3af; - --tw-prose-invert-bullets: #4b5563; - --tw-prose-invert-hr: #374151; - --tw-prose-invert-quotes: #f3f4f6; - --tw-prose-invert-quote-borders: #374151; - --tw-prose-invert-captions: #9ca3af; - --tw-prose-invert-kbd: #fff; - --tw-prose-invert-kbd-shadows: 255 255 255; - --tw-prose-invert-code: #fff; - --tw-prose-invert-pre-code: #d1d5db; - --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); - --tw-prose-invert-th-borders: #4b5563; - --tw-prose-invert-td-borders: #374151; - font-size: 1rem; - line-height: 1.75; -} - -h1 :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -h1 :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - margin-bottom: 0.5em; -} - -h1 :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -h1 :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -h1 :where(.prose > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -h1 :where(.prose > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -h1 :where(.prose > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -h1 :where(.prose > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -h1 :where(.prose > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -h1 :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -h1 :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -h1 :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - padding-inline-start: 1.625em; -} - -h1 :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h1 :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h1 :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h1 :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h1 :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -h1 :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -h1 :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-top: 0.5714286em; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -h1 :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -h1 :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -h1 :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h1 :where(.prose > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h1 :where(.prose > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 0; -} - -h1 { - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - font-size: 4.5rem; - line-height: 1; - --tw-text-opacity: 1; - color: rgb(234 157 52 / var(--tw-text-opacity)); -} - -h1 :is(:where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *))) { - --tw-text-opacity: 1; - color: rgb(234 157 52 / var(--tw-text-opacity)); -} - -h2 { - color: var(--tw-prose-body); - max-width: 65ch; -} - -h2 :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -h2 :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-lead); - font-size: 1.25em; - line-height: 1.6; - margin-top: 1.2em; - margin-bottom: 1.2em; -} - -h2 :where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-links); - text-decoration: underline; - font-weight: 500; -} - -h2 :where(strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-bold); - font-weight: 600; -} - -h2 :where(a strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h2 :where(blockquote strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h2 :where(thead th strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h2 :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -h2 :where(ol[type="A"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -h2 :where(ol[type="a"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -h2 :where(ol[type="A" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -h2 :where(ol[type="a" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -h2 :where(ol[type="I"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -h2 :where(ol[type="i"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -h2 :where(ol[type="I" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -h2 :where(ol[type="i" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -h2 :where(ol[type="1"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; -} - -h2 :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: disc; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -h2 :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - font-weight: 400; - color: var(--tw-prose-counters); -} - -h2 :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - color: var(--tw-prose-bullets); -} - -h2 :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - margin-top: 1.25em; -} - -h2 :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-color: var(--tw-prose-hr); - border-top-width: 1px; - margin-top: 3em; - margin-bottom: 3em; -} - -h2 :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-style: italic; - color: var(--tw-prose-quotes); - border-inline-start-width: 0.25rem; - border-inline-start-color: var(--tw-prose-quote-borders); - quotes: "\201C""\201D""\2018""\2019"; - margin-top: 1.6em; - margin-bottom: 1.6em; - padding-inline-start: 1em; -} - -h2 :where(blockquote p:first-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: open-quote; -} - -h2 :where(blockquote p:last-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: close-quote; -} - -h2 :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 800; - font-size: 2.25em; - margin-top: 0; - margin-bottom: 0.8888889em; - line-height: 1.1111111; -} - -h2 :where(h1 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 900; - color: inherit; -} - -h2 :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 700; - font-size: 1.5em; - margin-top: 2em; - margin-bottom: 1em; - line-height: 1.3333333; -} - -h2 :where(h2 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 800; - color: inherit; -} - -h2 :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - font-size: 1.25em; - margin-top: 1.6em; - margin-bottom: 0.6em; - line-height: 1.6; -} - -h2 :where(h3 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -h2 :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - margin-top: 1.5em; - margin-bottom: 0.5em; - line-height: 1.5; -} - -h2 :where(h4 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -h2 :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h2 :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - display: block; - margin-top: 2em; - margin-bottom: 2em; -} - -h2 :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h2 :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-family: inherit; - color: var(--tw-prose-kbd); - box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%); - font-size: 0.875em; - border-radius: 0.3125rem; - padding-top: 0.1875em; - padding-inline-end: 0.375em; - padding-bottom: 0.1875em; - padding-inline-start: 0.375em; -} - -h2 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-code); - font-weight: 600; - font-size: 0.875em; -} - -h2 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: ""; -} - -h2 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: ""; -} - -h2 :where(a code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h2 :where(h1 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h2 :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.875em; -} - -h2 :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.9em; -} - -h2 :where(h4 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h2 :where(blockquote code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h2 :where(thead th code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h2 :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-pre-code); - background-color: var(--tw-prose-pre-bg); - overflow-x: auto; - font-weight: 400; - font-size: 0.875em; - line-height: 1.7142857; - margin-top: 1.7142857em; - margin-bottom: 1.7142857em; - border-radius: 0.375rem; - padding-top: 0.8571429em; - padding-inline-end: 1.1428571em; - padding-bottom: 0.8571429em; - padding-inline-start: 1.1428571em; -} - -h2 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - background-color: transparent; - border-width: 0; - border-radius: 0; - padding: 0; - font-weight: inherit; - color: inherit; - font-size: inherit; - font-family: inherit; - line-height: inherit; -} - -h2 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: none; -} - -h2 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: none; -} - -h2 :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - width: 100%; - table-layout: auto; - margin-top: 2em; - margin-bottom: 2em; - font-size: 0.875em; - line-height: 1.7142857; -} - -h2 :where(thead):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-th-borders); -} - -h2 :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - vertical-align: bottom; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -h2 :where(tbody tr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-td-borders); -} - -h2 :where(tbody tr:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 0; -} - -h2 :where(tbody td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: baseline; -} - -h2 :where(tfoot):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-top-width: 1px; - border-top-color: var(--tw-prose-th-borders); -} - -h2 :where(tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: top; -} - -h2 :where(th, td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - text-align: start; -} - -h2 :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -h2 :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-captions); - font-size: 0.875em; - line-height: 1.4285714; - margin-top: 0.8571429em; -} - -h2 { - --tw-prose-body: #374151; - --tw-prose-headings: #111827; - --tw-prose-lead: #4b5563; - --tw-prose-links: #111827; - --tw-prose-bold: #111827; - --tw-prose-counters: #6b7280; - --tw-prose-bullets: #d1d5db; - --tw-prose-hr: #e5e7eb; - --tw-prose-quotes: #111827; - --tw-prose-quote-borders: #e5e7eb; - --tw-prose-captions: #6b7280; - --tw-prose-kbd: #111827; - --tw-prose-kbd-shadows: 17 24 39; - --tw-prose-code: #111827; - --tw-prose-pre-code: #e5e7eb; - --tw-prose-pre-bg: #1f2937; - --tw-prose-th-borders: #d1d5db; - --tw-prose-td-borders: #e5e7eb; - --tw-prose-invert-body: #d1d5db; - --tw-prose-invert-headings: #fff; - --tw-prose-invert-lead: #9ca3af; - --tw-prose-invert-links: #fff; - --tw-prose-invert-bold: #fff; - --tw-prose-invert-counters: #9ca3af; - --tw-prose-invert-bullets: #4b5563; - --tw-prose-invert-hr: #374151; - --tw-prose-invert-quotes: #f3f4f6; - --tw-prose-invert-quote-borders: #374151; - --tw-prose-invert-captions: #9ca3af; - --tw-prose-invert-kbd: #fff; - --tw-prose-invert-kbd-shadows: 255 255 255; - --tw-prose-invert-code: #fff; - --tw-prose-invert-pre-code: #d1d5db; - --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); - --tw-prose-invert-th-borders: #4b5563; - --tw-prose-invert-td-borders: #374151; - font-size: 1rem; - line-height: 1.75; -} - -h2 :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -h2 :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - margin-bottom: 0.5em; -} - -h2 :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -h2 :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -h2 :where(.prose > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -h2 :where(.prose > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -h2 :where(.prose > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -h2 :where(.prose > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -h2 :where(.prose > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -h2 :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -h2 :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -h2 :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - padding-inline-start: 1.625em; -} - -h2 :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h2 :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h2 :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h2 :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h2 :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -h2 :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -h2 :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-top: 0.5714286em; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -h2 :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -h2 :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -h2 :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h2 :where(.prose > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h2 :where(.prose > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 0; -} - -h2 { - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - font-size: 3rem; - line-height: 1; - --tw-text-opacity: 1; - color: rgb(234 157 52 / var(--tw-text-opacity)); -} - -h2 :is(:where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *))) { - --tw-text-opacity: 1; - color: rgb(234 157 52 / var(--tw-text-opacity)); -} - -h3 { - color: var(--tw-prose-body); - max-width: 65ch; -} - -h3 :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -h3 :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-lead); - font-size: 1.25em; - line-height: 1.6; - margin-top: 1.2em; - margin-bottom: 1.2em; -} - -h3 :where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-links); - text-decoration: underline; - font-weight: 500; -} - -h3 :where(strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-bold); - font-weight: 600; -} - -h3 :where(a strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h3 :where(blockquote strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h3 :where(thead th strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h3 :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -h3 :where(ol[type="A"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -h3 :where(ol[type="a"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -h3 :where(ol[type="A" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -h3 :where(ol[type="a" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -h3 :where(ol[type="I"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -h3 :where(ol[type="i"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -h3 :where(ol[type="I" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -h3 :where(ol[type="i" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -h3 :where(ol[type="1"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; -} - -h3 :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: disc; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -h3 :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - font-weight: 400; - color: var(--tw-prose-counters); -} - -h3 :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - color: var(--tw-prose-bullets); -} - -h3 :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - margin-top: 1.25em; -} - -h3 :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-color: var(--tw-prose-hr); - border-top-width: 1px; - margin-top: 3em; - margin-bottom: 3em; -} - -h3 :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-style: italic; - color: var(--tw-prose-quotes); - border-inline-start-width: 0.25rem; - border-inline-start-color: var(--tw-prose-quote-borders); - quotes: "\201C""\201D""\2018""\2019"; - margin-top: 1.6em; - margin-bottom: 1.6em; - padding-inline-start: 1em; -} - -h3 :where(blockquote p:first-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: open-quote; -} - -h3 :where(blockquote p:last-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: close-quote; -} - -h3 :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 800; - font-size: 2.25em; - margin-top: 0; - margin-bottom: 0.8888889em; - line-height: 1.1111111; -} - -h3 :where(h1 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 900; - color: inherit; -} - -h3 :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 700; - font-size: 1.5em; - margin-top: 2em; - margin-bottom: 1em; - line-height: 1.3333333; -} - -h3 :where(h2 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 800; - color: inherit; -} - -h3 :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - font-size: 1.25em; - margin-top: 1.6em; - margin-bottom: 0.6em; - line-height: 1.6; -} - -h3 :where(h3 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -h3 :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - margin-top: 1.5em; - margin-bottom: 0.5em; - line-height: 1.5; -} - -h3 :where(h4 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -h3 :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h3 :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - display: block; - margin-top: 2em; - margin-bottom: 2em; -} - -h3 :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h3 :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-family: inherit; - color: var(--tw-prose-kbd); - box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%); - font-size: 0.875em; - border-radius: 0.3125rem; - padding-top: 0.1875em; - padding-inline-end: 0.375em; - padding-bottom: 0.1875em; - padding-inline-start: 0.375em; -} - -h3 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-code); - font-weight: 600; - font-size: 0.875em; -} - -h3 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: ""; -} - -h3 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: ""; -} - -h3 :where(a code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h3 :where(h1 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h3 :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.875em; -} - -h3 :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.9em; -} - -h3 :where(h4 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h3 :where(blockquote code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h3 :where(thead th code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h3 :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-pre-code); - background-color: var(--tw-prose-pre-bg); - overflow-x: auto; - font-weight: 400; - font-size: 0.875em; - line-height: 1.7142857; - margin-top: 1.7142857em; - margin-bottom: 1.7142857em; - border-radius: 0.375rem; - padding-top: 0.8571429em; - padding-inline-end: 1.1428571em; - padding-bottom: 0.8571429em; - padding-inline-start: 1.1428571em; -} - -h3 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - background-color: transparent; - border-width: 0; - border-radius: 0; - padding: 0; - font-weight: inherit; - color: inherit; - font-size: inherit; - font-family: inherit; - line-height: inherit; -} - -h3 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: none; -} - -h3 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: none; -} - -h3 :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - width: 100%; - table-layout: auto; - margin-top: 2em; - margin-bottom: 2em; - font-size: 0.875em; - line-height: 1.7142857; -} - -h3 :where(thead):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-th-borders); -} - -h3 :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - vertical-align: bottom; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -h3 :where(tbody tr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-td-borders); -} - -h3 :where(tbody tr:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 0; -} - -h3 :where(tbody td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: baseline; -} - -h3 :where(tfoot):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-top-width: 1px; - border-top-color: var(--tw-prose-th-borders); -} - -h3 :where(tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: top; -} - -h3 :where(th, td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - text-align: start; -} - -h3 :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -h3 :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-captions); - font-size: 0.875em; - line-height: 1.4285714; - margin-top: 0.8571429em; -} - -h3 { - --tw-prose-body: #374151; - --tw-prose-headings: #111827; - --tw-prose-lead: #4b5563; - --tw-prose-links: #111827; - --tw-prose-bold: #111827; - --tw-prose-counters: #6b7280; - --tw-prose-bullets: #d1d5db; - --tw-prose-hr: #e5e7eb; - --tw-prose-quotes: #111827; - --tw-prose-quote-borders: #e5e7eb; - --tw-prose-captions: #6b7280; - --tw-prose-kbd: #111827; - --tw-prose-kbd-shadows: 17 24 39; - --tw-prose-code: #111827; - --tw-prose-pre-code: #e5e7eb; - --tw-prose-pre-bg: #1f2937; - --tw-prose-th-borders: #d1d5db; - --tw-prose-td-borders: #e5e7eb; - --tw-prose-invert-body: #d1d5db; - --tw-prose-invert-headings: #fff; - --tw-prose-invert-lead: #9ca3af; - --tw-prose-invert-links: #fff; - --tw-prose-invert-bold: #fff; - --tw-prose-invert-counters: #9ca3af; - --tw-prose-invert-bullets: #4b5563; - --tw-prose-invert-hr: #374151; - --tw-prose-invert-quotes: #f3f4f6; - --tw-prose-invert-quote-borders: #374151; - --tw-prose-invert-captions: #9ca3af; - --tw-prose-invert-kbd: #fff; - --tw-prose-invert-kbd-shadows: 255 255 255; - --tw-prose-invert-code: #fff; - --tw-prose-invert-pre-code: #d1d5db; - --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); - --tw-prose-invert-th-borders: #4b5563; - --tw-prose-invert-td-borders: #374151; - font-size: 1rem; - line-height: 1.75; -} - -h3 :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -h3 :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - margin-bottom: 0.5em; -} - -h3 :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -h3 :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -h3 :where(.prose > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -h3 :where(.prose > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -h3 :where(.prose > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -h3 :where(.prose > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -h3 :where(.prose > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -h3 :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -h3 :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -h3 :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - padding-inline-start: 1.625em; -} - -h3 :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h3 :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h3 :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h3 :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h3 :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -h3 :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -h3 :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-top: 0.5714286em; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -h3 :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -h3 :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -h3 :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h3 :where(.prose > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h3 :where(.prose > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 0; -} - -h3 { - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - font-size: 2.25rem; - line-height: 2.5rem; - --tw-text-opacity: 1; - color: rgb(234 157 52 / var(--tw-text-opacity)); -} - -h3 :is(:where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *))) { - --tw-text-opacity: 1; - color: rgb(234 157 52 / var(--tw-text-opacity)); -} - -h4 { - color: var(--tw-prose-body); - max-width: 65ch; -} - -h4 :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -h4 :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-lead); - font-size: 1.25em; - line-height: 1.6; - margin-top: 1.2em; - margin-bottom: 1.2em; -} - -h4 :where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-links); - text-decoration: underline; - font-weight: 500; -} - -h4 :where(strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-bold); - font-weight: 600; -} - -h4 :where(a strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h4 :where(blockquote strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h4 :where(thead th strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h4 :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -h4 :where(ol[type="A"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -h4 :where(ol[type="a"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -h4 :where(ol[type="A" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -h4 :where(ol[type="a" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -h4 :where(ol[type="I"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -h4 :where(ol[type="i"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -h4 :where(ol[type="I" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -h4 :where(ol[type="i" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -h4 :where(ol[type="1"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; -} - -h4 :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: disc; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -h4 :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - font-weight: 400; - color: var(--tw-prose-counters); -} - -h4 :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - color: var(--tw-prose-bullets); -} - -h4 :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - margin-top: 1.25em; -} - -h4 :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-color: var(--tw-prose-hr); - border-top-width: 1px; - margin-top: 3em; - margin-bottom: 3em; -} - -h4 :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-style: italic; - color: var(--tw-prose-quotes); - border-inline-start-width: 0.25rem; - border-inline-start-color: var(--tw-prose-quote-borders); - quotes: "\201C""\201D""\2018""\2019"; - margin-top: 1.6em; - margin-bottom: 1.6em; - padding-inline-start: 1em; -} - -h4 :where(blockquote p:first-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: open-quote; -} - -h4 :where(blockquote p:last-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: close-quote; -} - -h4 :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 800; - font-size: 2.25em; - margin-top: 0; - margin-bottom: 0.8888889em; - line-height: 1.1111111; -} - -h4 :where(h1 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 900; - color: inherit; -} - -h4 :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 700; - font-size: 1.5em; - margin-top: 2em; - margin-bottom: 1em; - line-height: 1.3333333; -} - -h4 :where(h2 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 800; - color: inherit; -} - -h4 :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - font-size: 1.25em; - margin-top: 1.6em; - margin-bottom: 0.6em; - line-height: 1.6; -} - -h4 :where(h3 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -h4 :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - margin-top: 1.5em; - margin-bottom: 0.5em; - line-height: 1.5; -} - -h4 :where(h4 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -h4 :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h4 :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - display: block; - margin-top: 2em; - margin-bottom: 2em; -} - -h4 :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h4 :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-family: inherit; - color: var(--tw-prose-kbd); - box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%); - font-size: 0.875em; - border-radius: 0.3125rem; - padding-top: 0.1875em; - padding-inline-end: 0.375em; - padding-bottom: 0.1875em; - padding-inline-start: 0.375em; -} - -h4 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-code); - font-weight: 600; - font-size: 0.875em; -} - -h4 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: ""; -} - -h4 :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: ""; -} - -h4 :where(a code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h4 :where(h1 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h4 :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.875em; -} - -h4 :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.9em; -} - -h4 :where(h4 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h4 :where(blockquote code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h4 :where(thead th code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -h4 :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-pre-code); - background-color: var(--tw-prose-pre-bg); - overflow-x: auto; - font-weight: 400; - font-size: 0.875em; - line-height: 1.7142857; - margin-top: 1.7142857em; - margin-bottom: 1.7142857em; - border-radius: 0.375rem; - padding-top: 0.8571429em; - padding-inline-end: 1.1428571em; - padding-bottom: 0.8571429em; - padding-inline-start: 1.1428571em; -} - -h4 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - background-color: transparent; - border-width: 0; - border-radius: 0; - padding: 0; - font-weight: inherit; - color: inherit; - font-size: inherit; - font-family: inherit; - line-height: inherit; -} - -h4 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: none; -} - -h4 :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: none; -} - -h4 :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - width: 100%; - table-layout: auto; - margin-top: 2em; - margin-bottom: 2em; - font-size: 0.875em; - line-height: 1.7142857; -} - -h4 :where(thead):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-th-borders); -} - -h4 :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - vertical-align: bottom; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -h4 :where(tbody tr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-td-borders); -} - -h4 :where(tbody tr:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 0; -} - -h4 :where(tbody td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: baseline; -} - -h4 :where(tfoot):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-top-width: 1px; - border-top-color: var(--tw-prose-th-borders); -} - -h4 :where(tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: top; -} - -h4 :where(th, td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - text-align: start; -} - -h4 :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -h4 :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-captions); - font-size: 0.875em; - line-height: 1.4285714; - margin-top: 0.8571429em; -} - -h4 { - --tw-prose-body: #374151; - --tw-prose-headings: #111827; - --tw-prose-lead: #4b5563; - --tw-prose-links: #111827; - --tw-prose-bold: #111827; - --tw-prose-counters: #6b7280; - --tw-prose-bullets: #d1d5db; - --tw-prose-hr: #e5e7eb; - --tw-prose-quotes: #111827; - --tw-prose-quote-borders: #e5e7eb; - --tw-prose-captions: #6b7280; - --tw-prose-kbd: #111827; - --tw-prose-kbd-shadows: 17 24 39; - --tw-prose-code: #111827; - --tw-prose-pre-code: #e5e7eb; - --tw-prose-pre-bg: #1f2937; - --tw-prose-th-borders: #d1d5db; - --tw-prose-td-borders: #e5e7eb; - --tw-prose-invert-body: #d1d5db; - --tw-prose-invert-headings: #fff; - --tw-prose-invert-lead: #9ca3af; - --tw-prose-invert-links: #fff; - --tw-prose-invert-bold: #fff; - --tw-prose-invert-counters: #9ca3af; - --tw-prose-invert-bullets: #4b5563; - --tw-prose-invert-hr: #374151; - --tw-prose-invert-quotes: #f3f4f6; - --tw-prose-invert-quote-borders: #374151; - --tw-prose-invert-captions: #9ca3af; - --tw-prose-invert-kbd: #fff; - --tw-prose-invert-kbd-shadows: 255 255 255; - --tw-prose-invert-code: #fff; - --tw-prose-invert-pre-code: #d1d5db; - --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); - --tw-prose-invert-th-borders: #4b5563; - --tw-prose-invert-td-borders: #374151; - font-size: 1rem; - line-height: 1.75; -} - -h4 :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -h4 :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - margin-bottom: 0.5em; -} - -h4 :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -h4 :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -h4 :where(.prose > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -h4 :where(.prose > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -h4 :where(.prose > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -h4 :where(.prose > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -h4 :where(.prose > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -h4 :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -h4 :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -h4 :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - padding-inline-start: 1.625em; -} - -h4 :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h4 :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h4 :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h4 :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h4 :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -h4 :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -h4 :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-top: 0.5714286em; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -h4 :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -h4 :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -h4 :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -h4 :where(.prose > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -h4 :where(.prose > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 0; -} - -h4 { - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - font-size: 1.875rem; - line-height: 2.25rem; - --tw-text-opacity: 1; - color: rgb(234 157 52 / var(--tw-text-opacity)); -} - -h4 :is(:where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *))) { - --tw-text-opacity: 1; - color: rgb(234 157 52 / var(--tw-text-opacity)); -} - -h5 { - margin-bottom: 1.5rem; - margin-top: 1rem; - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - font-size: 1.5rem; - line-height: 2rem; -} - -h6 { - margin-bottom: 1.5rem; - margin-top: 1rem; - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - font-size: 1.25rem; - line-height: 1.75rem; -} - -/* Preflight is injected here */ - -.prose { - color: var(--tw-prose-body); - max-width: 65ch; -} - -.prose :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -.prose :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-lead); - font-size: 1.25em; - line-height: 1.6; - margin-top: 1.2em; - margin-bottom: 1.2em; -} - -.prose :where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-links); - text-decoration: underline; - font-weight: 500; -} - -.prose :where(strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-bold); - font-weight: 600; -} - -.prose :where(a strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(blockquote strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(thead th strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -.prose :where(ol[type="A"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -.prose :where(ol[type="a"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -.prose :where(ol[type="A" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -.prose :where(ol[type="a" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -.prose :where(ol[type="I"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -.prose :where(ol[type="i"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -.prose :where(ol[type="I" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -.prose :where(ol[type="i" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -.prose :where(ol[type="1"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; -} - -.prose :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: disc; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -.prose :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - font-weight: 400; - color: var(--tw-prose-counters); -} - -.prose :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - color: var(--tw-prose-bullets); -} - -.prose :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - margin-top: 1.25em; -} - -.prose :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-color: var(--tw-prose-hr); - border-top-width: 1px; - margin-top: 3em; - margin-bottom: 3em; -} - -.prose :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-style: italic; - color: var(--tw-prose-quotes); - border-inline-start-width: 0.25rem; - border-inline-start-color: var(--tw-prose-quote-borders); - quotes: "\201C""\201D""\2018""\2019"; - margin-top: 1.6em; - margin-bottom: 1.6em; - padding-inline-start: 1em; -} - -.prose :where(blockquote p:first-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: open-quote; -} - -.prose :where(blockquote p:last-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: close-quote; -} - -.prose :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 800; - font-size: 2.25em; - margin-top: 0; - margin-bottom: 0.8888889em; - line-height: 1.1111111; -} - -.prose :where(h1 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 900; - color: inherit; -} - -.prose :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 700; - font-size: 1.5em; - margin-top: 2em; - margin-bottom: 1em; - line-height: 1.3333333; -} - -.prose :where(h2 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 800; - color: inherit; -} - -.prose :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - font-size: 1.25em; - margin-top: 1.6em; - margin-bottom: 0.6em; - line-height: 1.6; -} - -.prose :where(h3 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -.prose :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - margin-top: 1.5em; - margin-bottom: 0.5em; - line-height: 1.5; -} - -.prose :where(h4 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -.prose :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -.prose :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - display: block; - margin-top: 2em; - margin-bottom: 2em; -} - -.prose :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -.prose :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-family: inherit; - color: var(--tw-prose-kbd); - box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%); - font-size: 0.875em; - border-radius: 0.3125rem; - padding-top: 0.1875em; - padding-inline-end: 0.375em; - padding-bottom: 0.1875em; - padding-inline-start: 0.375em; -} - -.prose :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-code); - font-weight: 600; - font-size: 0.875em; -} - -.prose :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: ""; -} - -.prose :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: ""; -} - -.prose :where(a code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(h1 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.875em; -} - -.prose :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.9em; -} - -.prose :where(h4 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(blockquote code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(thead th code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-pre-code); - background-color: var(--tw-prose-pre-bg); - overflow-x: auto; - font-weight: 400; - font-size: 0.875em; - line-height: 1.7142857; - margin-top: 1.7142857em; - margin-bottom: 1.7142857em; - border-radius: 0.375rem; - padding-top: 0.8571429em; - padding-inline-end: 1.1428571em; - padding-bottom: 0.8571429em; - padding-inline-start: 1.1428571em; -} - -.prose :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - background-color: transparent; - border-width: 0; - border-radius: 0; - padding: 0; - font-weight: inherit; - color: inherit; - font-size: inherit; - font-family: inherit; - line-height: inherit; -} - -.prose :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: none; -} - -.prose :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: none; -} - -.prose :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - width: 100%; - table-layout: auto; - margin-top: 2em; - margin-bottom: 2em; - font-size: 0.875em; - line-height: 1.7142857; -} - -.prose :where(thead):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-th-borders); -} - -.prose :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - vertical-align: bottom; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -.prose :where(tbody tr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-td-borders); -} - -.prose :where(tbody tr:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 0; -} - -.prose :where(tbody td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: baseline; -} - -.prose :where(tfoot):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-top-width: 1px; - border-top-color: var(--tw-prose-th-borders); -} - -.prose :where(tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: top; -} - -.prose :where(th, td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - text-align: start; -} - -.prose :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -.prose :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-captions); - font-size: 0.875em; - line-height: 1.4285714; - margin-top: 0.8571429em; -} - -.prose { - --tw-prose-body: #374151; - --tw-prose-headings: #111827; - --tw-prose-lead: #4b5563; - --tw-prose-links: #111827; - --tw-prose-bold: #111827; - --tw-prose-counters: #6b7280; - --tw-prose-bullets: #d1d5db; - --tw-prose-hr: #e5e7eb; - --tw-prose-quotes: #111827; - --tw-prose-quote-borders: #e5e7eb; - --tw-prose-captions: #6b7280; - --tw-prose-kbd: #111827; - --tw-prose-kbd-shadows: 17 24 39; - --tw-prose-code: #111827; - --tw-prose-pre-code: #e5e7eb; - --tw-prose-pre-bg: #1f2937; - --tw-prose-th-borders: #d1d5db; - --tw-prose-td-borders: #e5e7eb; - --tw-prose-invert-body: #d1d5db; - --tw-prose-invert-headings: #fff; - --tw-prose-invert-lead: #9ca3af; - --tw-prose-invert-links: #fff; - --tw-prose-invert-bold: #fff; - --tw-prose-invert-counters: #9ca3af; - --tw-prose-invert-bullets: #4b5563; - --tw-prose-invert-hr: #374151; - --tw-prose-invert-quotes: #f3f4f6; - --tw-prose-invert-quote-borders: #374151; - --tw-prose-invert-captions: #9ca3af; - --tw-prose-invert-kbd: #fff; - --tw-prose-invert-kbd-shadows: 255 255 255; - --tw-prose-invert-code: #fff; - --tw-prose-invert-pre-code: #d1d5db; - --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); - --tw-prose-invert-th-borders: #4b5563; - --tw-prose-invert-td-borders: #374151; - font-size: 1rem; - line-height: 1.75; -} - -.prose :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -.prose :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - margin-bottom: 0.5em; -} - -.prose :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -.prose :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -.prose :where(.prose > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -.prose :where(.prose > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -.prose :where(.prose > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -.prose :where(.prose > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -.prose :where(.prose > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -.prose :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -.prose :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -.prose :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - padding-inline-start: 1.625em; -} - -.prose :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -.prose :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -.prose :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -.prose :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -.prose :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -.prose :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -.prose :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-top: 0.5714286em; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -.prose :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -.prose :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -.prose :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -.prose :where(.prose > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -.prose :where(.prose > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 0; -} - -.prose-slate { - --tw-prose-body: #334155; - --tw-prose-headings: #0f172a; - --tw-prose-lead: #475569; - --tw-prose-links: #0f172a; - --tw-prose-bold: #0f172a; - --tw-prose-counters: #64748b; - --tw-prose-bullets: #cbd5e1; - --tw-prose-hr: #e2e8f0; - --tw-prose-quotes: #0f172a; - --tw-prose-quote-borders: #e2e8f0; - --tw-prose-captions: #64748b; - --tw-prose-kbd: #0f172a; - --tw-prose-kbd-shadows: 15 23 42; - --tw-prose-code: #0f172a; - --tw-prose-pre-code: #e2e8f0; - --tw-prose-pre-bg: #1e293b; - --tw-prose-th-borders: #cbd5e1; - --tw-prose-td-borders: #e2e8f0; - --tw-prose-invert-body: #cbd5e1; - --tw-prose-invert-headings: #fff; - --tw-prose-invert-lead: #94a3b8; - --tw-prose-invert-links: #fff; - --tw-prose-invert-bold: #fff; - --tw-prose-invert-counters: #94a3b8; - --tw-prose-invert-bullets: #475569; - --tw-prose-invert-hr: #334155; - --tw-prose-invert-quotes: #f1f5f9; - --tw-prose-invert-quote-borders: #334155; - --tw-prose-invert-captions: #94a3b8; - --tw-prose-invert-kbd: #fff; - --tw-prose-invert-kbd-shadows: 255 255 255; - --tw-prose-invert-code: #fff; - --tw-prose-invert-pre-code: #cbd5e1; - --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); - --tw-prose-invert-th-borders: #475569; - --tw-prose-invert-td-borders: #334155; -} - -.prose-gray { - --tw-prose-body: #374151; - --tw-prose-headings: #111827; - --tw-prose-lead: #4b5563; - --tw-prose-links: #111827; - --tw-prose-bold: #111827; - --tw-prose-counters: #6b7280; - --tw-prose-bullets: #d1d5db; - --tw-prose-hr: #e5e7eb; - --tw-prose-quotes: #111827; - --tw-prose-quote-borders: #e5e7eb; - --tw-prose-captions: #6b7280; - --tw-prose-kbd: #111827; - --tw-prose-kbd-shadows: 17 24 39; - --tw-prose-code: #111827; - --tw-prose-pre-code: #e5e7eb; - --tw-prose-pre-bg: #1f2937; - --tw-prose-th-borders: #d1d5db; - --tw-prose-td-borders: #e5e7eb; - --tw-prose-invert-body: #d1d5db; - --tw-prose-invert-headings: #fff; - --tw-prose-invert-lead: #9ca3af; - --tw-prose-invert-links: #fff; - --tw-prose-invert-bold: #fff; - --tw-prose-invert-counters: #9ca3af; - --tw-prose-invert-bullets: #4b5563; - --tw-prose-invert-hr: #374151; - --tw-prose-invert-quotes: #f3f4f6; - --tw-prose-invert-quote-borders: #374151; - --tw-prose-invert-captions: #9ca3af; - --tw-prose-invert-kbd: #fff; - --tw-prose-invert-kbd-shadows: 255 255 255; - --tw-prose-invert-code: #fff; - --tw-prose-invert-pre-code: #d1d5db; - --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); - --tw-prose-invert-th-borders: #4b5563; - --tw-prose-invert-td-borders: #374151; -} - -.absolute { - position: absolute; -} - -.relative { - position: relative; -} - -.bottom-8 { - bottom: 2rem; -} - -.left-0 { - left: 0px; -} - -.col-span-2 { - grid-column: span 2 / span 2; -} - -.col-span-3 { - grid-column: span 3 / span 3; -} - -.mb-12 { - margin-bottom: 3rem; -} - -.block { - display: block; -} - -.inline-block { - display: inline-block; -} - -.flex { - display: flex; -} - -.grid { - display: grid; -} - -.h-\[350px\] { - height: 350px; -} - -.h-full { - height: 100%; -} - -.w-full { - width: 100%; -} - -.list-none { - list-style-type: none; -} - -.grid-cols-5 { - grid-template-columns: repeat(5, minmax(0, 1fr)); -} - -.justify-between { - justify-content: space-between; -} - -.overflow-hidden { - overflow: hidden; -} - -.rounded-lg { - border-radius: 0.5rem; -} - -.bg-gray-700 { - --tw-bg-opacity: 1; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)); -} - -.bg-rp-moon-base { - --tw-bg-opacity: 1; - background-color: rgb(250 244 237 / var(--tw-bg-opacity)); -} - -.bg-rp-moon-overlay { - --tw-bg-opacity: 1; - background-color: rgb(242 233 225 / var(--tw-bg-opacity)); -} - -.bg-rp-moon-surface { - --tw-bg-opacity: 1; - background-color: rgb(255 250 243 / var(--tw-bg-opacity)); -} - -.bg-rp-moon-foam { - --tw-bg-opacity: 1; - background-color: rgb(86 148 159 / var(--tw-bg-opacity)); -} - -.bg-rp-moon-gold { - --tw-bg-opacity: 1; - background-color: rgb(234 157 52 / var(--tw-bg-opacity)); -} - -.object-cover { - -o-object-fit: cover; - object-fit: cover; -} - -.object-center { - -o-object-position: center; - object-position: center; -} - -.p-2 { - padding: 0.5rem; -} - -.p-4 { - padding: 1rem; -} - -.p-8 { - padding: 2rem; -} - -.pb-60 { - padding-bottom: 15rem; -} - -.pt-20 { - padding-top: 5rem; -} - -.text-center { - text-align: center; -} - -.text-2xl { - font-size: 1.5rem; - line-height: 2rem; -} - -.text-3xl { - font-size: 1.875rem; - line-height: 2.25rem; -} - -.font-bold { - font-weight: 700; -} - -.italic { - font-style: italic; -} - -.leading-relaxed { - line-height: 1.625; -} - -.text-green-300 { - --tw-text-opacity: 1; - color: rgb(134 239 172 / var(--tw-text-opacity)); -} - -.text-rp-moon-foam { - --tw-text-opacity: 1; - color: rgb(86 148 159 / var(--tw-text-opacity)); -} - -.text-rp-moon-muted { - --tw-text-opacity: 1; - color: rgb(152 147 165 / var(--tw-text-opacity)); -} - -.text-rp-moon-gold { - --tw-text-opacity: 1; - color: rgb(234 157 52 / var(--tw-text-opacity)); -} - -.text-rp-moon-overlay { - --tw-text-opacity: 1; - color: rgb(242 233 225 / var(--tw-text-opacity)); -} - -.text-rp-moon-text { - --tw-text-opacity: 1; - color: rgb(87 82 121 / var(--tw-text-opacity)); -} - -.no-underline { - text-decoration-line: none; -} - -.opacity-65 { - opacity: 0.65; -} - -@media (min-width: 768px) { - .md\:prose-lg { - font-size: 1.125rem; - line-height: 1.7777778; - } - - .md\:prose-lg :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.3333333em; - margin-bottom: 1.3333333em; - } - - .md\:prose-lg :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 1.2222222em; - line-height: 1.4545455; - margin-top: 1.0909091em; - margin-bottom: 1.0909091em; - } - - .md\:prose-lg :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.6666667em; - margin-bottom: 1.6666667em; - padding-inline-start: 1em; - } - - .md\:prose-lg :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 2.6666667em; - margin-top: 0; - margin-bottom: 0.8333333em; - line-height: 1; - } - - .md\:prose-lg :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 1.6666667em; - margin-top: 1.8666667em; - margin-bottom: 1.0666667em; - line-height: 1.3333333; - } - - .md\:prose-lg :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 1.3333333em; - margin-top: 1.6666667em; - margin-bottom: 0.6666667em; - line-height: 1.5; - } - - .md\:prose-lg :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.7777778em; - margin-bottom: 0.4444444em; - line-height: 1.5555556; - } - - .md\:prose-lg :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.7777778em; - margin-bottom: 1.7777778em; - } - - .md\:prose-lg :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.7777778em; - margin-bottom: 1.7777778em; - } - - .md\:prose-lg :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; - } - - .md\:prose-lg :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.7777778em; - margin-bottom: 1.7777778em; - } - - .md\:prose-lg :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.8888889em; - border-radius: 0.3125rem; - padding-top: 0.2222222em; - padding-inline-end: 0.4444444em; - padding-bottom: 0.2222222em; - padding-inline-start: 0.4444444em; - } - - .md\:prose-lg :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.8888889em; - } - - .md\:prose-lg :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.8666667em; - } - - .md\:prose-lg :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.875em; - } - - .md\:prose-lg :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.8888889em; - line-height: 1.75; - margin-top: 2em; - margin-bottom: 2em; - border-radius: 0.375rem; - padding-top: 1em; - padding-inline-end: 1.5em; - padding-bottom: 1em; - padding-inline-start: 1.5em; - } - - .md\:prose-lg :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.3333333em; - margin-bottom: 1.3333333em; - padding-inline-start: 1.5555556em; - } - - .md\:prose-lg :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.3333333em; - margin-bottom: 1.3333333em; - padding-inline-start: 1.5555556em; - } - - .md\:prose-lg :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.6666667em; - margin-bottom: 0.6666667em; - } - - .md\:prose-lg :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.4444444em; - } - - .md\:prose-lg :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.4444444em; - } - - .md\:prose-lg :where(.md\:prose-lg > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.8888889em; - margin-bottom: 0.8888889em; - } - - .md\:prose-lg :where(.md\:prose-lg > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.3333333em; - } - - .md\:prose-lg :where(.md\:prose-lg > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.3333333em; - } - - .md\:prose-lg :where(.md\:prose-lg > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.3333333em; - } - - .md\:prose-lg :where(.md\:prose-lg > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.3333333em; - } - - .md\:prose-lg :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.8888889em; - margin-bottom: 0.8888889em; - } - - .md\:prose-lg :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.3333333em; - margin-bottom: 1.3333333em; - } - - .md\:prose-lg :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.3333333em; - } - - .md\:prose-lg :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.6666667em; - padding-inline-start: 1.5555556em; - } - - .md\:prose-lg :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 3.1111111em; - margin-bottom: 3.1111111em; - } - - .md\:prose-lg :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - } - - .md\:prose-lg :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - } - - .md\:prose-lg :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - } - - .md\:prose-lg :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - } - - .md\:prose-lg :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.8888889em; - line-height: 1.5; - } - - .md\:prose-lg :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0.75em; - padding-bottom: 0.75em; - padding-inline-start: 0.75em; - } - - .md\:prose-lg :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; - } - - .md\:prose-lg :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; - } - - .md\:prose-lg :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-top: 0.75em; - padding-inline-end: 0.75em; - padding-bottom: 0.75em; - padding-inline-start: 0.75em; - } - - .md\:prose-lg :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; - } - - .md\:prose-lg :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; - } - - .md\:prose-lg :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.7777778em; - margin-bottom: 1.7777778em; - } - - .md\:prose-lg :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; - } - - .md\:prose-lg :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.8888889em; - line-height: 1.5; - margin-top: 1em; - } - - .md\:prose-lg :where(.md\:prose-lg > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - } - - .md\:prose-lg :where(.md\:prose-lg > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 0; - } -} - -@media (min-width: 1024px) { - .lg\:prose-xl { - font-size: 1.25rem; - line-height: 1.8; - } - - .lg\:prose-xl :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.2em; - margin-bottom: 1.2em; - } - - .lg\:prose-xl :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 1.2em; - line-height: 1.5; - margin-top: 1em; - margin-bottom: 1em; - } - - .lg\:prose-xl :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.6em; - margin-bottom: 1.6em; - padding-inline-start: 1.0666667em; - } - - .lg\:prose-xl :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 2.8em; - margin-top: 0; - margin-bottom: 0.8571429em; - line-height: 1; - } - - .lg\:prose-xl :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 1.8em; - margin-top: 1.5555556em; - margin-bottom: 0.8888889em; - line-height: 1.1111111; - } - - .lg\:prose-xl :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 1.5em; - margin-top: 1.6em; - margin-bottom: 0.6666667em; - line-height: 1.3333333; - } - - .lg\:prose-xl :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.8em; - margin-bottom: 0.6em; - line-height: 1.6; - } - - .lg\:prose-xl :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; - } - - .lg\:prose-xl :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; - } - - .lg\:prose-xl :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; - } - - .lg\:prose-xl :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; - } - - .lg\:prose-xl :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.9em; - border-radius: 0.3125rem; - padding-top: 0.25em; - padding-inline-end: 0.4em; - padding-bottom: 0.25em; - padding-inline-start: 0.4em; - } - - .lg\:prose-xl :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.9em; - } - - .lg\:prose-xl :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.8611111em; - } - - .lg\:prose-xl :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.9em; - } - - .lg\:prose-xl :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.9em; - line-height: 1.7777778; - margin-top: 2em; - margin-bottom: 2em; - border-radius: 0.5rem; - padding-top: 1.1111111em; - padding-inline-end: 1.3333333em; - padding-bottom: 1.1111111em; - padding-inline-start: 1.3333333em; - } - - .lg\:prose-xl :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.2em; - margin-bottom: 1.2em; - padding-inline-start: 1.6em; - } - - .lg\:prose-xl :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.2em; - margin-bottom: 1.2em; - padding-inline-start: 1.6em; - } - - .lg\:prose-xl :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.6em; - margin-bottom: 0.6em; - } - - .lg\:prose-xl :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.4em; - } - - .lg\:prose-xl :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.4em; - } - - .lg\:prose-xl :where(.lg\:prose-xl > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.8em; - margin-bottom: 0.8em; - } - - .lg\:prose-xl :where(.lg\:prose-xl > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.2em; - } - - .lg\:prose-xl :where(.lg\:prose-xl > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.2em; - } - - .lg\:prose-xl :where(.lg\:prose-xl > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.2em; - } - - .lg\:prose-xl :where(.lg\:prose-xl > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.2em; - } - - .lg\:prose-xl :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.8em; - margin-bottom: 0.8em; - } - - .lg\:prose-xl :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.2em; - margin-bottom: 1.2em; - } - - .lg\:prose-xl :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.2em; - } - - .lg\:prose-xl :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.6em; - padding-inline-start: 1.6em; - } - - .lg\:prose-xl :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2.8em; - margin-bottom: 2.8em; - } - - .lg\:prose-xl :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - } - - .lg\:prose-xl :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - } - - .lg\:prose-xl :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - } - - .lg\:prose-xl :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - } - - .lg\:prose-xl :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.9em; - line-height: 1.5555556; - } - - .lg\:prose-xl :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0.6666667em; - padding-bottom: 0.8888889em; - padding-inline-start: 0.6666667em; - } - - .lg\:prose-xl :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; - } - - .lg\:prose-xl :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; - } - - .lg\:prose-xl :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-top: 0.8888889em; - padding-inline-end: 0.6666667em; - padding-bottom: 0.8888889em; - padding-inline-start: 0.6666667em; - } - - .lg\:prose-xl :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; - } - - .lg\:prose-xl :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; - } - - .lg\:prose-xl :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; - } - - .lg\:prose-xl :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; - } - - .lg\:prose-xl :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-size: 0.9em; - line-height: 1.5555556; - margin-top: 1em; - } - - .lg\:prose-xl :where(.lg\:prose-xl > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - } - - .lg\:prose-xl :where(.lg\:prose-xl > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 0; - } -} - -.target\:border-blue-400:target { - --tw-border-opacity: 1; - border-color: rgb(96 165 250 / var(--tw-border-opacity)); -} - -.hover\:bg-blue-800:hover { - --tw-bg-opacity: 1; - background-color: rgb(30 64 175 / var(--tw-bg-opacity)); -} - -.hover\:bg-red-800:hover { - --tw-bg-opacity: 1; - background-color: rgb(153 27 27 / var(--tw-bg-opacity)); -} - -.prose-headings\:text-rp-moon-gold :is(:where(h1, h2, h3, h4, h5, h6, th):not(:where([class~="not-prose"],[class~="not-prose"] *))) { - --tw-text-opacity: 1; - color: rgb(234 157 52 / var(--tw-text-opacity)); -} - -.prose-headings\:text-rp-moon-iris :is(:where(h1, h2, h3, h4, h5, h6, th):not(:where([class~="not-prose"],[class~="not-prose"] *))) { - --tw-text-opacity: 1; - color: rgb(144 122 169 / var(--tw-text-opacity)); -} diff --git a/pelican/themes/simple/static/js/highlight.min.js b/pelican/themes/simple/static/js/highlight.min.js deleted file mode 100644 index 5d699ae6..00000000 --- a/pelican/themes/simple/static/js/highlight.min.js +++ /dev/null @@ -1,1213 +0,0 @@ -/*! - Highlight.js v11.9.0 (git: f47103d4f1) - (c) 2006-2023 undefined and other contributors - License: BSD-3-Clause - */ -var hljs=function(){"use strict";function e(n){ -return n instanceof Map?n.clear=n.delete=n.set=()=>{ -throw Error("map is read-only")}:n instanceof Set&&(n.add=n.clear=n.delete=()=>{ -throw Error("set is read-only") -}),Object.freeze(n),Object.getOwnPropertyNames(n).forEach((t=>{ -const a=n[t],i=typeof a;"object"!==i&&"function"!==i||Object.isFrozen(a)||e(a) -})),n}class n{constructor(e){ -void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} -ignoreMatch(){this.isMatchIgnored=!0}}function t(e){ -return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") -}function a(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n] -;return n.forEach((e=>{for(const n in e)t[n]=e[n]})),t}const i=e=>!!e.scope -;class r{constructor(e,n){ -this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){ -this.buffer+=t(e)}openNode(e){if(!i(e))return;const n=((e,{prefix:n})=>{ -if(e.startsWith("language:"))return e.replace("language:","language-") -;if(e.includes(".")){const t=e.split(".") -;return[`${n}${t.shift()}`,...t.map(((e,n)=>`${e}${"_".repeat(n+1)}`))].join(" ") -}return`${n}${e}`})(e.scope,{prefix:this.classPrefix});this.span(n)} -closeNode(e){i(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ -this.buffer+=``}}const s=(e={})=>{const n={children:[]} -;return Object.assign(n,e),n};class o{constructor(){ -this.rootNode=s(),this.stack=[this.rootNode]}get top(){ -return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ -this.top.children.push(e)}openNode(e){const n=s({scope:e}) -;this.add(n),this.stack.push(n)}closeNode(){ -if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ -for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} -walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){ -return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n), -n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){ -"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ -o._collapse(e)})))}}class l extends o{constructor(e){super(),this.options=e} -addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){ -this.closeNode()}__addSublanguage(e,n){const t=e.root -;n&&(t.scope="language:"+n),this.add(t)}toHTML(){ -return new r(this,this.options).value()}finalize(){ -return this.closeAllNodes(),!0}}function c(e){ -return e?"string"==typeof e?e:e.source:null}function d(e){return b("(?=",e,")")} -function g(e){return b("(?:",e,")*")}function u(e){return b("(?:",e,")?")} -function b(...e){return e.map((e=>c(e))).join("")}function m(...e){const n=(e=>{ -const n=e[e.length-1] -;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} -})(e);return"("+(n.capture?"":"?:")+e.map((e=>c(e))).join("|")+")"} -function p(e){return RegExp(e.toString()+"|").exec("").length-1} -const _=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ -;function h(e,{joinWith:n}){let t=0;return e.map((e=>{t+=1;const n=t -;let a=c(e),i="";for(;a.length>0;){const e=_.exec(a);if(!e){i+=a;break} -i+=a.substring(0,e.index), -a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0], -"("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)} -const f="[a-zA-Z]\\w*",E="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",N="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",v={ -begin:"\\\\[\\s\\S]",relevance:0},O={scope:"string",begin:"'",end:"'", -illegal:"\\n",contains:[v]},k={scope:"string",begin:'"',end:'"',illegal:"\\n", -contains:[v]},x=(e,n,t={})=>{const i=a({scope:"comment",begin:e,end:n, -contains:[]},t);i.contains.push({scope:"doctag", -begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)", -end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0}) -;const r=m("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/) -;return i.contains.push({begin:b(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i -},M=x("//","$"),S=x("/\\*","\\*/"),A=x("#","$");var C=Object.freeze({ -__proto__:null,APOS_STRING_MODE:O,BACKSLASH_ESCAPE:v,BINARY_NUMBER_MODE:{ -scope:"number",begin:w,relevance:0},BINARY_NUMBER_RE:w,COMMENT:x, -C_BLOCK_COMMENT_MODE:S,C_LINE_COMMENT_MODE:M,C_NUMBER_MODE:{scope:"number", -begin:N,relevance:0},C_NUMBER_RE:N,END_SAME_AS_BEGIN:e=>Object.assign(e,{ -"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{ -n.data._beginMatch!==e[1]&&n.ignoreMatch()}}),HASH_COMMENT_MODE:A,IDENT_RE:f, -MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+E,relevance:0}, -NUMBER_MODE:{scope:"number",begin:y,relevance:0},NUMBER_RE:y, -PHRASAL_WORDS_MODE:{ -begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ -},QUOTE_STRING_MODE:k,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/, -end:/\/[gimuy]*/,contains:[v,{begin:/\[/,end:/\]/,relevance:0,contains:[v]}]}, -RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", -SHEBANG:(e={})=>{const n=/^#![ ]*\// -;return e.binary&&(e.begin=b(n,/.*\b/,e.binary,/\b.*/)),a({scope:"meta",begin:n, -end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)}, -TITLE_MODE:{scope:"title",begin:f,relevance:0},UNDERSCORE_IDENT_RE:E, -UNDERSCORE_TITLE_MODE:{scope:"title",begin:E,relevance:0}});function T(e,n){ -"."===e.input[e.index-1]&&n.ignoreMatch()}function R(e,n){ -void 0!==e.className&&(e.scope=e.className,delete e.className)}function D(e,n){ -n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", -e.__beforeBegin=T,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, -void 0===e.relevance&&(e.relevance=0))}function I(e,n){ -Array.isArray(e.illegal)&&(e.illegal=m(...e.illegal))}function L(e,n){ -if(e.match){ -if(e.begin||e.end)throw Error("begin & end are not supported with match") -;e.begin=e.match,delete e.match}}function B(e,n){ -void 0===e.relevance&&(e.relevance=1)}const $=(e,n)=>{if(!e.beforeMatch)return -;if(e.starts)throw Error("beforeMatch cannot be used with starts") -;const t=Object.assign({},e);Object.keys(e).forEach((n=>{delete e[n] -})),e.keywords=t.keywords,e.begin=b(t.beforeMatch,d(t.begin)),e.starts={ -relevance:0,contains:[Object.assign(t,{endsParent:!0})] -},e.relevance=0,delete t.beforeMatch -},z=["of","and","for","in","not","or","if","then","parent","list","value"],F="keyword" -;function U(e,n,t=F){const a=Object.create(null) -;return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((t=>{ -Object.assign(a,U(e[t],n,t))})),a;function i(e,t){ -n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((n=>{const t=n.split("|") -;a[t[0]]=[e,j(t[0],t[1])]}))}}function j(e,n){ -return n?Number(n):(e=>z.includes(e.toLowerCase()))(e)?0:1}const P={},K=e=>{ -console.error(e)},H=(e,...n)=>{console.log("WARN: "+e,...n)},q=(e,n)=>{ -P[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),P[`${e}/${n}`]=!0) -},G=Error();function Z(e,n,{key:t}){let a=0;const i=e[t],r={},s={} -;for(let e=1;e<=n.length;e++)s[e+a]=i[e],r[e+a]=!0,a+=p(n[e-1]) -;e[t]=s,e[t]._emit=r,e[t]._multi=!0}function W(e){(e=>{ -e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, -delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ -_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope -}),(e=>{if(Array.isArray(e.begin)){ -if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), -G -;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"), -G;Z(e,e.begin,{key:"beginScope"}),e.begin=h(e.begin,{joinWith:""})}})(e),(e=>{ -if(Array.isArray(e.end)){ -if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"), -G -;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"), -G;Z(e,e.end,{key:"endScope"}),e.end=h(e.end,{joinWith:""})}})(e)}function Q(e){ -function n(n,t){ -return RegExp(c(n),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(t?"g":"")) -}class t{constructor(){ -this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} -addRule(e,n){ -n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]), -this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) -;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(h(e,{joinWith:"|" -}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex -;const n=this.matcherRe.exec(e);if(!n)return null -;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t] -;return n.splice(0,t),Object.assign(n,a)}}class i{constructor(){ -this.rules=[],this.multiRegexes=[], -this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ -if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t -;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))), -n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){ -return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){ -this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){ -const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex -;let t=n.exec(e) -;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{ -const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)} -return t&&(this.regexIndex+=t.position+1, -this.regexIndex===this.count&&this.considerAll()),t}} -if(e.compilerExtensions||(e.compilerExtensions=[]), -e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") -;return e.classNameAliases=a(e.classNameAliases||{}),function t(r,s){const o=r -;if(r.isCompiled)return o -;[R,L,W,$].forEach((e=>e(r,s))),e.compilerExtensions.forEach((e=>e(r,s))), -r.__beforeBegin=null,[D,I,B].forEach((e=>e(r,s))),r.isCompiled=!0;let l=null -;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords), -l=r.keywords.$pattern, -delete r.keywords.$pattern),l=l||/\w+/,r.keywords&&(r.keywords=U(r.keywords,e.case_insensitive)), -o.keywordPatternRe=n(l,!0), -s&&(r.begin||(r.begin=/\B|\b/),o.beginRe=n(o.begin),r.end||r.endsWithParent||(r.end=/\B|\b/), -r.end&&(o.endRe=n(o.end)), -o.terminatorEnd=c(o.end)||"",r.endsWithParent&&s.terminatorEnd&&(o.terminatorEnd+=(r.end?"|":"")+s.terminatorEnd)), -r.illegal&&(o.illegalRe=n(r.illegal)), -r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((n=>a(e,{ -variants:null},n)))),e.cachedVariants?e.cachedVariants:X(e)?a(e,{ -starts:e.starts?a(e.starts):null -}):Object.isFrozen(e)?a(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{t(e,o) -})),r.starts&&t(r.starts,s),o.matcher=(e=>{const n=new i -;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin" -}))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end" -}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function X(e){ -return!!e&&(e.endsWithParent||X(e.starts))}class V extends Error{ -constructor(e,n){super(e),this.name="HTMLInjectionError",this.html=n}} -const J=t,Y=a,ee=Symbol("nomatch"),ne=t=>{ -const a=Object.create(null),i=Object.create(null),r=[];let s=!0 -;const o="Could not find the language '{}', did you forget to load/include a language module?",c={ -disableAutodetect:!0,name:"Plain text",contains:[]};let p={ -ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, -languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", -cssSelector:"pre code",languages:null,__emitter:l};function _(e){ -return p.noHighlightRe.test(e)}function h(e,n,t){let a="",i="" -;"object"==typeof n?(a=e, -t=n.ignoreIllegals,i=n.language):(q("10.7.0","highlight(lang, code, ...args) has been deprecated."), -q("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), -i=e,a=n),void 0===t&&(t=!0);const r={code:a,language:i};x("before:highlight",r) -;const s=r.result?r.result:f(r.language,r.code,t) -;return s.code=r.code,x("after:highlight",s),s}function f(e,t,i,r){ -const l=Object.create(null);function c(){if(!x.keywords)return void S.addText(A) -;let e=0;x.keywordPatternRe.lastIndex=0;let n=x.keywordPatternRe.exec(A),t="" -;for(;n;){t+=A.substring(e,n.index) -;const i=w.case_insensitive?n[0].toLowerCase():n[0],r=(a=i,x.keywords[a]);if(r){ -const[e,a]=r -;if(S.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(C+=a),e.startsWith("_"))t+=n[0];else{ -const t=w.classNameAliases[e]||e;g(n[0],t)}}else t+=n[0] -;e=x.keywordPatternRe.lastIndex,n=x.keywordPatternRe.exec(A)}var a -;t+=A.substring(e),S.addText(t)}function d(){null!=x.subLanguage?(()=>{ -if(""===A)return;let e=null;if("string"==typeof x.subLanguage){ -if(!a[x.subLanguage])return void S.addText(A) -;e=f(x.subLanguage,A,!0,M[x.subLanguage]),M[x.subLanguage]=e._top -}else e=E(A,x.subLanguage.length?x.subLanguage:null) -;x.relevance>0&&(C+=e.relevance),S.__addSublanguage(e._emitter,e.language) -})():c(),A=""}function g(e,n){ -""!==e&&(S.startScope(n),S.addText(e),S.endScope())}function u(e,n){let t=1 -;const a=n.length-1;for(;t<=a;){if(!e._emit[t]){t++;continue} -const a=w.classNameAliases[e[t]]||e[t],i=n[t];a?g(i,a):(A=i,c(),A=""),t++}} -function b(e,n){ -return e.scope&&"string"==typeof e.scope&&S.openNode(w.classNameAliases[e.scope]||e.scope), -e.beginScope&&(e.beginScope._wrap?(g(A,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), -A=""):e.beginScope._multi&&(u(e.beginScope,n),A="")),x=Object.create(e,{parent:{ -value:x}}),x}function m(e,t,a){let i=((e,n)=>{const t=e&&e.exec(n) -;return t&&0===t.index})(e.endRe,a);if(i){if(e["on:end"]){const a=new n(e) -;e["on:end"](t,a),a.isMatchIgnored&&(i=!1)}if(i){ -for(;e.endsParent&&e.parent;)e=e.parent;return e}} -if(e.endsWithParent)return m(e.parent,t,a)}function _(e){ -return 0===x.matcher.regexIndex?(A+=e[0],1):(D=!0,0)}function h(e){ -const n=e[0],a=t.substring(e.index),i=m(x,e,a);if(!i)return ee;const r=x -;x.endScope&&x.endScope._wrap?(d(), -g(n,x.endScope._wrap)):x.endScope&&x.endScope._multi?(d(), -u(x.endScope,e)):r.skip?A+=n:(r.returnEnd||r.excludeEnd||(A+=n), -d(),r.excludeEnd&&(A=n));do{ -x.scope&&S.closeNode(),x.skip||x.subLanguage||(C+=x.relevance),x=x.parent -}while(x!==i.parent);return i.starts&&b(i.starts,e),r.returnEnd?0:n.length} -let y={};function N(a,r){const o=r&&r[0];if(A+=a,null==o)return d(),0 -;if("begin"===y.type&&"end"===r.type&&y.index===r.index&&""===o){ -if(A+=t.slice(r.index,r.index+1),!s){const n=Error(`0 width match regex (${e})`) -;throw n.languageName=e,n.badRule=y.rule,n}return 1} -if(y=r,"begin"===r.type)return(e=>{ -const t=e[0],a=e.rule,i=new n(a),r=[a.__beforeBegin,a["on:begin"]] -;for(const n of r)if(n&&(n(e,i),i.isMatchIgnored))return _(t) -;return a.skip?A+=t:(a.excludeBegin&&(A+=t), -d(),a.returnBegin||a.excludeBegin||(A=t)),b(a,e),a.returnBegin?0:t.length})(r) -;if("illegal"===r.type&&!i){ -const e=Error('Illegal lexeme "'+o+'" for mode "'+(x.scope||"")+'"') -;throw e.mode=x,e}if("end"===r.type){const e=h(r);if(e!==ee)return e} -if("illegal"===r.type&&""===o)return 1 -;if(R>1e5&&R>3*r.index)throw Error("potential infinite loop, way more iterations than matches") -;return A+=o,o.length}const w=v(e) -;if(!w)throw K(o.replace("{}",e)),Error('Unknown language: "'+e+'"') -;const O=Q(w);let k="",x=r||O;const M={},S=new p.__emitter(p);(()=>{const e=[] -;for(let n=x;n!==w;n=n.parent)n.scope&&e.unshift(n.scope) -;e.forEach((e=>S.openNode(e)))})();let A="",C=0,T=0,R=0,D=!1;try{ -if(w.__emitTokens)w.__emitTokens(t,S);else{for(x.matcher.considerAll();;){ -R++,D?D=!1:x.matcher.considerAll(),x.matcher.lastIndex=T -;const e=x.matcher.exec(t);if(!e)break;const n=N(t.substring(T,e.index),e) -;T=e.index+n}N(t.substring(T))}return S.finalize(),k=S.toHTML(),{language:e, -value:k,relevance:C,illegal:!1,_emitter:S,_top:x}}catch(n){ -if(n.message&&n.message.includes("Illegal"))return{language:e,value:J(t), -illegal:!0,relevance:0,_illegalBy:{message:n.message,index:T, -context:t.slice(T-100,T+100),mode:n.mode,resultSoFar:k},_emitter:S};if(s)return{ -language:e,value:J(t),illegal:!1,relevance:0,errorRaised:n,_emitter:S,_top:x} -;throw n}}function E(e,n){n=n||p.languages||Object.keys(a);const t=(e=>{ -const n={value:J(e),illegal:!1,relevance:0,_top:c,_emitter:new p.__emitter(p)} -;return n._emitter.addText(e),n})(e),i=n.filter(v).filter(k).map((n=>f(n,e,!1))) -;i.unshift(t);const r=i.sort(((e,n)=>{ -if(e.relevance!==n.relevance)return n.relevance-e.relevance -;if(e.language&&n.language){if(v(e.language).supersetOf===n.language)return 1 -;if(v(n.language).supersetOf===e.language)return-1}return 0})),[s,o]=r,l=s -;return l.secondBest=o,l}function y(e){let n=null;const t=(e=>{ -let n=e.className+" ";n+=e.parentNode?e.parentNode.className:"" -;const t=p.languageDetectRe.exec(n);if(t){const n=v(t[1]) -;return n||(H(o.replace("{}",t[1])), -H("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"} -return n.split(/\s+/).find((e=>_(e)||v(e)))})(e);if(_(t))return -;if(x("before:highlightElement",{el:e,language:t -}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e) -;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), -console.warn("https://github.com/highlightjs/highlight.js/wiki/security"), -console.warn("The element with unescaped HTML:"), -console.warn(e)),p.throwUnescapedHTML))throw new V("One of your code blocks includes unescaped HTML.",e.innerHTML) -;n=e;const a=n.textContent,r=t?h(a,{language:t,ignoreIllegals:!0}):E(a) -;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,n,t)=>{const a=n&&i[n]||t -;e.classList.add("hljs"),e.classList.add("language-"+a) -})(e,t,r.language),e.result={language:r.language,re:r.relevance, -relevance:r.relevance},r.secondBest&&(e.secondBest={ -language:r.secondBest.language,relevance:r.secondBest.relevance -}),x("after:highlightElement",{el:e,result:r,text:a})}let N=!1;function w(){ -"loading"!==document.readyState?document.querySelectorAll(p.cssSelector).forEach(y):N=!0 -}function v(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]} -function O(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ -i[e.toLowerCase()]=n}))}function k(e){const n=v(e) -;return n&&!n.disableAutodetect}function x(e,n){const t=e;r.forEach((e=>{ -e[t]&&e[t](n)}))} -"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{ -N&&w()}),!1),Object.assign(t,{highlight:h,highlightAuto:E,highlightAll:w, -highlightElement:y, -highlightBlock:e=>(q("10.7.0","highlightBlock will be removed entirely in v12.0"), -q("10.7.0","Please use highlightElement now."),y(e)),configure:e=>{p=Y(p,e)}, -initHighlighting:()=>{ -w(),q("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, -initHighlightingOnLoad:()=>{ -w(),q("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") -},registerLanguage:(e,n)=>{let i=null;try{i=n(t)}catch(n){ -if(K("Language definition for '{}' could not be registered.".replace("{}",e)), -!s)throw n;K(n),i=c} -i.name||(i.name=e),a[e]=i,i.rawDefinition=n.bind(null,t),i.aliases&&O(i.aliases,{ -languageName:e})},unregisterLanguage:e=>{delete a[e] -;for(const n of Object.keys(i))i[n]===e&&delete i[n]}, -listLanguages:()=>Object.keys(a),getLanguage:v,registerAliases:O, -autoDetection:k,inherit:Y,addPlugin:e=>{(e=>{ -e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{ -e["before:highlightBlock"](Object.assign({block:n.el},n)) -}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{ -e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),r.push(e)}, -removePlugin:e=>{const n=r.indexOf(e);-1!==n&&r.splice(n,1)}}),t.debugMode=()=>{ -s=!1},t.safeMode=()=>{s=!0},t.versionString="11.9.0",t.regex={concat:b, -lookahead:d,either:m,optional:u,anyNumberOfTimes:g} -;for(const n in C)"object"==typeof C[n]&&e(C[n]);return Object.assign(t,C),t -},te=ne({});te.newInstance=()=>ne({});var ae=te;const ie=e=>({IMPORTANT:{ -scope:"meta",begin:"!important"},BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{ -scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/}, -FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/}, -ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$", -contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{ -scope:"number", -begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", -relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z_][A-Za-z0-9_-]*/} -}),re=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],se=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],oe=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],le=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],ce=["align-content","align-items","align-self","all","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","content-visibility","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-synthesis","font-variant","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inline-size","isolation","justify-content","left","letter-spacing","line-break","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","perspective","perspective-origin","pointer-events","position","quotes","resize","rest","rest-after","rest-before","right","row-gap","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","speak","speak-as","src","tab-size","table-layout","text-align","text-align-all","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-box","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index"].reverse(),de=oe.concat(le) -;var ge="[0-9](_*[0-9])*",ue=`\\.(${ge})`,be="[0-9a-fA-F](_*[0-9a-fA-F])*",me={ -className:"number",variants:[{ -begin:`(\\b(${ge})((${ue})|\\.)?|(${ue}))[eE][+-]?(${ge})[fFdD]?\\b`},{ -begin:`\\b(${ge})((${ue})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{ -begin:`(${ue})[fFdD]?\\b`},{begin:`\\b(${ge})[fFdD]\\b`},{ -begin:`\\b0[xX]((${be})\\.?|(${be})?\\.(${be}))[pP][+-]?(${ge})[fFdD]?\\b`},{ -begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${be})[lL]?\\b`},{ -begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], -relevance:0};function pe(e,n,t){return-1===t?"":e.replace(n,(a=>pe(e,n,t-1)))} -const _e="[A-Za-z$_][0-9A-Za-z$_]*",he=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],fe=["true","false","null","undefined","NaN","Infinity"],Ee=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],ye=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],Ne=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],we=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],ve=[].concat(Ne,Ee,ye) -;function Oe(e){const n=e.regex,t=_e,a={begin:/<[A-Za-z0-9\\._:-]+/, -end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ -const t=e[0].length+e.index,a=e.input[t] -;if("<"===a||","===a)return void n.ignoreMatch();let i -;">"===a&&(((e,{after:n})=>{const t="",M={ -match:[/const|var|let/,/\s+/,t,/\s*/,/=\s*/,/(async\s*)?/,n.lookahead(x)], -keywords:"async",className:{1:"keyword",3:"title.function"},contains:[f]} -;return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:i,exports:{ -PARAMS_CONTAINS:h,CLASS_REFERENCE:y},illegal:/#(?![$_A-z])/, -contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),{ -label:"use_strict",className:"meta",relevance:10, -begin:/^\s*['"]use (strict|asm)['"]/ -},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,d,g,u,b,m,{match:/\$\d+/},l,y,{ -className:"attr",begin:t+n.lookahead(":"),relevance:0},M,{ -begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", -keywords:"return throw case",relevance:0,contains:[m,e.REGEXP_MODE,{ -className:"function",begin:x,returnBegin:!0,end:"\\s*=>",contains:[{ -className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{ -className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0, -excludeEnd:!0,keywords:i,contains:h}]}]},{begin:/,/,relevance:0},{match:/\s+/, -relevance:0},{variants:[{begin:"<>",end:""},{ -match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:a.begin, -"on:begin":a.isTrulyOpeningTag,end:a.end}],subLanguage:"xml",contains:[{ -begin:a.begin,end:a.end,skip:!0,contains:["self"]}]}]},N,{ -beginKeywords:"while if switch catch for"},{ -begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", -returnBegin:!0,label:"func.def",contains:[f,e.inherit(e.TITLE_MODE,{begin:t, -className:"title.function"})]},{match:/\.\.\./,relevance:0},O,{match:"\\$"+t, -relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, -contains:[f]},w,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, -className:"variable.constant"},E,k,{match:/\$[(.]/}]}} -const ke=e=>b(/\b/,e,/\w$/.test(e)?/\b/:/\B/),xe=["Protocol","Type"].map(ke),Me=["init","self"].map(ke),Se=["Any","Self"],Ae=["actor","any","associatedtype","async","await",/as\?/,/as!/,"as","borrowing","break","case","catch","class","consume","consuming","continue","convenience","copy","default","defer","deinit","didSet","distributed","do","dynamic","each","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","macro","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Ce=["false","nil","true"],Te=["assignment","associativity","higherThan","left","lowerThan","none","right"],Re=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warning"],De=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],Ie=m(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Le=m(Ie,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),Be=b(Ie,Le,"*"),$e=m(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),ze=m($e,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Fe=b($e,ze,"*"),Ue=b(/[A-Z]/,ze,"*"),je=["attached","autoclosure",b(/convention\(/,m("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","freestanding","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",b(/objc\(/,Fe,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","Sendable","testable","UIApplicationMain","unchecked","unknown","usableFromInline","warn_unqualified_access"],Pe=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"] -;var Ke=Object.freeze({__proto__:null,grmr_bash:e=>{const n=e.regex,t={},a={ -begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]} -;Object.assign(t,{className:"variable",variants:[{ -begin:n.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const i={ -className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},r={ -begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/, -end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/, -contains:[e.BACKSLASH_ESCAPE,t,i]};i.contains.push(s);const o={begin:/\$?\(\(/, -end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t] -},l=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10 -}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, -contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ -name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/, -keyword:["if","then","else","elif","fi","for","while","until","in","do","done","case","esac","function","select"], -literal:["true","false"], -built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"] -},contains:[l,e.SHEBANG(),c,o,e.HASH_COMMENT_MODE,r,{match:/(\/[a-z._-]+)+/},s,{ -match:/\\"/},{className:"string",begin:/'/,end:/'/},{match:/\\'/},t]}}, -grmr_c:e=>{const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}] -}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ -className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{ -match:/\batomic_[a-z]{3,6}\b/}]},o={className:"string",variants:[{ -begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ -begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", -end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ -begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ -className:"number",variants:[{begin:"\\b(0b[01']+)"},{ -begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" -},{ -begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" -}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ -keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" -},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ -className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ -className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 -},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ -keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"], -type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","const","static","complex","bool","imaginary"], -literal:"true false NULL", -built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr" -},b=[c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],m={variants:[{begin:/=/,end:/;/},{ -begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], -keywords:u,contains:b.concat([{begin:/\(/,end:/\)/,keywords:u, -contains:b.concat(["self"]),relevance:0}]),relevance:0},p={ -begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, -keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ -begin:g,returnBegin:!0,contains:[e.inherit(d,{className:"title.function"})], -relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/, -keywords:u,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/, -end:/\)/,keywords:u,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s] -}]},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C",aliases:["h"],keywords:u, -disableAutodetect:!0,illegal:"=]/,contains:[{ -beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:c, -strings:o,keywords:u}}},grmr_cpp:e=>{const n=e.regex,t=e.COMMENT("//","$",{ -contains:[{begin:/\\\n/}] -}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="(?!struct)("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ -className:"type",begin:"\\b[a-z\\d_]*_t\\b"},o={className:"string",variants:[{ -begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ -begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", -end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ -begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ -className:"number",variants:[{begin:"\\b(0b[01']+)"},{ -begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" -},{ -begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" -}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ -keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" -},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ -className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ -className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 -},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ -type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"], -keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"], -literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"], -_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"] -},b={className:"function.dispatch",relevance:0,keywords:{ -_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"] -}, -begin:n.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,n.lookahead(/(<[^<>]+>|)\s*\(/)) -},m=[b,c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],p={variants:[{begin:/=/,end:/;/},{ -begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], -keywords:u,contains:m.concat([{begin:/\(/,end:/\)/,keywords:u, -contains:m.concat(["self"]),relevance:0}]),relevance:0},_={className:"function", -begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, -keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ -begin:g,returnBegin:!0,contains:[d],relevance:0},{begin:/::/,relevance:0},{ -begin:/:/,endsWithParent:!0,contains:[o,l]},{relevance:0,match:/,/},{ -className:"params",begin:/\(/,end:/\)/,keywords:u,relevance:0, -contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/,end:/\)/,keywords:u, -relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s]}] -},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C++", -aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:u,illegal:"",keywords:u,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:u},{ -match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/], -className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={ -keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]), -built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"], -literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{ -begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{ -begin:"\\b(0b[01']+)"},{ -begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ -begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" -}],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}] -},r=e.inherit(i,{illegal:/\n/}),s={className:"subst",begin:/\{/,end:/\}/, -keywords:n},o=e.inherit(s,{illegal:/\n/}),l={className:"string",begin:/\$"/, -end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/ -},e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{ -begin:/\{\{/},{begin:/\}\}/},{begin:'""'},s]},d=e.inherit(c,{illegal:/\n/, -contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]}) -;s.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE], -o.contains=[d,l,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{ -illegal:/\n/})];const g={variants:[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] -},u={begin:"<",end:">",contains:[{beginKeywords:"in out"},t] -},b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={ -begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"], -keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0, -contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{ -begin:"\x3c!--|--\x3e"},{begin:""}]}] -}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#", -end:"$",keywords:{ -keyword:"if else elif endif define undef warning error line region endregion pragma checksum" -}},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/, -illegal:/[^\s:,]/,contains:[{beginKeywords:"where class" -},t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace", -relevance:0,end:/[{;=]/,illegal:/[^\s:]/, -contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ -beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/, -contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta", -begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{ -className:"string",begin:/"/,end:/"/}]},{ -beginKeywords:"new return throw await else",relevance:0},{className:"function", -begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, -end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{ -beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial", -relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, -contains:[e.TITLE_MODE,u],relevance:0},{match:/\(\)/},{className:"params", -begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0, -contains:[g,a,e.C_BLOCK_COMMENT_MODE] -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{ -const n=e.regex,t=ie(e),a=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{ -name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{ -keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"}, -contains:[t.BLOCK_COMMENT,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/ -},t.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0 -},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0 -},t.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{ -begin:":("+oe.join("|")+")"},{begin:":(:)?("+le.join("|")+")"}] -},t.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b"},{ -begin:/:/,end:/[;}{]/, -contains:[t.BLOCK_COMMENT,t.HEXCOLOR,t.IMPORTANT,t.CSS_NUMBER_MODE,...a,{ -begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri" -},contains:[...a,{className:"string",begin:/[^)]/,endsWithParent:!0, -excludeEnd:!0}]},t.FUNCTION_DISPATCH]},{begin:n.lookahead(/@/),end:"[{;]", -relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/ -},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{ -$pattern:/[a-z-]+/,keyword:"and or not only",attribute:se.join(" ")},contains:[{ -begin:/[a-z-]+(?=:)/,className:"attribute"},...a,t.CSS_NUMBER_MODE]}]},{ -className:"selector-tag",begin:"\\b("+re.join("|")+")\\b"}]}},grmr_diff:e=>{ -const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{ -className:"meta",relevance:10, -match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/) -},{className:"comment",variants:[{ -begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/), -end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{ -className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/, -end:/$/}]}},grmr_go:e=>{const n={ -keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"], -type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"], -literal:["true","false","iota","nil"], -built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"] -};return{name:"Go",aliases:["golang"],keywords:n,illegal:"{const n=e.regex;return{name:"GraphQL",aliases:["gql"], -case_insensitive:!0,disableAutodetect:!1,keywords:{ -keyword:["query","mutation","subscription","type","input","schema","directive","interface","union","scalar","fragment","enum","on"], -literal:["true","false","null"]}, -contains:[e.HASH_COMMENT_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{ -scope:"punctuation",match:/[.]{3}/,relevance:0},{scope:"punctuation", -begin:/[\!\(\)\:\=\[\]\{\|\}]{1}/,relevance:0},{scope:"variable",begin:/\$/, -end:/\W/,excludeEnd:!0,relevance:0},{scope:"meta",match:/@\w+/,excludeEnd:!0},{ -scope:"symbol",begin:n.concat(/[_A-Za-z][_0-9A-Za-z]*/,n.lookahead(/\s*:/)), -relevance:0}],illegal:[/[;<']/,/BEGIN/]}},grmr_ini:e=>{const n=e.regex,t={ -className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{ -begin:e.NUMBER_RE}]},a=e.COMMENT();a.variants=[{begin:/;/,end:/$/},{begin:/#/, -end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{ -begin:/\$\{(.*?)\}/}]},r={className:"literal", -begin:/\bon|off|true|false|yes|no\b/},s={className:"string", -contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{ -begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}] -},o={begin:/\[/,end:/\]/,contains:[a,r,i,s,t,"self"],relevance:0 -},l=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{ -name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/, -contains:[a,{className:"section",begin:/\[+/,end:/\]+/},{ -begin:n.concat(l,"(\\s*\\.\\s*",l,")*",n.lookahead(/\s*=\s*[^#\s]/)), -className:"attr",starts:{end:/$/,contains:[a,o,r,i,s,t]}}]}},grmr_java:e=>{ -const n=e.regex,t="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",a=t+pe("(?:<"+t+"~~~(?:\\s*,\\s*"+t+"~~~)*>)?",/~~~/g,2),i={ -keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits"], -literal:["false","true","null"], -type:["char","boolean","long","float","int","byte","short","double"], -built_in:["super","this"]},r={className:"meta",begin:"@"+t,contains:[{ -begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/, -end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} -;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/, -contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, -relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ -begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/, -className:"string",contains:[e.BACKSLASH_ESCAPE] -},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ -match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,t],className:{ -1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{ -begin:[n.concat(/(?!else)/,t),/\s+/,t,/\s+/,/=(?!=)/],className:{1:"type", -3:"variable",5:"operator"}},{begin:[/record/,/\s+/,t],className:{1:"keyword", -3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ -beginKeywords:"new throw return else",relevance:0},{ -begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ -2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/, -end:/\)/,keywords:i,relevance:0, -contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,me,e.C_BLOCK_COMMENT_MODE] -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},me,r]}},grmr_javascript:Oe, -grmr_json:e=>{const n=["true","false","null"],t={scope:"literal", -beginKeywords:n.join(" ")};return{name:"JSON",keywords:{literal:n},contains:[{ -className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{ -match:/[{}[\],:]/,className:"punctuation",relevance:0 -},e.QUOTE_STRING_MODE,t,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE], -illegal:"\\S"}},grmr_kotlin:e=>{const n={ -keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", -built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", -literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" -},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={ -className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string", -variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'", -illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, -contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={ -className:"meta", -begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" -},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, -end:/\)/,contains:[e.inherit(r,{className:"string"}),"self"]}] -},l=me,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={ -variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/, -contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g], -{name:"Kotlin",aliases:["kt","kts"],keywords:n, -contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag", -begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword", -begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", -begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$", -returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{ -begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, -contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, -keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, -endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, -endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0 -},e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{ -begin:[/class|interface|trait/,/\s+/,e.UNDERSCORE_IDENT_RE],beginScope:{ -3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, -illegal:"extends implements",contains:[{ -beginKeywords:"public protected internal private constructor" -},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, -excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/, -excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env", -end:"$",illegal:"\n"},l]}},grmr_less:e=>{ -const n=ie(e),t=de,a="[\\w-]+",i="("+a+"|@\\{"+a+"\\})",r=[],s=[],o=e=>({ -className:"string",begin:"~?"+e+".*?"+e}),l=(e,n,t)=>({className:e,begin:n, -relevance:t}),c={$pattern:/[a-z-]+/,keyword:"and or not only", -attribute:se.join(" ")},d={begin:"\\(",end:"\\)",contains:s,keywords:c, -relevance:0} -;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,o("'"),o('"'),n.CSS_NUMBER_MODE,{ -begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]", -excludeEnd:!0} -},n.HEXCOLOR,d,l("variable","@@?"+a,10),l("variable","@\\{"+a+"\\}"),l("built_in","~?`[^`]*?`"),{ -className:"attribute",begin:a+"\\s*:",end:":",returnBegin:!0,excludeEnd:!0 -},n.IMPORTANT,{beginKeywords:"and not"},n.FUNCTION_DISPATCH);const g=s.concat({ -begin:/\{/,end:/\}/,contains:r}),u={beginKeywords:"when",endsWithParent:!0, -contains:[{beginKeywords:"and not"}].concat(s)},b={begin:i+"\\s*:", -returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/ -},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b", -end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}] -},m={className:"keyword", -begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b", -starts:{end:"[;{}]",keywords:c,returnEnd:!0,contains:s,relevance:0}},p={ -className:"variable",variants:[{begin:"@"+a+"\\s*:",relevance:15},{begin:"@"+a -}],starts:{end:"[;}]",returnEnd:!0,contains:g}},_={variants:[{ -begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:i,end:/\{/}],returnBegin:!0, -returnEnd:!0,illegal:"[<='$\"]",relevance:0, -contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,u,l("keyword","all\\b"),l("variable","@\\{"+a+"\\}"),{ -begin:"\\b("+re.join("|")+")\\b",className:"selector-tag" -},n.CSS_NUMBER_MODE,l("selector-tag",i,0),l("selector-id","#"+i),l("selector-class","\\."+i,0),l("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{ -className:"selector-pseudo",begin:":("+oe.join("|")+")"},{ -className:"selector-pseudo",begin:":(:)?("+le.join("|")+")"},{begin:/\(/, -end:/\)/,relevance:0,contains:g},{begin:"!important"},n.FUNCTION_DISPATCH]},h={ -begin:a+":(:)?"+`(${t.join("|")})`,returnBegin:!0,contains:[_]} -;return r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,m,p,h,b,_,u,n.FUNCTION_DISPATCH), -{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:r}}, -grmr_lua:e=>{const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"] -},i=[e.COMMENT("--(?!"+n+")","$"),e.COMMENT("--"+n,t,{contains:[a],relevance:10 -})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE, -literal:"true false nil", -keyword:"and break do else elseif end for goto if in local not or repeat return then until while", -built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove" -},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)", -contains:[e.inherit(e.TITLE_MODE,{ -begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params", -begin:"\\(",endsWithParent:!0,contains:i}].concat(i) -},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string", -begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={ -className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)", -contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%{ -const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={ -variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{ -begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, -relevance:2},{ -begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), -relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{ -begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/ -},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0, -returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)", -excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[", -end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[], -variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}] -},i={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{ -begin:/_(?![_\s])/,end:/_/,relevance:0}]},r=e.inherit(a,{contains:[] -}),s=e.inherit(i,{contains:[]});a.contains.push(s),i.contains.push(r) -;let o=[n,t];return[a,i,r,s].forEach((e=>{e.contains=e.contains.concat(o) -})),o=o.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ -className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{ -begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", -contains:o}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", -end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:o, -end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{ -begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{ -begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))", -contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{ -begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ -className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ -className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}},grmr_objectivec:e=>{ -const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n, -keyword:["@interface","@class","@protocol","@implementation"]};return{ -name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], -keywords:{"variable.language":["this","super"],$pattern:n, -keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","switch","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"], -literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"], -built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"], -type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"] -},illegal:"/,end:/$/,illegal:"\\n" -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class", -begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t, -contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE, -relevance:0}]}},grmr_perl:e=>{const n=e.regex,t=/[dualxmsipngr]{0,12}/,a={ -$pattern:/[\w.]+/, -keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0" -},i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:a},r={begin:/->\{/, -end:/\}/},s={variants:[{begin:/\$\d/},{ -begin:n.concat(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])") -},{begin:/[$%@][^\s\w{]/,relevance:0}] -},o=[e.BACKSLASH_ESCAPE,i,s],l=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],c=(e,a,i="\\1")=>{ -const r="\\1"===i?i:n.concat(i,a) -;return n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,r,/(?:\\.|[^\\\/])*?/,i,t) -},d=(e,a,i)=>n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,i,t),g=[s,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{ -endsWithParent:!0}),r,{className:"string",contains:o,variants:[{ -begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[", -end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{ -begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">", -relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'", -contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`", -contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{ -begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number", -begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b", -relevance:0},{ -begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*", -keywords:"split return print reverse grep",relevance:0, -contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{ -begin:c("s|tr|y",n.either(...l,{capture:!0}))},{begin:c("s|tr|y","\\(","\\)")},{ -begin:c("s|tr|y","\\[","\\]")},{begin:c("s|tr|y","\\{","\\}")}],relevance:2},{ -className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{ -begin:d("(?:m|qr)?",/\//,/\//)},{begin:d("m|qr",n.either(...l,{capture:!0 -}),/\1/)},{begin:d("m|qr",/\(/,/\)/)},{begin:d("m|qr",/\[/,/\]/)},{ -begin:d("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub", -end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{ -begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$", -subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}] -}];return i.contains=g,r.contains=g,{name:"Perl",aliases:["pl","pm"],keywords:a, -contains:g}},grmr_php:e=>{ -const n=e.regex,t=/(?![A-Za-z0-9])(?![$])/,a=n.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,t),i=n.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,t),r={ -scope:"variable",match:"\\$+"+a},s={scope:"subst",variants:[{begin:/\$\w+/},{ -begin:/\{\$/,end:/\}/}]},o=e.inherit(e.APOS_STRING_MODE,{illegal:null -}),l="[ \t\n]",c={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{ -illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(s)}),o,{ -begin:/<<<[ \t]*(?:(\w+)|"(\w+)")\n/,end:/[ \t]*(\w+)\b/, -contains:e.QUOTE_STRING_MODE.contains.concat(s),"on:begin":(e,n)=>{ -n.data._beginMatch=e[1]||e[2]},"on:end":(e,n)=>{ -n.data._beginMatch!==e[1]&&n.ignoreMatch()}},e.END_SAME_AS_BEGIN({ -begin:/<<<[ \t]*'(\w+)'\n/,end:/[ \t]*(\w+)\b/})]},d={scope:"number",variants:[{ -begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{ -begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{ -begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?" -}],relevance:0 -},g=["false","null","true"],u=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],m={ -keyword:u,literal:(e=>{const n=[];return e.forEach((e=>{ -n.push(e),e.toLowerCase()===e?n.push(e.toUpperCase()):n.push(e.toLowerCase()) -})),n})(g),built_in:b},p=e=>e.map((e=>e.replace(/\|\d+$/,""))),_={variants:[{ -match:[/new/,n.concat(l,"+"),n.concat("(?!",p(b).join("\\b|"),"\\b)"),i],scope:{ -1:"keyword",4:"title.class"}}]},h=n.concat(a,"\\b(?!\\()"),f={variants:[{ -match:[n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant" -}},{match:[/::/,/class/],scope:{2:"variable.language"}},{ -match:[i,n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{1:"title.class", -3:"variable.constant"}},{match:[i,n.concat("::",n.lookahead(/(?!class\b)/))], -scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class", -3:"variable.language"}}]},E={scope:"attr", -match:n.concat(a,n.lookahead(":"),n.lookahead(/(?!::)/))},y={relevance:0, -begin:/\(/,end:/\)/,keywords:m,contains:[E,r,f,e.C_BLOCK_COMMENT_MODE,c,d,_] -},N={relevance:0, -match:[/\b/,n.concat("(?!fn\\b|function\\b|",p(u).join("\\b|"),"|",p(b).join("\\b|"),"\\b)"),a,n.concat(l,"*"),n.lookahead(/(?=\()/)], -scope:{3:"title.function.invoke"},contains:[y]};y.contains.push(N) -;const w=[E,f,e.C_BLOCK_COMMENT_MODE,c,d,_];return{case_insensitive:!1, -keywords:m,contains:[{begin:n.concat(/#\[\s*/,i),beginScope:"meta",end:/]/, -endScope:"meta",keywords:{literal:g,keyword:["new","array"]},contains:[{ -begin:/\[/,end:/]/,keywords:{literal:g,keyword:["new","array"]}, -contains:["self",...w]},...w,{scope:"meta",match:i}] -},e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{ -scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/, -keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE, -contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{ -begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{ -begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},r,N,f,{ -match:[/const/,/\s/,a],scope:{1:"keyword",3:"variable.constant"}},_,{ -scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/, -excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use" -},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params", -begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:m, -contains:["self",r,f,e.C_BLOCK_COMMENT_MODE,c,d]}]},{scope:"class",variants:[{ -beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait", -illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{ -beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ -beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/, -contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{ -beginKeywords:"use",relevance:0,end:";",contains:[{ -match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},c,d]} -},grmr_php_template:e=>({name:"PHP template",subLanguage:"xml",contains:[{ -begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*", -end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0 -},e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null, -skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null, -contains:null,skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text", -aliases:["text","txt"],disableAutodetect:!0}),grmr_python:e=>{ -const n=e.regex,t=/[\p{XID_Start}_]\p{XID_Continue}*/u,a=["and","as","assert","async","await","break","case","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","match","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],i={ -$pattern:/[A-Za-z]\w+|__\w+__/,keyword:a, -built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"], -literal:["__debug__","Ellipsis","False","None","NotImplemented","True"], -type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"] -},r={className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/, -end:/\}/,keywords:i,illegal:/#/},o={begin:/\{\{/,relevance:0},l={ -className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{ -begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/, -contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ -begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/, -contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ -begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/, -contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/, -end:/"""/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([uU]|[rR])'/,end:/'/, -relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{ -begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/, -end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/, -contains:[e.BACKSLASH_ESCAPE,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/, -contains:[e.BACKSLASH_ESCAPE,o,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] -},c="[0-9](_?[0-9])*",d=`(\\b(${c}))?\\.(${c})|\\b(${c})\\.`,g="\\b|"+a.join("|"),u={ -className:"number",relevance:0,variants:[{ -begin:`(\\b(${c})|(${d}))[eE][+-]?(${c})[jJ]?(?=${g})`},{begin:`(${d})[jJ]?`},{ -begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${g})`},{ -begin:`\\b0[bB](_?[01])+[lL]?(?=${g})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${g})` -},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${g})`},{begin:`\\b(${c})[jJ](?=${g})` -}]},b={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:i, -contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={ -className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/, -end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i, -contains:["self",r,u,l,e.HASH_COMMENT_MODE]}]};return s.contains=[l,u,r],{ -name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:i, -illegal:/(<\/|\?)|=>/,contains:[r,u,{begin:/\bself\b/},{beginKeywords:"if", -relevance:0},l,b,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,t],scope:{ -1:"keyword",3:"title.function"},contains:[m]},{variants:[{ -match:[/\bclass/,/\s+/,t,/\s*/,/\(\s*/,t,/\s*\)/]},{match:[/\bclass/,/\s+/,t]}], -scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{ -className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[u,m,l]}]}}, -grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta.prompt", -starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{ -begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{ -const n=e.regex,t=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,a=n.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/,r=n.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/) -;return{name:"R",keywords:{$pattern:t, -keyword:"function if in break next repeat else for while", -literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10", -built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm" -},contains:[e.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/, -starts:{end:n.lookahead(n.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)), -endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{ -scope:"variable",variants:[{match:t},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0 -}]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}] -}),e.HASH_COMMENT_MODE,{scope:"string",contains:[e.BACKSLASH_ESCAPE], -variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/ -}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/ -}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/ -}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/ -}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/ -}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"', -relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{ -1:"operator",2:"number"},match:[i,a]},{scope:{1:"operator",2:"number"}, -match:[/%[^%]*%/,a]},{scope:{1:"punctuation",2:"number"},match:[r,a]},{scope:{ -2:"number"},match:[/[^a-zA-Z0-9._]|^/,a]}]},{scope:{3:"operator"}, -match:[t,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{ -match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:r},{begin:"`",end:"`", -contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{ -const n=e.regex,t="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",a=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(a,/(::\w+)*/),r={ -"variable.constant":["__FILE__","__LINE__","__ENCODING__"], -"variable.language":["self","super"], -keyword:["alias","and","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield","include","extend","prepend","public","private","protected","raise","throw"], -built_in:["proc","lambda","attr_accessor","attr_reader","attr_writer","define_method","private_constant","module_function"], -literal:["true","false","nil"]},s={className:"doctag",begin:"@[A-Za-z]+"},o={ -begin:"#<",end:">"},l=[e.COMMENT("#","$",{contains:[s] -}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10 -}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],c={className:"subst",begin:/#\{/, -end:/\}/,keywords:r},d={className:"string",contains:[e.BACKSLASH_ESCAPE,c], -variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{ -begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{ -begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//, -end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{ -begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{ -begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{ -begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{ -begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{ -begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)), -contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, -contains:[e.BACKSLASH_ESCAPE,c]})]}]},g="[0-9](_?[0-9])*",u={className:"number", -relevance:0,variants:[{ -begin:`\\b([1-9](_?[0-9])*|0)(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{ -begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b" -},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{ -begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{ -begin:"\\b0(_?[0-7])+r?i?\\b"}]},b={variants:[{match:/\(\)/},{ -className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0, -keywords:r}]},m=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{ -match:[/\b(class|module)\s+/,i]}],scope:{2:"title.class", -4:"title.class.inherited"},keywords:r},{match:[/(include|extend)\s+/,i],scope:{ -2:"title.class"},keywords:r},{relevance:0,match:[i,/\.new[. (]/],scope:{ -1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, -className:"variable.constant"},{relevance:0,match:a,scope:"title.class"},{ -match:[/def/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[b]},{ -begin:e.IDENT_RE+"::"},{className:"symbol", -begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol", -begin:":(?!\\s)",contains:[d,{begin:t}],relevance:0},u,{className:"variable", -begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{ -className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0, -relevance:0,keywords:r},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*", -keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c], -illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{ -begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[", -end:"\\][a-z]*"}]}].concat(o,l),relevance:0}].concat(o,l) -;c.contains=m,b.contains=m;const p=[{begin:/^\s*=>/,starts:{end:"$",contains:m} -},{className:"meta.prompt", -begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])", -starts:{end:"$",keywords:r,contains:m}}];return l.unshift(o),{name:"Ruby", -aliases:["rb","gemspec","podspec","thor","irb"],keywords:r,illegal:/\/\*/, -contains:[e.SHEBANG({binary:"ruby"})].concat(p).concat(l).concat(m)}}, -grmr_rust:e=>{const n=e.regex,t={className:"title.function.invoke",relevance:0, -begin:n.concat(/\b/,/(?!let|for|while|if|else|match\b)/,e.IDENT_RE,n.lookahead(/\s*\(/)) -},a="([ui](8|16|32|64|128|size)|f(32|64))?",i=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","eprintln!","panic!","file!","format!","format_args!","include_bytes!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"],r=["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"] -;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:r, -keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"], -literal:["true","false","Some","None","Ok","Err"],built_in:i},illegal:""},t]}}, -grmr_scss:e=>{const n=ie(e),t=le,a=oe,i="@[a-z-]+",r={className:"variable", -begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b",relevance:0};return{name:"SCSS", -case_insensitive:!0,illegal:"[=/|']", -contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n.CSS_NUMBER_MODE,{ -className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{ -className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0 -},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag", -begin:"\\b("+re.join("|")+")\\b",relevance:0},{className:"selector-pseudo", -begin:":("+a.join("|")+")"},{className:"selector-pseudo", -begin:":(:)?("+t.join("|")+")"},r,{begin:/\(/,end:/\)/, -contains:[n.CSS_NUMBER_MODE]},n.CSS_VARIABLE,{className:"attribute", -begin:"\\b("+ce.join("|")+")\\b"},{ -begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b" -},{begin:/:/,end:/[;}{]/,relevance:0, -contains:[n.BLOCK_COMMENT,r,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT,n.FUNCTION_DISPATCH] -},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{ -begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/, -keyword:"and or not only",attribute:se.join(" ")},contains:[{begin:i, -className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute" -},r,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE] -},n.FUNCTION_DISPATCH]}},grmr_shell:e=>({name:"Shell Session", -aliases:["console","shellsession"],contains:[{className:"meta.prompt", -begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/, -subLanguage:"bash"}}]}),grmr_sql:e=>{ -const n=e.regex,t=e.COMMENT("--","$"),a=["true","false","unknown"],i=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],r=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=r,l=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!r.includes(e))),c={ -begin:n.concat(/\b/,n.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}} -;return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{ -$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t -;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e)) -})(l,{when:e=>e.length<3}),literal:a,type:i, -built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"] -},contains:[{begin:n.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/, -keyword:l.concat(s),literal:a,type:i}},{className:"type", -begin:n.either("double precision","large object","with timezone","without timezone") -},c,{className:"variable",begin:/@[a-z0-9][a-z0-9_]*/},{className:"string", -variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/, -contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{ -className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, -relevance:0}]}},grmr_swift:e=>{const n={match:/\s+/,relevance:0 -},t=e.COMMENT("/\\*","\\*/",{contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={ -match:[/\./,m(...xe,...Me)],className:{2:"keyword"}},r={match:b(/\./,m(...Ae)), -relevance:0},s=Ae.filter((e=>"string"==typeof e)).concat(["_|0"]),o={variants:[{ -className:"keyword", -match:m(...Ae.filter((e=>"string"!=typeof e)).concat(Se).map(ke),...Me)}]},l={ -$pattern:m(/\b\w+/,/#\w+/),keyword:s.concat(Re),literal:Ce},c=[i,r,o],g=[{ -match:b(/\./,m(...De)),relevance:0},{className:"built_in", -match:b(/\b/,m(...De),/(?=\()/)}],u={match:/->/,relevance:0},p=[u,{ -className:"operator",relevance:0,variants:[{match:Be},{match:`\\.(\\.|${Le})+`}] -}],_="([0-9]_*)+",h="([0-9a-fA-F]_*)+",f={className:"number",relevance:0, -variants:[{match:`\\b(${_})(\\.(${_}))?([eE][+-]?(${_}))?\\b`},{ -match:`\\b0x(${h})(\\.(${h}))?([pP][+-]?(${_}))?\\b`},{match:/\b0o([0-7]_*)+\b/ -},{match:/\b0b([01]_*)+\b/}]},E=(e="")=>({className:"subst",variants:[{ -match:b(/\\/,e,/[0\\tnr"']/)},{match:b(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}] -}),y=(e="")=>({className:"subst",match:b(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/) -}),N=(e="")=>({className:"subst",label:"interpol",begin:b(/\\/,e,/\(/),end:/\)/ -}),w=(e="")=>({begin:b(e,/"""/),end:b(/"""/,e),contains:[E(e),y(e),N(e)] -}),v=(e="")=>({begin:b(e,/"/),end:b(/"/,e),contains:[E(e),N(e)]}),O={ -className:"string", -variants:[w(),w("#"),w("##"),w("###"),v(),v("#"),v("##"),v("###")] -},k=[e.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0, -contains:[e.BACKSLASH_ESCAPE]}],x={begin:/\/[^\s](?=[^/\n]*\/)/,end:/\//, -contains:k},M=e=>{const n=b(e,/\//),t=b(/\//,e);return{begin:n,end:t, -contains:[...k,{scope:"comment",begin:`#(?!.*${t})`,end:/$/}]}},S={ -scope:"regexp",variants:[M("###"),M("##"),M("#"),x]},A={match:b(/`/,Fe,/`/) -},C=[A,{className:"variable",match:/\$\d+/},{className:"variable", -match:`\\$${ze}+`}],T=[{match:/(@|#(un)?)available/,scope:"keyword",starts:{ -contains:[{begin:/\(/,end:/\)/,keywords:Pe,contains:[...p,f,O]}]}},{ -scope:"keyword",match:b(/@/,m(...je))},{scope:"meta",match:b(/@/,Fe)}],R={ -match:d(/\b[A-Z]/),relevance:0,contains:[{className:"type", -match:b(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,ze,"+") -},{className:"type",match:Ue,relevance:0},{match:/[?!]+/,relevance:0},{ -match:/\.\.\./,relevance:0},{match:b(/\s+&\s+/,d(Ue)),relevance:0}]},D={ -begin://,keywords:l,contains:[...a,...c,...T,u,R]};R.contains.push(D) -;const I={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{ -match:b(Fe,/\s*:/),keywords:"_|0",relevance:0 -},...a,S,...c,...g,...p,f,O,...C,...T,R]},L={begin://, -keywords:"repeat each",contains:[...a,R]},B={begin:/\(/,end:/\)/,keywords:l, -contains:[{begin:m(d(b(Fe,/\s*:/)),d(b(Fe,/\s+/,Fe,/\s*:/))),end:/:/, -relevance:0,contains:[{className:"keyword",match:/\b_\b/},{className:"params", -match:Fe}]},...a,...c,...p,f,O,...T,R,I],endsParent:!0,illegal:/["']/},$={ -match:[/(func|macro)/,/\s+/,m(A.match,Fe,Be)],className:{1:"keyword", -3:"title.function"},contains:[L,B,n],illegal:[/\[/,/%/]},z={ -match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"}, -contains:[L,B,n],illegal:/\[|%/},F={match:[/operator/,/\s+/,Be],className:{ -1:"keyword",3:"title"}},U={begin:[/precedencegroup/,/\s+/,Ue],className:{ -1:"keyword",3:"title"},contains:[R],keywords:[...Te,...Ce],end:/}/} -;for(const e of O.variants){const n=e.contains.find((e=>"interpol"===e.label)) -;n.keywords=l;const t=[...c,...g,...p,f,O,...C];n.contains=[...t,{begin:/\(/, -end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:l, -contains:[...a,$,z,{beginKeywords:"struct protocol class extension enum actor", -end:"\\{",excludeEnd:!0,keywords:l,contains:[e.inherit(e.TITLE_MODE,{ -className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...c] -},F,U,{beginKeywords:"import",end:/$/,contains:[...a],relevance:0 -},S,...c,...g,...p,f,O,...C,...T,R,I]}},grmr_typescript:e=>{ -const n=Oe(e),t=_e,a=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],i={ -beginKeywords:"namespace",end:/\{/,excludeEnd:!0, -contains:[n.exports.CLASS_REFERENCE]},r={beginKeywords:"interface",end:/\{/, -excludeEnd:!0,keywords:{keyword:"interface extends",built_in:a}, -contains:[n.exports.CLASS_REFERENCE]},s={$pattern:_e, -keyword:he.concat(["type","namespace","interface","public","private","protected","implements","declare","abstract","readonly","enum","override"]), -literal:fe,built_in:ve.concat(a),"variable.language":we},o={className:"meta", -begin:"@"+t},l=(e,n,t)=>{const a=e.contains.findIndex((e=>e.label===n)) -;if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)} -;return Object.assign(n.keywords,s), -n.exports.PARAMS_CONTAINS.push(o),n.contains=n.contains.concat([o,i,r]), -l(n,"shebang",e.SHEBANG()),l(n,"use_strict",{className:"meta",relevance:10, -begin:/^\s*['"]use strict['"]/ -}),n.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(n,{ -name:"TypeScript",aliases:["ts","tsx","mts","cts"]}),n},grmr_vbnet:e=>{ -const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,r=/\d{1,2}(:\d{1,2}){1,2}/,s={ -className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{ -begin:n.concat(/# */,r,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{ -begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,r),/ *#/)}] -},o=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}] -}),l=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]}) -;return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0, -classNameAliases:{label:"symbol"},keywords:{ -keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield", -built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort", -type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort", -literal:"true false nothing"}, -illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{ -className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/, -end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0, -variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/ -},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{ -begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{ -className:"label",begin:/^\w+:/},o,l,{className:"meta", -begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/, -end:/$/,keywords:{ -keyword:"const disable else elseif enable end externalsource if region then"}, -contains:[l]}]}},grmr_wasm:e=>{e.regex;const n=e.COMMENT(/\(;/,/;\)/) -;return n.contains.push("self"),{name:"WebAssembly",keywords:{$pattern:/[\w.]+/, -keyword:["anyfunc","block","br","br_if","br_table","call","call_indirect","data","drop","elem","else","end","export","func","global.get","global.set","local.get","local.set","local.tee","get_global","get_local","global","if","import","local","loop","memory","memory.grow","memory.size","module","mut","nop","offset","param","result","return","select","set_global","set_local","start","table","tee_local","then","type","unreachable"] -},contains:[e.COMMENT(/;;/,/$/),n,{match:[/(?:offset|align)/,/\s*/,/=/], -className:{1:"keyword",3:"operator"}},{className:"variable",begin:/\$[\w_]+/},{ -match:/(\((?!;)|\))+/,className:"punctuation",relevance:0},{ -begin:[/(?:func|call|call_indirect)/,/\s+/,/\$[^\s)]+/],className:{1:"keyword", -3:"title.function"}},e.QUOTE_STRING_MODE,{match:/(i32|i64|f32|f64)(?!\.)/, -className:"type"},{className:"keyword", -match:/\b(f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))\b/ -},{className:"number",relevance:0, -match:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/ -}]}},grmr_xml:e=>{ -const n=e.regex,t=n.concat(/[\p{L}_]/u,n.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),a={ -className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/, -contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] -},r=e.inherit(i,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{ -className:"string"}),o=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),l={ -endsWithParent:!0,illegal:/`]+/}]}]}]};return{ -name:"HTML, XML", -aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], -case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,o,s,r,{begin:/\[/,end:/\]/,contains:[{ -className:"meta",begin://,contains:[i,r,o,s]}]}] -},e.COMMENT(//,{relevance:10}),{begin://, -relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/, -relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag", -begin:/)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{ -end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", -begin:/)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{ -end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ -className:"tag",begin:/<>|<\/>/},{className:"tag", -begin:n.concat(//,/>/,/\s/)))), -end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{ -className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{ -className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]} -},grmr_yaml:e=>{ -const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={ -className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ -},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", -variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{ -variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={ -end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/, -end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]", -contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{ -begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{ -begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$", -relevance:10},{className:"string", -begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ -begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, -relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type", -begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t -},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", -begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", -relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ -className:"number", -begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" -},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l] -;return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0, -aliases:["yml"],contains:l}}});const He=ae;for(const e of Object.keys(Ke)){ -const n=e.replace("grmr_","").replace("_","-");He.registerLanguage(n,Ke[e])} -return He}() -;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); \ No newline at end of file diff --git a/pelican/themes/simple/tailwind.config.js b/pelican/themes/simple/tailwind.config.js deleted file mode 100644 index 6f60fb7d..00000000 --- a/pelican/themes/simple/tailwind.config.js +++ /dev/null @@ -1,51 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ["./templates/*.html"], - plugins: [require("@tailwindcss/typography")], - theme: { - //fontFamily: { - //sans: ["Erode", "sans-serif"], - //serif: ["Recia", "serif"], - //}, - extend: { - colors: { - // rose pine palette: https://rosepinetheme.com/palette/ - "rp-moon-base": "#faf4ed", // main background - "rp-moon-surface": "#fffaf3", // navigation background - "rp-moon-overlay": "#f2e9e1", // content background - "rp-moon-foam": "#56949f", // main site title - "rp-moon-text": "#575279", - "rp-moon-muted": "#9893a5", - "rp-moon-subtle": "#797593", - "rp-moon-iris": "#907aa9", // links - "rp-moon-highlight-med": "#dfdad9", // footer - "rp-moon-gold": "#ea9d34", // headings - }, - typography: { - DEFAULT: { - css: { - // remove backticks from Typography for inline code - "code::before": { - content: '""', - }, - // remove backticks from Typography for inline code - "code::after": { - content: '""', - }, - //code: { - // "background-color": "#f4ede8", - // padding: "0.3rem", - //}, - //highlight: { - // "background-color": "#e5e7eb", - // padding: "0.3rem", - //}, - }, - }, - }, - }, - }, - //corePlugins: { - // preflight: false, - //}, -}; diff --git a/pelican/themes/simple/templates/article.html b/pelican/themes/simple/templates/article.html deleted file mode 100644 index 1a1148f3..00000000 --- a/pelican/themes/simple/templates/article.html +++ /dev/null @@ -1,70 +0,0 @@ -{% extends "base.html" %} -{% block html_lang %}{{ article.lang }}{% endblock %} - -{% block title %}{{ SITENAME|striptags }} - {{ article.title|striptags }}{% endblock %} - -{% block head %} - {{ super() }} - - {% if article.description %} - - {% endif %} - - {% for tag in article.tags %} - - {% endfor %} - -{% endblock %} - -{% block content %} -
      -
      - {% if not article.image %} -

      {{ article.title }}

      - {% endif %} - {% if article.image %} -
      - -
      -

      - - {{ article.title }} - -

      -
      -
      - {% endif %} -
      - {{ article.content }} -
      -

      Published:

      - {% if article.modified %} -

      Last updated:

      - {% endif %} - {% if article.authors %} -
      - By {% for author in article.authors %} - {{ author }} - {% endfor %} -
      - {% endif %} - {% if article.category %} -

      - Category: {{ article.category }} -

      - {% endif %} - {% if article.tags %} -

      - Tags: - {% for tag in article.tags %} - {{ tag }} - {% endfor %} -

      - {% endif %} -
      -
      -{% endblock %} diff --git a/pelican/themes/simple/templates/base.html b/pelican/themes/simple/templates/base.html deleted file mode 100644 index 08e09763..00000000 --- a/pelican/themes/simple/templates/base.html +++ /dev/null @@ -1,105 +0,0 @@ - - - - {% block head %} - {% block title %}{{ SITENAME|striptags }}{% endblock title %} - - - - {% if SITESUBTITLE %} - - {% endif %} - {% if STYLESHEET_URL %} - - {% endif %} - {% if FEED_ALL_ATOM %} - - {% endif %} - {% if FEED_ALL_RSS %} - - {% endif %} - {% if FEED_ATOM %} - - {% endif %} - {% if FEED_RSS %} - - {% endif %} - {% if CATEGORY_FEED_ATOM and category %} - - {% endif %} - {% if CATEGORY_FEED_RSS and category %} - - {% endif %} - {% if TAG_FEED_ATOM and tag %} - - {% endif %} - {% if TAG_FEED_RSS and tag %} - - {% endif %} - - - {% endblock head %} - - - - - -
      -
      -
      -
      -

      {{ SITENAME }}

      - {% if SITESUBTITLE %} -

      {{ SITESUBTITLE }}

      - {% endif %} -
      -
      -
      -
      - -
      -
      -
      -
      -
      - {% block content %} - {% endblock %} -
      -
      -
      -
      -
      -
      -
      - -
      -
      -
      -
      - - diff --git a/pelican/themes/simple/templates/index.html b/pelican/themes/simple/templates/index.html deleted file mode 100644 index afbc5688..00000000 --- a/pelican/themes/simple/templates/index.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends "base.html" %} -{% block content %} - {% block content_title %} -

      All articles

      - {% endblock %} - - {% for article in articles_page.object_list %} -
      -

      {{ article.title }}

      -
      {{ article.summary }}
      -
      -

      Published:

      - {% if article.authors %} -
      By - {% for author in article.authors %} - {{ author }} - {% endfor %} -
      - {% endif %} -
      -
      - {% endfor %} - - {% if articles_page.has_other_pages() %} - {% include 'pagination.html' %} - {% endif %} - -{% endblock content %} diff --git a/pelican/themes/simple/templates/page.html b/pelican/themes/simple/templates/page.html deleted file mode 100644 index bdd742f4..00000000 --- a/pelican/themes/simple/templates/page.html +++ /dev/null @@ -1,47 +0,0 @@ -{% extends "base.html" %} -{% block html_lang %}{{ page.lang }}{% endblock %} - -{% block title %}{{ SITENAME|striptags }} - {{ page.title|striptags }}{%endblock%} - -{% block head %} - {{ super() }} - - {% import 'translations.html' as translations with context %} - {% if translations.entry_hreflang(page) %} - {{ translations.entry_hreflang(page) }} - {% endif %} -{% endblock %} - -{% block content %} -
      -
      - {% if not page.image %} -

      {{ page.title }}

      - {% endif %} - {% if page.image %} - - -
      - - -
      - {% endif %} - - -
      - {% import 'translations.html' as translations with context %} - {{ translations.translations_for(page) }} -
      - {{ page.content }} -
      - - {% if page.modified %} -
      -

      -

      -
      - {% endif %} -
      -{% endblock %} diff --git a/pelican/themes/simple/templates/pagination.html b/pelican/themes/simple/templates/pagination.html deleted file mode 100644 index 4b1a9051..00000000 --- a/pelican/themes/simple/templates/pagination.html +++ /dev/null @@ -1,21 +0,0 @@ -{% if DEFAULT_PAGINATION %} {% set first_page = articles_paginator.page(1) %} {% -set last_page = articles_paginator.page(articles_paginator.num_pages) %} - -{% endif %} diff --git a/pelican/themes/simple/templates/translations.html b/pelican/themes/simple/templates/translations.html deleted file mode 100644 index eed0703d..00000000 --- a/pelican/themes/simple/templates/translations.html +++ /dev/null @@ -1,16 +0,0 @@ -{% macro translations_for(article) %} - {% if article.translations %} - Translations: - {% for translation in article.translations %} - {{ translation.lang }} - {% endfor %} - {% endif %} -{% endmacro %} - -{% macro entry_hreflang(entry) %} - {% if entry.translations %} - {% for translation in entry.translations %} - - {% endfor %} - {% endif %} -{% endmacro %} diff --git a/pelican/tools/__init__.py b/pelican/tools/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pelican/tools/pelican_import.py b/pelican/tools/pelican_import.py deleted file mode 100755 index 65517f42..00000000 --- a/pelican/tools/pelican_import.py +++ /dev/null @@ -1,1271 +0,0 @@ -#!/usr/bin/env python - -import argparse -import datetime -import logging -import os -import re -import subprocess -import sys -import tempfile -import time -from collections import defaultdict -from html import unescape -from urllib.error import URLError -from urllib.parse import quote, urlparse, urlsplit, urlunsplit -from urllib.request import urlretrieve - -import dateutil.parser - -# because logging.setLoggerClass has to be called before logging.getLogger -from pelican.log import init -from pelican.settings import DEFAULT_CONFIG -from pelican.utils import SafeDatetime, slugify - -logger = logging.getLogger(__name__) - - -def decode_wp_content(content, br=True): - pre_tags = {} - if content.strip() == "": - return "" - - content += "\n" - if "") - last_pre = pre_parts.pop() - content = "" - pre_index = 0 - - for pre_part in pre_parts: - start = pre_part.find("" - pre_tags[name] = pre_part[start:] + "" - content = content + pre_part[0:start] + name - pre_index += 1 - content = content + last_pre - - content = re.sub(r"
      \s*
      ", "\n\n", content) - allblocks = ( - "(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|" - "td|th|div|dl|dd|dt|ul|ol|li|pre|select|option|form|" - "map|area|blockquote|address|math|style|p|h[1-6]|hr|" - "fieldset|noscript|samp|legend|section|article|aside|" - "hgroup|header|footer|nav|figure|figcaption|details|" - "menu|summary)" - ) - content = re.sub(r"(<" + allblocks + r"[^>]*>)", "\n\\1", content) - content = re.sub(r"()", "\\1\n\n", content) - # content = content.replace("\r\n", "\n") - if " inside object/embed - content = re.sub(r"\s*]*)>\s*", "", content) - content = re.sub(r"\s*\s*", "", content) - # content = re.sub(r'/\n\n+/', '\n\n', content) - pgraphs = filter(lambda s: s != "", re.split(r"\n\s*\n", content)) - content = "" - for p in pgraphs: - content = content + "

      " + p.strip() + "

      \n" - # under certain strange conditions it could create - # a P of entirely whitespace - content = re.sub(r"

      \s*

      ", "", content) - content = re.sub(r"

      ([^<]+)", "

      \\1

      ", content) - # don't wrap tags - content = re.sub(r"

      \s*(]*>)\s*

      ", "\\1", content) - # problem with nested lists - content = re.sub(r"

      (", "\\1", content) - content = re.sub(r"

      ]*)>", "

      ", content) - content = content.replace("

      ", "

      ") - content = re.sub(r"

      \s*(]*>)", "\\1", content) - content = re.sub(r"(]*>)\s*

      ", "\\1", content) - if br: - - def _preserve_newline(match): - return match.group(0).replace("\n", "") - - content = re.sub(r"/<(script|style).*?<\/\\1>/s", _preserve_newline, content) - # optionally make line breaks - content = re.sub(r"(?)\s*\n", "
      \n", content) - content = content.replace("", "\n") - content = re.sub(r"(]*>)\s*
      ", "\\1", content) - content = re.sub( - r"
      (\s*]*>)", "\\1", content - ) - content = re.sub(r"\n

      ", "

      ", content) - - if pre_tags: - - def _multi_replace(dic, string): - pattern = r"|".join(map(re.escape, dic.keys())) - return re.sub(pattern, lambda m: dic[m.group()], string) - - content = _multi_replace(pre_tags, content) - - # convert [caption] tags into
      - content = re.sub( - r"\[caption(?:.*?)(?:caption=\"(.*?)\")?\]" - r"((?:\)?(?:\)(?:\<\/a\>)?)\s?(.*?)\[\/caption\]", - r"
      \n\2\n
      \1\3
      \n
      ", - content, - ) - - return content - - -def _import_bs4(): - """Import and return bs4, otherwise sys.exit.""" - try: - import bs4 - except ImportError: - error = ( - 'Missing dependency "BeautifulSoup4" and "lxml" required to ' - "import XML files." - ) - sys.exit(error) - return bs4 - - -def file_to_soup(xml, features="xml"): - """Reads a file, returns soup.""" - bs4 = _import_bs4() - with open(xml, encoding="utf-8") as infile: - xmlfile = infile.read() - soup = bs4.BeautifulSoup(xmlfile, features) - return soup - - -def get_filename(post_name, post_id): - if post_name is None or post_name.isspace(): - return post_id - else: - return post_name - - -def wp2fields(xml, wp_custpost=False): - """Opens a wordpress XML file, and yield Pelican fields""" - - soup = file_to_soup(xml) - items = soup.rss.channel.findAll("item") - for item in items: - if item.find("status").string in ["publish", "draft"]: - try: - # Use HTMLParser due to issues with BeautifulSoup 3 - title = unescape(item.title.contents[0]) - except IndexError: - title = "No title [{}]".format(item.find("post_name").string) - logger.warning('Post "%s" is lacking a proper title', title) - - post_name = item.find("post_name").string - post_id = item.find("post_id").string - filename = get_filename(post_name, post_id) - - content = item.find("encoded").string - raw_date = item.find("post_date").string - if raw_date == "0000-00-00 00:00:00": - date = None - else: - date_object = SafeDatetime.strptime(raw_date, "%Y-%m-%d %H:%M:%S") - date = date_object.strftime("%Y-%m-%d %H:%M") - author = item.find("creator").string - - categories = [ - cat.string for cat in item.findAll("category", {"domain": "category"}) - ] - - tags = [ - tag.string for tag in item.findAll("category", {"domain": "post_tag"}) - ] - # To publish a post the status should be 'published' - status = ( - "published" - if item.find("status").string == "publish" - else item.find("status").string - ) - - kind = "article" - post_type = item.find("post_type").string - if post_type == "page": - kind = "page" - elif wp_custpost: - if post_type == "post": - pass - # Old behaviour was to name everything not a page as an - # article.Theoretically all attachments have status == inherit - # so no attachments should be here. But this statement is to - # maintain existing behaviour in case that doesn't hold true. - elif post_type == "attachment": - pass - else: - kind = post_type - yield ( - title, - content, - filename, - date, - author, - categories, - tags, - status, - kind, - "wp-html", - ) - - -def blogger2fields(xml): - """Opens a blogger XML file, and yield Pelican fields""" - - soup = file_to_soup(xml) - entries = soup.feed.findAll("entry") - for entry in entries: - raw_kind = entry.find( - "category", {"scheme": "http://schemas.google.com/g/2005#kind"} - ).get("term") - if raw_kind == "http://schemas.google.com/blogger/2008/kind#post": - kind = "article" - elif raw_kind == "http://schemas.google.com/blogger/2008/kind#comment": - kind = "comment" - elif raw_kind == "http://schemas.google.com/blogger/2008/kind#page": - kind = "page" - else: - continue - - try: - assert kind != "comment" - filename = entry.find("link", {"rel": "alternate"})["href"] - filename = os.path.splitext(os.path.basename(filename))[0] - except (AssertionError, TypeError, KeyError): - filename = entry.find("id").string.split(".")[-1] - - title = entry.find("title").string or "" - - content = entry.find("content").string - raw_date = entry.find("published").string - if hasattr(SafeDatetime, "fromisoformat"): - date_object = SafeDatetime.fromisoformat(raw_date) - else: - date_object = SafeDatetime.strptime(raw_date[:23], "%Y-%m-%dT%H:%M:%S.%f") - date = date_object.strftime("%Y-%m-%d %H:%M") - author = entry.find("author").find("name").string - - # blogger posts only have tags, no category - tags = [ - tag.get("term") - for tag in entry.findAll( - "category", {"scheme": "http://www.blogger.com/atom/ns#"} - ) - ] - - # Drafts have yes - status = "published" - try: - if entry.find("control").find("draft").string == "yes": - status = "draft" - except AttributeError: - pass - - yield (title, content, filename, date, author, None, tags, status, kind, "html") - - -def dc2fields(file): - """Opens a Dotclear export file, and yield pelican fields""" - try: - from bs4 import BeautifulSoup - except ImportError: - error = ( - "Missing dependency " - '"BeautifulSoup4" and "lxml" required ' - "to import Dotclear files." - ) - sys.exit(error) - - in_cat = False - in_post = False - category_list = {} - posts = [] - - with open(file, encoding="utf-8") as f: - for line in f: - # remove final \n - line = line[:-1] - - if line.startswith("[category"): - in_cat = True - elif line.startswith("[post"): - in_post = True - elif in_cat: - fields = line.split('","') - if not line: - in_cat = False - else: - # remove 1st and last "" - fields[0] = fields[0][1:] - # fields[-1] = fields[-1][:-1] - category_list[fields[0]] = fields[2] - elif in_post: - if not line: - in_post = False - break - else: - posts.append(line) - - print("%i posts read." % len(posts)) - - subs = DEFAULT_CONFIG["SLUG_REGEX_SUBSTITUTIONS"] - for post in posts: - fields = post.split('","') - - # post_id = fields[0][1:] - # blog_id = fields[1] - # user_id = fields[2] - cat_id = fields[3] - # post_dt = fields[4] - # post_tz = fields[5] - post_creadt = fields[6] - # post_upddt = fields[7] - # post_password = fields[8] - # post_type = fields[9] - post_format = fields[10] - # post_url = fields[11] - # post_lang = fields[12] - post_title = fields[13] - post_excerpt = fields[14] - post_excerpt_xhtml = fields[15] - post_content = fields[16] - post_content_xhtml = fields[17] - # post_notes = fields[18] - # post_words = fields[19] - # post_status = fields[20] - # post_selected = fields[21] - # post_position = fields[22] - # post_open_comment = fields[23] - # post_open_tb = fields[24] - # nb_comment = fields[25] - # nb_trackback = fields[26] - post_meta = fields[27] - # redirect_url = fields[28][:-1] - - # remove seconds - post_creadt = ":".join(post_creadt.split(":")[0:2]) - - author = "" - categories = [] - tags = [] - - if cat_id: - categories = [category_list[id].strip() for id in cat_id.split(",")] - - # Get tags related to a post - tag = ( - post_meta.replace("{", "") - .replace("}", "") - .replace('a:1:s:3:\\"tag\\";a:', "") - .replace("a:0:", "") - ) - if len(tag) > 1: - if int(len(tag[:1])) == 1: - newtag = tag.split('"')[1] - tags.append( - BeautifulSoup(newtag, "xml") - # bs4 always outputs UTF-8 - .decode("utf-8") - ) - else: - i = 1 - j = 1 - while i <= int(tag[:1]): - newtag = tag.split('"')[j].replace("\\", "") - tags.append( - BeautifulSoup(newtag, "xml") - # bs4 always outputs UTF-8 - .decode("utf-8") - ) - i = i + 1 - if j < int(tag[:1]) * 2: - j = j + 2 - - """ - dotclear2 does not use markdown by default unless - you use the markdown plugin - Ref: http://plugins.dotaddict.org/dc2/details/formatting-markdown - """ - if post_format == "markdown": - content = post_excerpt + post_content - else: - content = post_excerpt_xhtml + post_content_xhtml - content = content.replace("\\n", "") - post_format = "html" - - kind = "article" # TODO: Recognise pages - status = "published" # TODO: Find a way for draft posts - - yield ( - post_title, - content, - slugify(post_title, regex_subs=subs), - post_creadt, - author, - categories, - tags, - status, - kind, - post_format, - ) - - -def _get_tumblr_posts(api_key, blogname, offset=0): - import json - import urllib.request as urllib_request - - url = ( - "https://api.tumblr.com/v2/blog/%s.tumblr.com/" - "posts?api_key=%s&offset=%d&filter=raw" - ) % (blogname, api_key, offset) - request = urllib_request.Request(url) - handle = urllib_request.urlopen(request) - posts = json.loads(handle.read().decode("utf-8")) - return posts.get("response").get("posts") - - -def tumblr2fields(api_key, blogname): - """Imports Tumblr posts (API v2)""" - offset = 0 - posts = _get_tumblr_posts(api_key, blogname, offset) - subs = DEFAULT_CONFIG["SLUG_REGEX_SUBSTITUTIONS"] - while len(posts) > 0: - for post in posts: - title = ( - post.get("title") - or post.get("source_title") - or post.get("type").capitalize() - ) - slug = post.get("slug") or slugify(title, regex_subs=subs) - tags = post.get("tags") - timestamp = post.get("timestamp") - date = SafeDatetime.fromtimestamp( - int(timestamp), tz=datetime.timezone.utc - ).strftime("%Y-%m-%d %H:%M:%S%z") - slug = ( - SafeDatetime.fromtimestamp( - int(timestamp), tz=datetime.timezone.utc - ).strftime("%Y-%m-%d-") - + slug - ) - format = post.get("format") - content = post.get("body") - type = post.get("type") - if type == "photo": - if format == "markdown": - fmtstr = "![%s](%s)" - else: - fmtstr = '%s' - content = "\n".join( - fmtstr - % (photo.get("caption"), photo.get("original_size").get("url")) - for photo in post.get("photos") - ) - elif type == "quote": - if format == "markdown": - fmtstr = "\n\n— %s" - else: - fmtstr = "

      — %s

      " - content = post.get("text") + fmtstr % post.get("source") - elif type == "link": - if format == "markdown": - fmtstr = "[via](%s)\n\n" - else: - fmtstr = '

      via

      \n' - content = fmtstr % post.get("url") + post.get("description") - elif type == "audio": - if format == "markdown": - fmtstr = "[via](%s)\n\n" - else: - fmtstr = '

      via

      \n' - content = ( - fmtstr % post.get("source_url") - + post.get("caption") - + post.get("player") - ) - elif type == "video": - if format == "markdown": - fmtstr = "[via](%s)\n\n" - else: - fmtstr = '

      via

      \n' - source = fmtstr % post.get("source_url") - caption = post.get("caption") - players = [ - # If embed_code is False, couldn't get the video - player.get("embed_code") or None - for player in post.get("player") - ] - # If there are no embeddable players, say so, once - if len(players) > 0 and all(player is None for player in players): - players = "

      (This video isn't available anymore.)

      \n" - else: - players = "\n".join(players) - content = source + caption + players - elif type == "answer": - title = post.get("question") - content = ( - "

      " - '{}' - ": {}" - "

      \n" - " {}".format( - post.get("asking_name"), - post.get("asking_url"), - post.get("question"), - post.get("answer"), - ) - ) - - content = content.rstrip() + "\n" - kind = "article" - status = "published" # TODO: Find a way for draft posts - - yield ( - title, - content, - slug, - date, - post.get("blog_name"), - [type], - tags, - status, - kind, - format, - ) - - offset += len(posts) - posts = _get_tumblr_posts(api_key, blogname, offset) - - -def strip_medium_post_content(soup) -> str: - """Strip some tags and attributes from medium post content. - - For example, the 'section' and 'div' tags cause trouble while rendering. - - The problem with these tags is you can get a section divider (--------------) - that is not between two pieces of content. For example: - - Some text. - - .. container:: section-divider - - -------------- - - .. container:: section-content - - More content. - - In this case, pandoc complains: "Unexpected section title or transition." - - Also, the "id" and "name" attributes in tags cause similar problems. They show - up in .rst as extra junk that separates transitions. - """ - # Remove tags - # section and div cause problems - # footer also can cause problems, and has nothing we want to keep - # See https://stackoverflow.com/a/8439761 - invalid_tags = ["section", "div", "footer"] - for tag in invalid_tags: - for match in soup.findAll(tag): - match.replaceWithChildren() - - # Remove attributes - # See https://stackoverflow.com/a/9045719 - invalid_attributes = ["name", "id", "class"] - bs4 = _import_bs4() - for tag in soup.descendants: - if isinstance(tag, bs4.element.Tag): - tag.attrs = { - key: value - for key, value in tag.attrs.items() - if key not in invalid_attributes - } - - # Get the string of all content, keeping other tags - all_content = "".join(str(element) for element in soup.contents) - return all_content - - -def mediumpost2fields(filepath: str) -> tuple: - """Take an HTML post from a medium export, return Pelican fields.""" - - soup = file_to_soup(filepath, "html.parser") - if not soup: - raise ValueError(f"{filepath} could not be parsed by beautifulsoup") - kind = "article" - - content = soup.find("section", class_="e-content") - if not content: - raise ValueError(f"{filepath}: Post has no content") - - title = soup.find("title").string or "" - - raw_date = soup.find("time", class_="dt-published") - date = None - if raw_date: - # This datetime can include timezone, e.g., "2017-04-21T17:11:55.799Z" - # python before 3.11 can't parse the timezone using datetime.fromisoformat - # See also https://docs.python.org/3.10/library/datetime.html#datetime.datetime.fromisoformat - # "This does not support parsing arbitrary ISO 8601 strings" - # So, we use dateutil.parser, which can handle it. - date_object = dateutil.parser.parse(raw_date.attrs["datetime"]) - date = date_object.strftime("%Y-%m-%d %H:%M") - status = "published" - else: - status = "draft" - author = soup.find("a", class_="p-author h-card") - if author: - author = author.string - - # Now that we're done with classes, we can strip the content - content = strip_medium_post_content(content) - - # medium HTML export doesn't have tag or category - # RSS feed has tags, but it doesn't have all the posts. - tags = () - - slug = medium_slug(filepath) - - # TODO: make the fields a python dataclass - return ( - title, - content, - slug, - date, - author, - None, - tags, - status, - kind, - "html", - ) - - -def medium_slug(filepath: str) -> str: - """Make the filepath of a medium exported file into a slug.""" - # slug: filename without extension - slug = os.path.basename(filepath) - slug = os.path.splitext(slug)[0] - # A medium export filename looks like date_-title-...html - # But, RST doesn't like "_-" (see https://github.com/sphinx-doc/sphinx/issues/4350) - # so get rid of it - slug = slug.replace("_-", "-") - # drop the hex string medium puts on the end of the filename, why keep it. - # e.g., "-a8a8a8a8" or "---a9a9a9a9" - # also: drafts don't need "--DRAFT" - slug = re.sub(r"((-)+([0-9a-f]+|DRAFT))+$", "", slug) - return slug - - -def mediumposts2fields(medium_export_dir: str): - """Take HTML posts in a medium export directory, and yield Pelican fields.""" - for file in os.listdir(medium_export_dir): - filename = os.fsdecode(file) - yield mediumpost2fields(os.path.join(medium_export_dir, filename)) - - -def feed2fields(file): - """Read a feed and yield pelican fields""" - import feedparser - - d = feedparser.parse(file) - subs = DEFAULT_CONFIG["SLUG_REGEX_SUBSTITUTIONS"] - for entry in d.entries: - date = ( - time.strftime("%Y-%m-%d %H:%M", entry.updated_parsed) - if hasattr(entry, "updated_parsed") - else None - ) - author = entry.author if hasattr(entry, "author") else None - tags = [e["term"] for e in entry.tags] if hasattr(entry, "tags") else None - - slug = slugify(entry.title, regex_subs=subs) - kind = "article" - yield ( - entry.title, - entry.description, - slug, - date, - author, - [], - tags, - None, - kind, - "html", - ) - - -def build_header( - title, date, author, categories, tags, slug, status=None, attachments=None -): - """Build a header from a list of fields""" - - from docutils.utils import column_width - - header = "{}\n{}\n".format(title, "#" * column_width(title)) - if date: - header += f":date: {date}\n" - if author: - header += f":author: {author}\n" - if categories: - header += ":category: {}\n".format(", ".join(categories)) - if tags: - header += ":tags: {}\n".format(", ".join(tags)) - if slug: - header += f":slug: {slug}\n" - if status: - header += f":status: {status}\n" - if attachments: - header += ":attachments: {}\n".format(", ".join(attachments)) - header += "\n" - return header - - -def build_asciidoc_header( - title, date, author, categories, tags, slug, status=None, attachments=None -): - """Build a header from a list of fields""" - - header = f"= {title}\n" - if author: - header += f"{author}\n" - if date: - header += f"{date}\n" - if categories: - header += ":category: {}\n".format(", ".join(categories)) - if tags: - header += ":tags: {}\n".format(", ".join(tags)) - if slug: - header += f":slug: {slug}\n" - if status: - header += f":status: {status}\n" - if attachments: - header += ":attachments: {}\n".format(", ".join(attachments)) - header += "\n" - return header - - -def build_markdown_header( - title, date, author, categories, tags, slug, status=None, attachments=None -): - """Build a header from a list of fields""" - header = f"Title: {title}\n" - if date: - header += f"Date: {date}\n" - if author: - header += f"Author: {author}\n" - if categories: - header += "Category: {}\n".format(", ".join(categories)) - if tags: - header += "Tags: {}\n".format(", ".join(tags)) - if slug: - header += f"Slug: {slug}\n" - if status: - header += f"Status: {status}\n" - if attachments: - header += "Attachments: {}\n".format(", ".join(attachments)) - header += "\n" - return header - - -def get_ext(out_markup, in_markup="html"): - if out_markup == "asciidoc": - ext = ".adoc" - elif in_markup == "markdown" or out_markup == "markdown": - ext = ".md" - else: - ext = ".rst" - return ext - - -def get_out_filename( - output_path, - filename, - ext, - kind, - dirpage, - dircat, - categories, - wp_custpost, - slug_subs, -): - filename = os.path.basename(filename) - - # Enforce filename restrictions for various filesystems at once; see - # https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words - # we do not need to filter words because an extension will be appended - filename = re.sub(r'[<>:"/\\|?*^% ]', "-", filename) # invalid chars - filename = filename.lstrip(".") # should not start with a dot - if not filename: - filename = "_" - filename = filename[:249] # allow for 5 extra characters - - out_filename = os.path.join(output_path, filename + ext) - # option to put page posts in pages/ subdirectory - if dirpage and kind == "page": - pages_dir = os.path.join(output_path, "pages") - if not os.path.isdir(pages_dir): - os.mkdir(pages_dir) - out_filename = os.path.join(pages_dir, filename + ext) - elif not dirpage and kind == "page": - pass - # option to put wp custom post types in directories with post type - # names. Custom post types can also have categories so option to - # create subdirectories with category names - elif kind != "article": - if wp_custpost: - typename = slugify(kind, regex_subs=slug_subs) - else: - typename = "" - kind = "article" - if dircat and (len(categories) > 0): - catname = slugify(categories[0], regex_subs=slug_subs, preserve_case=True) - else: - catname = "" - out_filename = os.path.join(output_path, typename, catname, filename + ext) - if not os.path.isdir(os.path.join(output_path, typename, catname)): - os.makedirs(os.path.join(output_path, typename, catname)) - # option to put files in directories with categories names - elif dircat and (len(categories) > 0): - catname = slugify(categories[0], regex_subs=slug_subs, preserve_case=True) - out_filename = os.path.join(output_path, catname, filename + ext) - if not os.path.isdir(os.path.join(output_path, catname)): - os.mkdir(os.path.join(output_path, catname)) - - return out_filename - - -def get_attachments(xml): - """returns a dictionary of posts that have attachments with a list - of the attachment_urls - """ - soup = file_to_soup(xml) - items = soup.rss.channel.findAll("item") - names = {} - attachments = [] - - for item in items: - kind = item.find("post_type").string - post_name = item.find("post_name").string - post_id = item.find("post_id").string - - if kind == "attachment": - attachments.append( - (item.find("post_parent").string, item.find("attachment_url").string) - ) - else: - filename = get_filename(post_name, post_id) - names[post_id] = filename - attachedposts = defaultdict(set) - for parent, url in attachments: - try: - parent_name = names[parent] - except KeyError: - # attachment's parent is not a valid post - parent_name = None - - attachedposts[parent_name].add(url) - return attachedposts - - -def download_attachments(output_path, urls): - """Downloads WordPress attachments and returns a list of paths to - attachments that can be associated with a post (relative path to output - directory). Files that fail to download, will not be added to posts""" - locations = {} - for url in urls: - path = urlparse(url).path - # teardown path and rebuild to negate any errors with - # os.path.join and leading /'s - path = path.split("/") - filename = path.pop(-1) - localpath = "" - for item in path: - if sys.platform != "win32" or ":" not in item: - localpath = os.path.join(localpath, item) - full_path = os.path.join(output_path, localpath) - - # Generate percent-encoded URL - scheme, netloc, path, query, fragment = urlsplit(url) - if scheme != "file": - path = quote(path) - url = urlunsplit((scheme, netloc, path, query, fragment)) - - if not os.path.exists(full_path): - os.makedirs(full_path) - print(f"downloading {filename}") - try: - urlretrieve(url, os.path.join(full_path, filename)) - locations[url] = os.path.join(localpath, filename) - except (URLError, OSError) as e: - # Python 2.7 throws an IOError rather Than URLError - logger.warning("No file could be downloaded from %s\n%s", url, e) - return locations - - -def is_pandoc_needed(in_markup): - return in_markup in ("html", "wp-html") - - -def get_pandoc_version(): - cmd = ["pandoc", "--version"] - try: - output = subprocess.check_output(cmd, text=True) - except (subprocess.CalledProcessError, OSError) as e: - logger.warning("Pandoc version unknown: %s", e) - return () - - return tuple(int(i) for i in output.split()[1].split(".")) - - -def update_links_to_attached_files(content, attachments): - for old_url, new_path in attachments.items(): - # url may occur both with http:// and https:// - http_url = old_url.replace("https://", "http://") - https_url = old_url.replace("http://", "https://") - for url in [http_url, https_url]: - content = content.replace(url, "{static}" + new_path) - return content - - -def fields2pelican( - fields, - out_markup, - output_path, - dircat=False, - strip_raw=False, - disable_slugs=False, - dirpage=False, - filename_template=None, - filter_author=None, - wp_custpost=False, - wp_attach=False, - attachments=None, -): - pandoc_version = get_pandoc_version() - posts_require_pandoc = [] - - slug_subs = DEFAULT_CONFIG["SLUG_REGEX_SUBSTITUTIONS"] - - for ( - title, - content, - filename, - date, - author, - categories, - tags, - status, - kind, - in_markup, - ) in fields: - if filter_author and filter_author != author: - continue - if is_pandoc_needed(in_markup) and not pandoc_version: - posts_require_pandoc.append(filename) - - slug = not disable_slugs and filename or None - assert slug is None or filename == os.path.basename( - filename - ), f"filename is not a basename: {filename}" - - if wp_attach and attachments: - try: - urls = attachments[filename] - links = download_attachments(output_path, urls) - except KeyError: - links = None - else: - links = None - - ext = get_ext(out_markup, in_markup) - if ext == ".adoc": - header = build_asciidoc_header( - title, date, author, categories, tags, slug, status, attachments - ) - elif ext == ".md": - header = build_markdown_header( - title, - date, - author, - categories, - tags, - slug, - status, - links.values() if links else None, - ) - else: - out_markup = "rst" - header = build_header( - title, - date, - author, - categories, - tags, - slug, - status, - links.values() if links else None, - ) - - out_filename = get_out_filename( - output_path, - filename, - ext, - kind, - dirpage, - dircat, - categories, - wp_custpost, - slug_subs, - ) - print(out_filename) - - if in_markup in ("html", "wp-html"): - with tempfile.TemporaryDirectory() as tmpdir: - html_filename = os.path.join(tmpdir, "pandoc-input.html") - # Replace newlines with paragraphs wrapped with

      so - # HTML is valid before conversion - if in_markup == "wp-html": - new_content = decode_wp_content(content) - else: - paragraphs = content.splitlines() - paragraphs = [f"

      {p}

      " for p in paragraphs] - new_content = "".join(paragraphs) - with open(html_filename, "w", encoding="utf-8") as fp: - fp.write(new_content) - - if pandoc_version < (2,): - parse_raw = "--parse-raw" if not strip_raw else "" - wrap_none = ( - "--wrap=none" if pandoc_version >= (1, 16) else "--no-wrap" - ) - cmd = ( - "pandoc --normalize {0} --from=html" - ' --to={1} {2} -o "{3}" "{4}"' - ) - cmd = cmd.format( - parse_raw, - out_markup if out_markup != "markdown" else "gfm", - wrap_none, - out_filename, - html_filename, - ) - else: - from_arg = "-f html+raw_html" if not strip_raw else "-f html" - cmd = 'pandoc {0} --to={1}-smart --wrap=none -o "{2}" "{3}"' - cmd = cmd.format( - from_arg, - out_markup if out_markup != "markdown" else "gfm", - out_filename, - html_filename, - ) - - try: - rc = subprocess.call(cmd, shell=True) - if rc < 0: - error = "Child was terminated by signal %d" % -rc - sys.exit(error) - - elif rc > 0: - error = "Please, check your Pandoc installation." - sys.exit(error) - except OSError as e: - error = f"Pandoc execution failed: {e}" - sys.exit(error) - - with open(out_filename, encoding="utf-8") as fs: - content = fs.read() - if out_markup == "markdown": - # In markdown, to insert a
      , end a line with two - # or more spaces & then a end-of-line - content = content.replace("\\\n ", " \n") - content = content.replace("\\\n", " \n") - - if wp_attach and links: - content = update_links_to_attached_files(content, links) - - with open(out_filename, "w", encoding="utf-8") as fs: - fs.write(header + content) - - if posts_require_pandoc: - logger.error( - "Pandoc must be installed to import the following posts:\n {}".format( - "\n ".join(posts_require_pandoc) - ) - ) - - if wp_attach and attachments and None in attachments: - print("downloading attachments that don't have a parent post") - urls = attachments[None] - download_attachments(output_path, urls) - - -def main(): - parser = argparse.ArgumentParser( - description="Transform feed, Blogger, Dotclear, Tumblr, or " - "WordPress files into reST (rst) or Markdown (md) files. " - "Be sure to have pandoc installed.", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - - parser.add_argument(dest="input", help="The input file to read") - parser.add_argument( - "--blogger", action="store_true", dest="blogger", help="Blogger XML export" - ) - parser.add_argument( - "--dotclear", action="store_true", dest="dotclear", help="Dotclear export" - ) - parser.add_argument( - "--medium", action="store_true", dest="medium", help="Medium export" - ) - parser.add_argument( - "--tumblr", action="store_true", dest="tumblr", help="Tumblr export" - ) - parser.add_argument( - "--wpfile", action="store_true", dest="wpfile", help="Wordpress XML export" - ) - parser.add_argument( - "--feed", action="store_true", dest="feed", help="Feed to parse" - ) - parser.add_argument( - "-o", "--output", dest="output", default="content", help="Output path" - ) - parser.add_argument( - "-m", - "--markup", - dest="markup", - default="rst", - help="Output markup format (supports rst & markdown)", - ) - parser.add_argument( - "--dir-cat", - action="store_true", - dest="dircat", - help="Put files in directories with categories name", - ) - parser.add_argument( - "--dir-page", - action="store_true", - dest="dirpage", - help=( - 'Put files recognised as pages in "pages/" sub-directory' - " (blogger and wordpress import only)" - ), - ) - parser.add_argument( - "--filter-author", - dest="author", - help="Import only post from the specified author", - ) - parser.add_argument( - "--strip-raw", - action="store_true", - dest="strip_raw", - help="Strip raw HTML code that can't be converted to " - "markup such as flash embeds or iframes (wordpress import only)", - ) - parser.add_argument( - "--wp-custpost", - action="store_true", - dest="wp_custpost", - help="Put wordpress custom post types in directories. If used with " - "--dir-cat option directories will be created as " - "/post_type/category/ (wordpress import only)", - ) - parser.add_argument( - "--wp-attach", - action="store_true", - dest="wp_attach", - help="(wordpress import only) Download files uploaded to wordpress as " - "attachments. Files will be added to posts as a list in the post " - "header. All files will be downloaded, even if " - "they aren't associated with a post. Files will be downloaded " - "with their original path inside the output directory. " - "e.g. output/wp-uploads/date/postname/file.jpg " - "-- Requires an internet connection --", - ) - parser.add_argument( - "--disable-slugs", - action="store_true", - dest="disable_slugs", - help="Disable storing slugs from imported posts within output. " - "With this disabled, your Pelican URLs may not be consistent " - "with your original posts.", - ) - parser.add_argument( - "-b", "--blogname", dest="blogname", help="Blog name (Tumblr import only)" - ) - - args = parser.parse_args() - - input_type = None - if args.blogger: - input_type = "blogger" - elif args.dotclear: - input_type = "dotclear" - elif args.medium: - input_type = "medium" - elif args.tumblr: - input_type = "tumblr" - elif args.wpfile: - input_type = "wordpress" - elif args.feed: - input_type = "feed" - else: - error = ( - "You must provide one of --blogger, --dotclear, " - "--medium, --tumblr, --wpfile or --feed options" - ) - sys.exit(error) - - if not os.path.exists(args.output): - try: - os.mkdir(args.output) - except OSError: - error = "Unable to create the output folder: " + args.output - sys.exit(error) - - if args.wp_attach and input_type != "wordpress": - error = "You must be importing a wordpress xml to use the --wp-attach option" - sys.exit(error) - - if input_type == "blogger": - fields = blogger2fields(args.input) - elif input_type == "dotclear": - fields = dc2fields(args.input) - elif input_type == "medium": - fields = mediumposts2fields(args.input) - elif input_type == "tumblr": - fields = tumblr2fields(args.input, args.blogname) - elif input_type == "wordpress": - fields = wp2fields(args.input, args.wp_custpost or False) - elif input_type == "feed": - fields = feed2fields(args.input) - else: - raise ValueError(f"Unhandled input_type {input_type}") - - if args.wp_attach: - attachments = get_attachments(args.input) - else: - attachments = None - - # init logging - init() - fields2pelican( - fields, - args.markup, - args.output, - dircat=args.dircat or False, - dirpage=args.dirpage or False, - strip_raw=args.strip_raw or False, - disable_slugs=args.disable_slugs or False, - filter_author=args.author, - wp_custpost=args.wp_custpost or False, - wp_attach=args.wp_attach or False, - attachments=attachments or None, - ) diff --git a/pelican/tools/pelican_quickstart.py b/pelican/tools/pelican_quickstart.py deleted file mode 100755 index e278e3bc..00000000 --- a/pelican/tools/pelican_quickstart.py +++ /dev/null @@ -1,401 +0,0 @@ -#!/usr/bin/env python - -import argparse -import locale -import os -from typing import Mapping - -from jinja2 import Environment, FileSystemLoader - -try: - import zoneinfo -except ModuleNotFoundError: - from backports import zoneinfo - -try: - import readline # NOQA -except ImportError: - pass - -try: - import tzlocal - - if hasattr(tzlocal.get_localzone(), "zone"): - _DEFAULT_TIMEZONE = tzlocal.get_localzone().zone - else: - _DEFAULT_TIMEZONE = tzlocal.get_localzone_name() -except ModuleNotFoundError: - _DEFAULT_TIMEZONE = "Europe/Rome" - -from pelican import __version__ - -locale.setlocale(locale.LC_ALL, "") -try: - _DEFAULT_LANGUAGE = locale.getlocale()[0] -except ValueError: - # Don't fail on macosx: "unknown locale: UTF-8" - _DEFAULT_LANGUAGE = None -if _DEFAULT_LANGUAGE is None: - _DEFAULT_LANGUAGE = "en" -else: - _DEFAULT_LANGUAGE = _DEFAULT_LANGUAGE.split("_")[0] - -_TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "templates") -_jinja_env = Environment( - loader=FileSystemLoader(_TEMPLATES_DIR), - trim_blocks=True, - keep_trailing_newline=True, -) - - -_GITHUB_PAGES_BRANCHES = {"personal": "main", "project": "gh-pages"} - -CONF = { - "pelican": "pelican", - "pelicanopts": "", - "basedir": os.curdir, - "ftp_host": "localhost", - "ftp_user": "anonymous", - "ftp_target_dir": "/", - "ssh_host": "localhost", - "ssh_port": 22, - "ssh_user": "root", - "ssh_target_dir": "/var/www", - "s3_bucket": "my_s3_bucket", - "cloudfiles_username": "my_rackspace_username", - "cloudfiles_api_key": "my_rackspace_api_key", - "cloudfiles_container": "my_cloudfiles_container", - "dropbox_dir": "~/Dropbox/Public/", - "github_pages_branch": _GITHUB_PAGES_BRANCHES["project"], - "default_pagination": 10, - "siteurl": "", - "lang": _DEFAULT_LANGUAGE, - "timezone": _DEFAULT_TIMEZONE, -} - -# url for list of valid timezones -_TZ_URL = "https://en.wikipedia.org/wiki/List_of_tz_database_time_zones" - - -# Create a 'marked' default path, to determine if someone has supplied -# a path on the command-line. -class _DEFAULT_PATH_TYPE(str): # noqa: SLOT000 - is_default_path = True - - -_DEFAULT_PATH = _DEFAULT_PATH_TYPE(os.curdir) - - -def ask(question, answer=str, default=None, length=None): - if answer == str: - r = "" - while True: - if default: - r = input(f"> {question} [{default}] ") - else: - r = input(f"> {question} ") - - r = r.strip() - - if len(r) <= 0: - if default: - r = default - break - else: - print("You must enter something") - elif length and len(r) != length: - print(f"Entry must be {length} characters long") - else: - break - - return r - - elif answer == bool: - r = None - while True: - if default is True: - r = input(f"> {question} (Y/n) ") - elif default is False: - r = input(f"> {question} (y/N) ") - else: - r = input(f"> {question} (y/n) ") - - r = r.strip().lower() - - if r in ("y", "yes"): - r = True - break - elif r in ("n", "no"): - r = False - break - elif not r: - r = default - break - else: - print("You must answer 'yes' or 'no'") - return r - elif answer == int: - r = None - while True: - if default: - r = input(f"> {question} [{default}] ") - else: - r = input(f"> {question} ") - - r = r.strip() - - if not r: - r = default - break - - try: - r = int(r) - break - except ValueError: - print("You must enter an integer") - return r - else: - raise NotImplementedError("Argument `answer` must be str, bool, or integer") - - -def ask_timezone(question, default, tzurl): - """Prompt for time zone and validate input""" - tz_dict = {tz.lower(): tz for tz in zoneinfo.available_timezones()} - while True: - r = ask(question, str, default) - r = r.strip().replace(" ", "_").lower() - if r in tz_dict.keys(): - r = tz_dict[r] - break - else: - print(f"Please enter a valid time zone:\n (check [{tzurl}])") - return r - - -def render_jinja_template(tmpl_name: str, tmpl_vars: Mapping, target_path: str): - try: - with open( - os.path.join(CONF["basedir"], target_path), "w", encoding="utf-8" - ) as fd: - _template = _jinja_env.get_template(tmpl_name) - fd.write(_template.render(**tmpl_vars)) - except OSError as e: - print(f"Error: {e}") - - -def main(): - parser = argparse.ArgumentParser( - description="A kickstarter for Pelican", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "-p", "--path", default=_DEFAULT_PATH, help="The path to generate the blog into" - ) - parser.add_argument( - "-t", "--title", metavar="title", help="Set the title of the website" - ) - parser.add_argument( - "-a", "--author", metavar="author", help="Set the author name of the website" - ) - parser.add_argument( - "-l", "--lang", metavar="lang", help="Set the default web site language" - ) - - args = parser.parse_args() - - print( - f"""Welcome to pelican-quickstart v{__version__}. - -This script will help you create a new Pelican-based website. - -Please answer the following questions so this script can generate the files -needed by Pelican. - - """ - ) - - project = os.path.join(os.environ.get("VIRTUAL_ENV", os.curdir), ".project") - no_path_was_specified = hasattr(args.path, "is_default_path") - if os.path.isfile(project) and no_path_was_specified: - CONF["basedir"] = open(project).read().rstrip("\n") - print( - "Using project associated with current virtual environment. " - "Will save to:\n{}\n".format(CONF["basedir"]) - ) - else: - CONF["basedir"] = os.path.abspath( - os.path.expanduser( - ask( - "Where do you want to create your new web site?", - answer=str, - default=args.path, - ) - ) - ) - - CONF["sitename"] = ask( - "What will be the title of this web site?", answer=str, default=args.title - ) - CONF["author"] = ask( - "Who will be the author of this web site?", answer=str, default=args.author - ) - CONF["lang"] = ask( - "What will be the default language of this web site?", - str, - args.lang or CONF["lang"], - 2, - ) - - if ask( - "Do you want to specify a URL prefix? e.g., https://example.com ", - answer=bool, - default=True, - ): - CONF["siteurl"] = ask( - "What is your URL prefix? (see above example; no trailing slash)", - str, - CONF["siteurl"], - ) - - CONF["with_pagination"] = ask( - "Do you want to enable article pagination?", - bool, - bool(CONF["default_pagination"]), - ) - - if CONF["with_pagination"]: - CONF["default_pagination"] = ask( - "How many articles per page do you want?", - int, - CONF["default_pagination"], - ) - else: - CONF["default_pagination"] = False - - CONF["timezone"] = ask_timezone( - "What is your time zone?", CONF["timezone"], _TZ_URL - ) - - automation = ask( - "Do you want to generate a tasks.py/Makefile " - "to automate generation and publishing?", - bool, - True, - ) - - if automation: - if ask( - "Do you want to upload your website using FTP?", answer=bool, default=False - ): - CONF["ftp"] = (True,) - CONF["ftp_host"] = ask( - "What is the hostname of your FTP server?", str, CONF["ftp_host"] - ) - CONF["ftp_user"] = ask( - "What is your username on that server?", str, CONF["ftp_user"] - ) - CONF["ftp_target_dir"] = ask( - "Where do you want to put your web site on that server?", - str, - CONF["ftp_target_dir"], - ) - if ask( - "Do you want to upload your website using SSH?", answer=bool, default=False - ): - CONF["ssh"] = (True,) - CONF["ssh_host"] = ask( - "What is the hostname of your SSH server?", str, CONF["ssh_host"] - ) - CONF["ssh_port"] = ask( - "What is the port of your SSH server?", int, CONF["ssh_port"] - ) - CONF["ssh_user"] = ask( - "What is your username on that server?", str, CONF["ssh_user"] - ) - CONF["ssh_target_dir"] = ask( - "Where do you want to put your web site on that server?", - str, - CONF["ssh_target_dir"], - ) - - if ask( - "Do you want to upload your website using Dropbox?", - answer=bool, - default=False, - ): - CONF["dropbox"] = (True,) - CONF["dropbox_dir"] = ask( - "Where is your Dropbox directory?", str, CONF["dropbox_dir"] - ) - - if ask( - "Do you want to upload your website using S3?", answer=bool, default=False - ): - CONF["s3"] = (True,) - CONF["s3_bucket"] = ask( - "What is the name of your S3 bucket?", str, CONF["s3_bucket"] - ) - - if ask( - "Do you want to upload your website using Rackspace Cloud Files?", - answer=bool, - default=False, - ): - CONF["cloudfiles"] = (True,) - CONF["cloudfiles_username"] = ask( - "What is your Rackspace Cloud username?", - str, - CONF["cloudfiles_username"], - ) - CONF["cloudfiles_api_key"] = ask( - "What is your Rackspace Cloud API key?", - str, - CONF["cloudfiles_api_key"], - ) - CONF["cloudfiles_container"] = ask( - "What is the name of your Cloud Files container?", - str, - CONF["cloudfiles_container"], - ) - - if ask( - "Do you want to upload your website using GitHub Pages?", - answer=bool, - default=False, - ): - CONF["github"] = (True,) - if ask( - "Is this your personal page (username.github.io)?", - answer=bool, - default=False, - ): - CONF["github_pages_branch"] = _GITHUB_PAGES_BRANCHES["personal"] - else: - CONF["github_pages_branch"] = _GITHUB_PAGES_BRANCHES["project"] - - try: - os.makedirs(os.path.join(CONF["basedir"], "content")) - except OSError as e: - print(f"Error: {e}") - - try: - os.makedirs(os.path.join(CONF["basedir"], "output")) - except OSError as e: - print(f"Error: {e}") - - conf_python = {} - for key, value in CONF.items(): - conf_python[key] = repr(value) - render_jinja_template("pelicanconf.py.jinja2", conf_python, "pelicanconf.py") - - render_jinja_template("publishconf.py.jinja2", CONF, "publishconf.py") - - if automation: - render_jinja_template("tasks.py.jinja2", CONF, "tasks.py") - render_jinja_template("Makefile.jinja2", CONF, "Makefile") - - print("Done. Your new project is available at {}".format(CONF["basedir"])) - - -if __name__ == "__main__": - main() diff --git a/pelican/tools/pelican_themes.py b/pelican/tools/pelican_themes.py deleted file mode 100755 index fa59b8fd..00000000 --- a/pelican/tools/pelican_themes.py +++ /dev/null @@ -1,291 +0,0 @@ -#!/usr/bin/env python - -import argparse -import os -import shutil -import sys - - -def err(msg, die=None): - """Print an error message and exits if an exit code is given""" - sys.stderr.write(msg + "\n") - if die: - sys.exit(die if isinstance(die, int) else 1) - - -try: - import pelican -except ImportError: - err( - "Cannot import pelican.\nYou must " - "install Pelican in order to run this script.", - -1, - ) - - -global _THEMES_PATH -_THEMES_PATH = os.path.join( - os.path.dirname(os.path.abspath(pelican.__file__)), "themes" -) - -__version__ = "0.2" -_BUILTIN_THEMES = ["simple", "notmyidea"] - - -def main(): - """Main function""" - - parser = argparse.ArgumentParser(description="""Install themes for Pelican""") - - excl = parser.add_mutually_exclusive_group() - excl.add_argument( - "-l", - "--list", - dest="action", - action="store_const", - const="list", - help="Show the themes already installed and exit", - ) - excl.add_argument( - "-p", - "--path", - dest="action", - action="store_const", - const="path", - help="Show the themes path and exit", - ) - excl.add_argument( - "-V", - "--version", - action="version", - version=f"pelican-themes v{__version__}", - help="Print the version of this script", - ) - - parser.add_argument( - "-i", - "--install", - dest="to_install", - nargs="+", - metavar="theme path", - help="The themes to install", - ) - parser.add_argument( - "-r", - "--remove", - dest="to_remove", - nargs="+", - metavar="theme name", - help="The themes to remove", - ) - parser.add_argument( - "-U", - "--upgrade", - dest="to_upgrade", - nargs="+", - metavar="theme path", - help="The themes to upgrade", - ) - parser.add_argument( - "-s", - "--symlink", - dest="to_symlink", - nargs="+", - metavar="theme path", - help="Same as `--install', but create a symbolic link instead of " - "copying the theme. Useful for theme development", - ) - parser.add_argument( - "-c", - "--clean", - dest="clean", - action="store_true", - help="Remove the broken symbolic links of the theme path", - ) - - parser.add_argument( - "-v", "--verbose", dest="verbose", action="store_true", help="Verbose output" - ) - - args = parser.parse_args() - - to_install = args.to_install or args.to_upgrade - to_sym = args.to_symlink or args.clean - - if args.action: - if args.action == "list": - list_themes(args.verbose) - elif args.action == "path": - print(_THEMES_PATH) - elif to_install or args.to_remove or to_sym: - if args.to_remove: - if args.verbose: - print("Removing themes...") - - for i in args.to_remove: - remove(i, v=args.verbose) - - if args.to_install: - if args.verbose: - print("Installing themes...") - - for i in args.to_install: - install(i, v=args.verbose) - - if args.to_upgrade: - if args.verbose: - print("Upgrading themes...") - - for i in args.to_upgrade: - install(i, v=args.verbose, u=True) - - if args.to_symlink: - if args.verbose: - print("Linking themes...") - - for i in args.to_symlink: - symlink(i, v=args.verbose) - - if args.clean: - if args.verbose: - print("Cleaning the themes directory...") - - clean(v=args.verbose) - else: - print("No argument given... exiting.") - - -def themes(): - """Returns the list of the themes""" - for i in os.listdir(_THEMES_PATH): - e = os.path.join(_THEMES_PATH, i) - - if os.path.isdir(e): - if os.path.islink(e): - yield (e, os.readlink(e)) - else: - yield (e, None) - - -def list_themes(v=False): - """Display the list of the themes""" - for theme_path, link_target in themes(): - if not v: - theme_path = os.path.basename(theme_path) - if link_target: - if v: - print(theme_path + (" (symbolic link to `" + link_target + "')")) - else: - print(theme_path + "@") - else: - print(theme_path) - - -def remove(theme_name, v=False): - """Removes a theme""" - - theme_name = theme_name.replace("/", "") - target = os.path.join(_THEMES_PATH, theme_name) - - if theme_name in _BUILTIN_THEMES: - err( - theme_name + " is a builtin theme.\n" - "You cannot remove a builtin theme with this script, " - "remove it by hand if you want." - ) - elif os.path.islink(target): - if v: - print("Removing link `" + target + "'") - os.remove(target) - elif os.path.isdir(target): - if v: - print("Removing directory `" + target + "'") - shutil.rmtree(target) - elif os.path.exists(target): - err(target + " : not a valid theme") - else: - err(target + " : no such file or directory") - - -def install(path, v=False, u=False): - """Installs a theme""" - if not os.path.exists(path): - err(path + " : no such file or directory") - elif not os.path.isdir(path): - err(path + " : not a directory") - else: - theme_name = os.path.basename(os.path.normpath(path)) - theme_path = os.path.join(_THEMES_PATH, theme_name) - exists = os.path.exists(theme_path) - if exists and not u: - err(path + " : already exists") - elif exists: - remove(theme_name, v) - install(path, v) - else: - if v: - print(f"Copying '{path}' to '{theme_path}' ...") - try: - shutil.copytree(path, theme_path) - - try: - if os.name == "posix": - for root, dirs, files in os.walk(theme_path): - for d in dirs: - dname = os.path.join(root, d) - os.chmod(dname, 493) # 0o755 - for f in files: - fname = os.path.join(root, f) - os.chmod(fname, 420) # 0o644 - except OSError as e: - err( - "Cannot change permissions of files " - f"or directory in `{theme_path}':\n{e!s}", - die=False, - ) - except Exception as e: - err(f"Cannot copy `{path}' to `{theme_path}':\n{e!s}") - - -def symlink(path, v=False): - """Symbolically link a theme""" - if not os.path.exists(path): - err(path + " : no such file or directory") - elif not os.path.isdir(path): - err(path + " : not a directory") - else: - theme_name = os.path.basename(os.path.normpath(path)) - theme_path = os.path.join(_THEMES_PATH, theme_name) - if os.path.exists(theme_path): - err(path + " : already exists") - else: - if v: - print(f"Linking `{path}' to `{theme_path}' ...") - try: - os.symlink(path, theme_path) - except Exception as e: - err(f"Cannot link `{path}' to `{theme_path}':\n{e!s}") - - -def is_broken_link(path): - """Returns True if the path given as is a broken symlink""" - path = os.readlink(path) - return not os.path.exists(path) - - -def clean(v=False): - """Removes the broken symbolic links""" - c = 0 - for path in os.listdir(_THEMES_PATH): - path = os.path.join(_THEMES_PATH, path) - if os.path.islink(path) and is_broken_link(path): - if v: - print(f"Removing {path}") - try: - os.remove(path) - except OSError: - print(f"Error: cannot remove {path}") - else: - c += 1 - - print(f"\nRemoved {c} broken links") diff --git a/pelican/tools/templates/Makefile.jinja2 b/pelican/tools/templates/Makefile.jinja2 deleted file mode 100644 index 67571b47..00000000 --- a/pelican/tools/templates/Makefile.jinja2 +++ /dev/null @@ -1,170 +0,0 @@ -PY?={{py_v}} -PELICAN?={{pelican}} -PELICANOPTS={{pelicanopts}} - -BASEDIR=$(CURDIR) -INPUTDIR=$(BASEDIR)/content -OUTPUTDIR=$(BASEDIR)/output -CONFFILE=$(BASEDIR)/pelicanconf.py -PUBLISHCONF=$(BASEDIR)/publishconf.py - -{% if ftp %} -FTP_HOST={{ftp_host}} -FTP_USER={{ftp_user}} -FTP_TARGET_DIR={{ftp_target_dir}} - -{% endif %} -{% if ssh %} -SSH_HOST={{ssh_host}} -SSH_PORT={{ssh_port}} -SSH_USER={{ssh_user}} -SSH_TARGET_DIR={{ssh_target_dir}} - -{% endif %} -{% if s3 %} -S3_BUCKET={{s3_bucket}} - -{% endif %} -{% if cloudfiles %} -CLOUDFILES_USERNAME={{cloudfiles_username}} -CLOUDFILES_API_KEY={{cloudfiles_api_key}} -CLOUDFILES_CONTAINER={{cloudfiles_container}} - -{% endif %} -{% if dropbox %} -DROPBOX_DIR={{dropbox_dir}} - -{% endif %} -{% if github %} -GITHUB_PAGES_BRANCH={{github_pages_branch}} -GITHUB_PAGES_COMMIT_MESSAGE=Generate Pelican site - -{% endif %} - -DEBUG ?= 0 -ifeq ($(DEBUG), 1) - PELICANOPTS += -D -endif - -RELATIVE ?= 0 -ifeq ($(RELATIVE), 1) - PELICANOPTS += --relative-urls -endif - -SERVER ?= "0.0.0.0" - -PORT ?= 0 -ifneq ($(PORT), 0) - PELICANOPTS += -p $(PORT) -endif - - -help: - @echo 'Makefile for a pelican Web site ' - @echo ' ' - @echo 'Usage: ' - @echo ' make html (re)generate the web site ' - @echo ' make clean remove the generated files ' - @echo ' make regenerate regenerate files upon modification ' - @echo ' make publish generate using production settings ' - @echo ' make serve [PORT=8000] serve site at http://localhost:8000' - @echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 ' - @echo ' make devserver [PORT=8000] serve and regenerate together ' - @echo ' make devserver-global regenerate and serve on 0.0.0.0 ' -{% if ssh %} - @echo ' make ssh_upload upload the web site via SSH ' - @echo ' make sftp_upload upload the web site via SFTP ' - @echo ' make rsync_upload upload the web site via rsync+ssh ' -{% endif %} -{% if dropbox %} - @echo ' make dropbox_upload upload the web site via Dropbox ' -{% endif %} -{% if ftp %} - @echo ' make ftp_upload upload the web site via FTP ' -{% endif %} -{% if s3 %} - @echo ' make s3_upload upload the web site via S3 ' -{% endif %} -{% if cloudfiles %} - @echo ' make cf_upload upload the web site via Cloud Files' -{% endif %} -{% if github %} - @echo ' make github upload the web site via gh-pages ' -{% endif %} - @echo ' ' - @echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html ' - @echo 'Set the RELATIVE variable to 1 to enable relative urls ' - @echo ' ' - -html: - "$(PELICAN)" "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) - -clean: - [ ! -d "$(OUTPUTDIR)" ] || rm -rf "$(OUTPUTDIR)" - -regenerate: - "$(PELICAN)" -r "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) - -serve: - "$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) - -serve-global: - "$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -b $(SERVER) - -devserver: - "$(PELICAN)" -lr "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) - -devserver-global: - "$(PELICAN)" -lr "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -b 0.0.0.0 - -publish: - "$(PELICAN)" "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(PUBLISHCONF)" $(PELICANOPTS) - -{% set upload = [] %} -{% if ssh %} -{% set upload = upload + ["ssh_upload"] %} -ssh_upload: publish - scp -P $(SSH_PORT) -r "$(OUTPUTDIR)"/* "$(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)" - -{% set upload = upload + ["sftp_upload"] %} -sftp_upload: publish - printf 'put -r $(OUTPUTDIR)/*' | sftp $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) - -{% set upload = upload + ["rsync_upload"] %} -rsync_upload: publish - rsync -e "ssh -p $(SSH_PORT)" -P -rvzc --include tags --cvs-exclude --delete "$(OUTPUTDIR)"/ "$(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)" - -{% endif %} -{% if dropbox %} -{% set upload = upload + ["dropbox_upload"] %} -dropbox_upload: publish - cp -r "$(OUTPUTDIR)"/* "$(DROPBOX_DIR)"/ - -{% endif %} -{% if ftp %} -{% set upload = upload + ["ftp_upload"] %} -ftp_upload: publish - lftp ftp://$(FTP_USER)@$(FTP_HOST) -e "mirror -R $(OUTPUTDIR) $(FTP_TARGET_DIR) ; quit" - -{% endif %} -{% if s3 %} -{% set upload = upload + ["s3_upload"] %} -s3_upload: publish - aws s3 sync "$(OUTPUTDIR)"/ s3://$(S3_BUCKET) --acl public-read --delete - -{% endif %} -{% if cloudfiles %} -{% set upload = upload + ["cf_upload"] %} -cf_upload: publish - cd "$(OUTPUTDIR)" && swift -v -A https://auth.api.rackspacecloud.com/v1.0 -U $(CLOUDFILES_USERNAME) -K $(CLOUDFILES_API_KEY) upload -c $(CLOUDFILES_CONTAINER) . - -{% endif %} -{% if github %} -{% set upload = upload + ["github"] %} -github: publish - ghp-import -m "$(GITHUB_PAGES_COMMIT_MESSAGE)" -b $(GITHUB_PAGES_BRANCH) "$(OUTPUTDIR)" --no-jekyll - git push origin $(GITHUB_PAGES_BRANCH) - -{% endif %} - -.PHONY: html help clean regenerate serve serve-global devserver devserver-global publish {{ upload|join(" ") }} diff --git a/pelican/tools/templates/pelicanconf.py.jinja2 b/pelican/tools/templates/pelicanconf.py.jinja2 deleted file mode 100644 index d2e92d4b..00000000 --- a/pelican/tools/templates/pelicanconf.py.jinja2 +++ /dev/null @@ -1,35 +0,0 @@ -AUTHOR = {{author}} -SITENAME = {{sitename}} -SITEURL = "" - -PATH = "content" - -TIMEZONE = {{timezone}} - -DEFAULT_LANG = {{lang}} - -# Feed generation is usually not desired when developing -FEED_ALL_ATOM = None -CATEGORY_FEED_ATOM = None -TRANSLATION_FEED_ATOM = None -AUTHOR_FEED_ATOM = None -AUTHOR_FEED_RSS = None - -# Blogroll -LINKS = ( - ("Pelican", "https://getpelican.com/"), - ("Python.org", "https://www.python.org/"), - ("Jinja2", "https://palletsprojects.com/p/jinja/"), - ("You can modify those links in your config file", "#"), -) - -# Social widget -SOCIAL = ( - ("You can add links in your config file", "#"), - ("Another social link", "#"), -) - -DEFAULT_PAGINATION = {{default_pagination}} - -# Uncomment following line if you want document-relative URLs when developing -# RELATIVE_URLS = True diff --git a/pelican/tools/templates/publishconf.py.jinja2 b/pelican/tools/templates/publishconf.py.jinja2 deleted file mode 100755 index 301e4dfa..00000000 --- a/pelican/tools/templates/publishconf.py.jinja2 +++ /dev/null @@ -1,22 +0,0 @@ -# This file is only used if you use `make publish` or -# explicitly specify it as your config file. - -import os -import sys - -sys.path.append(os.curdir) -from pelicanconf import * - -# If your site is available via HTTPS, make sure SITEURL begins with https:// -SITEURL = "{{siteurl}}" -RELATIVE_URLS = False - -FEED_ALL_ATOM = "feeds/all.atom.xml" -CATEGORY_FEED_ATOM = "feeds/{slug}.atom.xml" - -DELETE_OUTPUT_DIRECTORY = True - -# Following items are often useful when publishing - -# DISQUS_SITENAME = "" -# GOOGLE_ANALYTICS = "" diff --git a/pelican/tools/templates/tasks.py.jinja2 b/pelican/tools/templates/tasks.py.jinja2 deleted file mode 100644 index 26af6f0d..00000000 --- a/pelican/tools/templates/tasks.py.jinja2 +++ /dev/null @@ -1,193 +0,0 @@ -import os -import shlex -import shutil -import sys -{% if github %} -import datetime -{% endif %} - -from invoke import task -from invoke.main import program -{% if cloudfiles %} -from invoke.util import cd -{% endif %} -from pelican import main as pelican_main -from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer -from pelican.settings import DEFAULT_CONFIG, get_settings_from_file - -OPEN_BROWSER_ON_SERVE = True -SETTINGS_FILE_BASE = "pelicanconf.py" -SETTINGS = {} -SETTINGS.update(DEFAULT_CONFIG) -LOCAL_SETTINGS = get_settings_from_file(SETTINGS_FILE_BASE) -SETTINGS.update(LOCAL_SETTINGS) - -CONFIG = { - "settings_base": SETTINGS_FILE_BASE, - "settings_publish": "publishconf.py", - # Output path. Can be absolute or relative to tasks.py. Default: 'output' - "deploy_path": SETTINGS["OUTPUT_PATH"], -{% if ssh %} - # Remote server configuration - "ssh_user": "{{ssh_user}}", - "ssh_host": "{{ssh_host}}", - "ssh_port": "{{ssh_port}}", - "ssh_path": "{{ssh_target_dir}}", -{% endif %} -{% if cloudfiles %} - # Rackspace Cloud Files configuration settings - "cloudfiles_username": "{{cloudfiles_username}}", - "cloudfiles_api_key": "{{cloudfiles_api_key}}", - "cloudfiles_container": "{{cloudfiles_container}}", -{% endif %} -{% if github %} - # Github Pages configuration - "github_pages_branch": "{{github_pages_branch}}", - "commit_message": f"'Publish site on {datetime.date.today().isoformat()}'", -{% endif %} - # Host and port for `serve` - "host": "localhost", - "port": 8000, -} - - -@task -def clean(c): - """Remove generated files""" - if os.path.isdir(CONFIG["deploy_path"]): - shutil.rmtree(CONFIG["deploy_path"]) - os.makedirs(CONFIG["deploy_path"]) - - -@task -def build(c): - """Build local version of site""" - pelican_run("-s {settings_base}".format(**CONFIG)) - - -@task -def rebuild(c): - """`build` with the delete switch""" - pelican_run("-d -s {settings_base}".format(**CONFIG)) - - -@task -def regenerate(c): - """Automatically regenerate site upon file modification""" - pelican_run("-r -s {settings_base}".format(**CONFIG)) - - -@task -def serve(c): - """Serve site at http://$HOST:$PORT/ (default is localhost:8000)""" - - class AddressReuseTCPServer(RootedHTTPServer): - allow_reuse_address = True - - server = AddressReuseTCPServer( - CONFIG["deploy_path"], - (CONFIG["host"], CONFIG["port"]), - ComplexHTTPRequestHandler, - ) - - if OPEN_BROWSER_ON_SERVE: - # Open site in default browser - import webbrowser - - webbrowser.open("http://{host}:{port}".format(**CONFIG)) - - sys.stderr.write("Serving at {host}:{port} ...\n".format(**CONFIG)) - server.serve_forever() - - -@task -def reserve(c): - """`build`, then `serve`""" - build(c) - serve(c) - - -@task -def preview(c): - """Build production version of site""" - pelican_run("-s {settings_publish}".format(**CONFIG)) - -@task -def livereload(c): - """Automatically reload browser tab upon file modification.""" - from livereload import Server - - def cached_build(): - cmd = "-s {settings_base} -e CACHE_CONTENT=true LOAD_CONTENT_CACHE=true" - pelican_run(cmd.format(**CONFIG)) - - cached_build() - server = Server() - theme_path = SETTINGS["THEME"] - watched_globs = [ - CONFIG["settings_base"], - f"{theme_path}/templates/**/*.html", - ] - - content_file_extensions = [".md", ".rst"] - for extension in content_file_extensions: - content_glob = "{}/**/*{}".format(SETTINGS["PATH"], extension) - watched_globs.append(content_glob) - - static_file_extensions = [".css", ".js"] - for extension in static_file_extensions: - static_file_glob = f"{theme_path}/static/**/*{extension}" - watched_globs.append(static_file_glob) - - for glob in watched_globs: - server.watch(glob, cached_build) - - if OPEN_BROWSER_ON_SERVE: - # Open site in default browser - import webbrowser - - webbrowser.open("http://{host}:{port}".format(**CONFIG)) - - server.serve(host=CONFIG["host"], port=CONFIG["port"], root=CONFIG["deploy_path"]) - -{% if cloudfiles %} -@task -def cf_upload(c): - """Publish to Rackspace Cloud Files""" - rebuild(c) - with cd(CONFIG["deploy_path"]): - c.run( - "swift -v -A https://auth.api.rackspacecloud.com/v1.0 " - "-U {cloudfiles_username} " - "-K {cloudfiles_api_key} " - "upload -c {cloudfiles_container} .".format(**CONFIG) - ) -{% endif %} - -@task -def publish(c): - """Publish to production via rsync""" - pelican_run("-s {settings_publish}".format(**CONFIG)) - c.run( - 'rsync --delete --exclude ".DS_Store" -pthrvz -c ' - '-e "ssh -p {ssh_port}" ' - "{} {ssh_user}@{ssh_host}:{ssh_path}".format( - CONFIG["deploy_path"].rstrip("/") + "/", **CONFIG - ) - ) - -{% if github %} -@task -def gh_pages(c): - """Publish to GitHub Pages""" - preview(c) - c.run( - "ghp-import -b {github_pages_branch} " - "-m {commit_message} " - "{deploy_path} -p".format(**CONFIG) - ) -{% endif %} - -def pelican_run(cmd): - cmd += " " + program.core.remainder # allows to pass-through args to pelican - pelican_main(shlex.split(cmd)) diff --git a/pelican/urlwrappers.py b/pelican/urlwrappers.py deleted file mode 100644 index 8023613c..00000000 --- a/pelican/urlwrappers.py +++ /dev/null @@ -1,140 +0,0 @@ -import functools -import logging -import os -import pathlib - -from pelican.utils import slugify - -logger = logging.getLogger(__name__) - - -@functools.total_ordering -class URLWrapper: - def __init__(self, name, settings): - self.settings = settings - self._name = name - self._slug = None - self._slug_from_name = True - - @property - def name(self): - return self._name - - @name.setter - def name(self, name): - self._name = name - # if slug wasn't explicitly set, it needs to be regenerated from name - # so, changing name should reset slug for slugification - if self._slug_from_name: - self._slug = None - - @property - def slug(self): - if self._slug is None: - class_key = f"{self.__class__.__name__.upper()}_REGEX_SUBSTITUTIONS" - regex_subs = self.settings.get( - class_key, self.settings.get("SLUG_REGEX_SUBSTITUTIONS", []) - ) - preserve_case = self.settings.get("SLUGIFY_PRESERVE_CASE", False) - self._slug = slugify( - self.name, - regex_subs=regex_subs, - preserve_case=preserve_case, - use_unicode=self.settings.get("SLUGIFY_USE_UNICODE", False), - ) - return self._slug - - @slug.setter - def slug(self, slug): - # if slug is expliticly set, changing name won't alter slug - self._slug_from_name = False - self._slug = slug - - def as_dict(self): - d = self.__dict__ - d["name"] = self.name - d["slug"] = self.slug - return d - - def __hash__(self): - return hash(self.slug) - - def _normalize_key(self, key): - class_key = f"{self.__class__.__name__.upper()}_REGEX_SUBSTITUTIONS" - regex_subs = self.settings.get( - class_key, self.settings.get("SLUG_REGEX_SUBSTITUTIONS", []) - ) - use_unicode = self.settings.get("SLUGIFY_USE_UNICODE", False) - preserve_case = self.settings.get("SLUGIFY_PRESERVE_CASE", False) - return slugify( - key, - regex_subs=regex_subs, - preserve_case=preserve_case, - use_unicode=use_unicode, - ) - - def __eq__(self, other): - if isinstance(other, self.__class__): - return self.slug == other.slug - if isinstance(other, str): - return self.slug == self._normalize_key(other) - return False - - def __ne__(self, other): - if isinstance(other, self.__class__): - return self.slug != other.slug - if isinstance(other, str): - return self.slug != self._normalize_key(other) - return True - - def __lt__(self, other): - if isinstance(other, self.__class__): - return self.slug < other.slug - if isinstance(other, str): - return self.slug < self._normalize_key(other) - return False - - def __str__(self): - return self.name - - def __repr__(self): - return f"<{type(self).__name__} {self._name!r}>" - - def _from_settings(self, key, get_page_name=False): - """Returns URL information as defined in settings. - - When get_page_name=True returns URL without anything after {slug} e.g. - if in settings: CATEGORY_URL="cat/{slug}.html" this returns - "cat/{slug}" Useful for pagination. - - """ - setting = f"{self.__class__.__name__.upper()}_{key}" - value = self.settings[setting] - if isinstance(value, pathlib.Path): - value = str(value) - if not isinstance(value, str): - logger.warning("%s is set to %s", setting, value) - return value - elif get_page_name: - return os.path.splitext(value)[0].format(**self.as_dict()) - else: - return value.format(**self.as_dict()) - - page_name = property( - functools.partial(_from_settings, key="URL", get_page_name=True) - ) - url = property(functools.partial(_from_settings, key="URL")) - save_as = property(functools.partial(_from_settings, key="SAVE_AS")) - - -class Category(URLWrapper): - pass - - -class Tag(URLWrapper): - def __init__(self, name, *args, **kwargs): - super().__init__(name.strip(), *args, **kwargs) - - -class Author(URLWrapper): - pass diff --git a/pelican/utils.py b/pelican/utils.py deleted file mode 100644 index 69d9dde5..00000000 --- a/pelican/utils.py +++ /dev/null @@ -1,954 +0,0 @@ -from __future__ import annotations - -import datetime -import fnmatch -import locale -import logging -import os -import pathlib -import re -import shutil -import sys -import traceback -import urllib -from collections.abc import Hashable -from contextlib import contextmanager -from functools import partial -from html import entities -from html.parser import HTMLParser -from itertools import groupby -from operator import attrgetter -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Collection, - Generator, - Iterable, - Sequence, -) - -import dateutil.parser -from watchfiles import Change - -try: - from zoneinfo import ZoneInfo -except ModuleNotFoundError: - from backports.zoneinfo import ZoneInfo -import watchfiles -from markupsafe import Markup - -if TYPE_CHECKING: - from pelican.contents import Content - from pelican.settings import Settings - -logger = logging.getLogger(__name__) - - -def sanitised_join(base_directory: str, *parts: str) -> str: - joined = posixize_path(os.path.abspath(os.path.join(base_directory, *parts))) - base = posixize_path(os.path.abspath(base_directory)) - if not joined.startswith(base): - raise RuntimeError(f"Attempted to break out of output directory to {joined}") - - return joined - - -def strftime(date: datetime.datetime, date_format: str) -> str: - """ - Enhanced replacement for built-in strftime with zero stripping - - This works by 'grabbing' possible format strings (those starting with %), - formatting them with the date, stripping any leading zeros if - prefix is - used and replacing formatted output back. - """ - - def strip_zeros(x): - return x.lstrip("0") or "0" - - # includes ISO date parameters added by Python 3.6 - c89_directives = "aAbBcdfGHIjmMpSUuVwWxXyYzZ%" - - # grab candidate format options - format_options = "%[-]?." - candidates = re.findall(format_options, date_format) - - # replace candidates with placeholders for later % formatting - template = re.sub(format_options, "%s", date_format) - - formatted_candidates = [] - for candidate in candidates: - # test for valid C89 directives only - if candidate[-1] in c89_directives: - # check for '-' prefix - if len(candidate) == 3: # noqa: PLR2004 - # '-' prefix - candidate = f"%{candidate[-1]}" - conversion = strip_zeros - else: - conversion = None - - # format date - if isinstance(date, SafeDatetime): - formatted = date.strftime(candidate, safe=False) - else: - formatted = date.strftime(candidate) - - # strip zeros if '-' prefix is used - if conversion: - formatted = conversion(formatted) - else: - formatted = candidate - formatted_candidates.append(formatted) - - # put formatted candidates back and return - return template % tuple(formatted_candidates) - - -class SafeDatetime(datetime.datetime): - """Subclass of datetime that works with utf-8 format strings on PY2""" - - def strftime(self, fmt, safe=True): - """Uses our custom strftime if supposed to be *safe*""" - if safe: - return strftime(self, fmt) - else: - return super().strftime(fmt) - - -class DateFormatter: - """A date formatter object used as a jinja filter - - Uses the `strftime` implementation and makes sure jinja uses the locale - defined in LOCALE setting - """ - - def __init__(self) -> None: - self.locale = locale.setlocale(locale.LC_TIME) - # python has issue with Turkish_Türkiye.1254 locale, replace it to - # something accepted: Turkish - if self.locale == "Turkish_Türkiye.1254": - self.locale = "Turkish" - - def __call__(self, date: datetime.datetime, date_format: str) -> str: - # on OSX, encoding from LC_CTYPE determines the unicode output in PY3 - # make sure it's same as LC_TIME - with temporary_locale(self.locale, locale.LC_TIME), temporary_locale( - self.locale, locale.LC_CTYPE - ): - formatted = strftime(date, date_format) - - return formatted - - -class memoized: - """Function decorator to cache return values. - - If called later with the same arguments, the cached value is returned - (not reevaluated). - - """ - - def __init__(self, func: Callable) -> None: - self.func = func - self.cache: dict[Any, Any] = {} - - def __call__(self, *args) -> Any: - if not isinstance(args, Hashable): - # uncacheable. a list, for instance. - # better to not cache than blow up. - return self.func(*args) - if args in self.cache: - return self.cache[args] - else: - value = self.func(*args) - self.cache[args] = value - return value - - def __repr__(self) -> str | None: - return self.func.__doc__ - - def __get__(self, obj: Any, objtype): - """Support instance methods.""" - fn = partial(self.__call__, obj) - fn.cache = self.cache - return fn - - -def deprecated_attribute( - old: str, - new: str, - since: tuple[int, ...], - remove: tuple[int, ...] | None = None, - doc: str | None = None, -): - """Attribute deprecation decorator for gentle upgrades - - For example: - - class MyClass (object): - @deprecated_attribute( - old='abc', new='xyz', since=(3, 2, 0), remove=(4, 1, 3)) - def abc(): return None - - def __init__(self): - xyz = 5 - - Note that the decorator needs a dummy method to attach to, but the - content of the dummy method is ignored. - """ - - def _warn(): - version = ".".join(str(x) for x in since) - message = [f"{old} has been deprecated since {version}"] - if remove: - version = ".".join(str(x) for x in remove) - message.append(f" and will be removed by version {version}") - message.append(f". Use {new} instead.") - logger.warning("".join(message)) - logger.debug("".join(str(x) for x in traceback.format_stack())) - - def fget(self): - _warn() - return getattr(self, new) - - def fset(self, value): - _warn() - setattr(self, new, value) - - def decorator(dummy): - return property(fget=fget, fset=fset, doc=doc) - - return decorator - - -def get_date(string: str) -> datetime.datetime: - """Return a datetime object from a string. - - If no format matches the given date, raise a ValueError. - """ - string = re.sub(" +", " ", string) - default = SafeDatetime.now().replace(hour=0, minute=0, second=0, microsecond=0) - try: - return dateutil.parser.parse(string, default=default) - except (TypeError, ValueError): - raise ValueError(f"{string!r} is not a valid date") from None - - -@contextmanager -def pelican_open( - filename: str, mode: str = "r", strip_crs: bool = (sys.platform == "win32") -) -> Generator[str, None, None]: - """Open a file and return its content""" - - # utf-8-sig will clear any BOM if present - with open(filename, mode, encoding="utf-8-sig") as infile: - content = infile.read() - yield content - - -def slugify( - value: str, - regex_subs: Iterable[tuple[str, str]] = (), - preserve_case: bool = False, - use_unicode: bool = False, -) -> str: - """ - Normalizes string, converts to lowercase, removes non-alpha characters, - and converts spaces to hyphens. - - Took from Django sources. - - For a set of sensible default regex substitutions to pass to regex_subs - look into pelican.settings.DEFAULT_CONFIG['SLUG_REGEX_SUBSTITUTIONS']. - """ - - import unicodedata - - import unidecode - - def normalize_unicode(text: str) -> str: - # normalize text by compatibility composition - # see: https://en.wikipedia.org/wiki/Unicode_equivalence - return unicodedata.normalize("NFKC", text) - - # strip tags from value - value = Markup(value).striptags() - - # normalization - value = normalize_unicode(value) - - if not use_unicode: - # ASCII-fy - value = unidecode.unidecode(value) - - # perform regex substitutions - for src, dst in regex_subs: - value = re.sub( - normalize_unicode(src), normalize_unicode(dst), value, flags=re.IGNORECASE - ) - - if not preserve_case: - value = value.lower() - - return value.strip() - - -def copy(source: str, destination: str, ignores: Iterable[str] | None = None) -> None: - """Recursively copy source into destination. - - If source is a file, destination has to be a file as well. - The function is able to copy either files or directories. - - :param source: the source file or directory - :param destination: the destination file or directory - :param ignores: either None, or a list of glob patterns; - files matching those patterns will _not_ be copied. - """ - - def walk_error(err): - logger.warning("While copying %s: %s: %s", source_, err.filename, err.strerror) - - source_ = os.path.abspath(os.path.expanduser(source)) - destination_ = os.path.abspath(os.path.expanduser(destination)) - - if ignores is None: - ignores = [] - - if any(fnmatch.fnmatch(os.path.basename(source), ignore) for ignore in ignores): - logger.info("Not copying %s due to ignores", source_) - return - - if os.path.isfile(source_): - dst_dir = os.path.dirname(destination_) - if not os.path.exists(dst_dir): - logger.info("Creating directory %s", dst_dir) - os.makedirs(dst_dir) - logger.info("Copying %s to %s", source_, destination_) - copy_file(source_, destination_) - - elif os.path.isdir(source_): - if not os.path.exists(destination_): - logger.info("Creating directory %s", destination_) - os.makedirs(destination_) - if not os.path.isdir(destination_): - logger.warning( - "Cannot copy %s (a directory) to %s (a file)", source_, destination_ - ) - return - - for src_dir, subdirs, others in os.walk(source_, followlinks=True): - dst_dir = os.path.join(destination_, os.path.relpath(src_dir, source_)) - - subdirs[:] = ( - s for s in subdirs if not any(fnmatch.fnmatch(s, i) for i in ignores) - ) - others[:] = ( - o for o in others if not any(fnmatch.fnmatch(o, i) for i in ignores) - ) - - if not os.path.isdir(dst_dir): - logger.info("Creating directory %s", dst_dir) - # Parent directories are known to exist, so 'mkdir' suffices. - os.mkdir(dst_dir) - - for o in others: - src_path = os.path.join(src_dir, o) - dst_path = os.path.join(dst_dir, o) - if os.path.isfile(src_path): - logger.info("Copying %s to %s", src_path, dst_path) - copy_file(src_path, dst_path) - else: - logger.warning( - "Skipped copy %s (not a file or directory) to %s", - src_path, - dst_path, - ) - - -def copy_file(source: str, destination: str) -> None: - """Copy a file""" - try: - shutil.copyfile(source, destination) - except OSError as e: - logger.warning( - "A problem occurred copying file %s to %s; %s", source, destination, e - ) - - -def clean_output_dir(path: str, retention: Iterable[str]) -> None: - """Remove all files from output directory except those in retention list""" - - if not os.path.exists(path): - logger.debug("Directory already removed: %s", path) - return - - if not os.path.isdir(path): - try: - os.remove(path) - except Exception as e: - logger.error("Unable to delete file %s; %s", path, e) - return - - # remove existing content from output folder unless in retention list - for filename in os.listdir(path): - file = os.path.join(path, filename) - if any(filename == retain for retain in retention): - logger.debug( - "Skipping deletion; %s is on retention list: %s", filename, file - ) - elif os.path.isdir(file): - try: - shutil.rmtree(file) - logger.debug("Deleted directory %s", file) - except Exception as e: - logger.error("Unable to delete directory %s; %s", file, e) - elif os.path.isfile(file) or os.path.islink(file): - try: - os.remove(file) - logger.debug("Deleted file/link %s", file) - except Exception as e: - logger.error("Unable to delete file %s; %s", file, e) - else: - logger.error("Unable to delete %s, file type unknown", file) - - -def get_relative_path(path: str) -> str: - """Return the relative path from the given path to the root path.""" - components = split_all(path) - if components is None or len(components) <= 1: - return os.curdir - else: - parents = [os.pardir] * (len(components) - 1) - return os.path.join(*parents) - - -def path_to_url(path: str) -> str: - """Return the URL corresponding to a given path.""" - if path is not None: - path = posixize_path(path) - return path - - -def posixize_path(rel_path: str) -> str: - """Use '/' as path separator, so that source references, - like '{static}/foo/bar.jpg' or 'extras/favicon.ico', - will work on Windows as well as on Mac and Linux.""" - return rel_path.replace(os.sep, "/") - - -class _HTMLWordTruncator(HTMLParser): - _word_regex = re.compile( - r"{DBC}|(\w[\w'-]*)".format( - # DBC means CJK-like characters. An character can stand for a word. - DBC=( - "([\u4e00-\u9fff])|" # CJK Unified Ideographs - "([\u3400-\u4dbf])|" # CJK Unified Ideographs Extension A - "([\uf900-\ufaff])|" # CJK Compatibility Ideographs - "([\U00020000-\U0002a6df])|" # CJK Unified Ideographs Extension B - "([\U0002f800-\U0002fa1f])|" # CJK Compatibility Ideographs Supplement - "([\u3040-\u30ff])|" # Hiragana and Katakana - "([\u1100-\u11ff])|" # Hangul Jamo - "([\uac00-\ud7ff])|" # Hangul Compatibility Jamo - "([\u3130-\u318f])" # Hangul Syllables - ) - ), - re.UNICODE, - ) - _word_prefix_regex = re.compile(r"\w", re.U) - _singlets = ("br", "col", "link", "base", "img", "param", "area", "hr", "input") - - class TruncationCompleted(Exception): - def __init__(self, truncate_at: int) -> None: - super().__init__(truncate_at) - self.truncate_at = truncate_at - - def __init__(self, max_words: int) -> None: - super().__init__(convert_charrefs=False) - - self.max_words = max_words - self.words_found = 0 - self.open_tags = [] - self.last_word_end = None - self.truncate_at: int | None = None - - def feed(self, *args, **kwargs) -> None: - try: - super().feed(*args, **kwargs) - except self.TruncationCompleted as exc: - self.truncate_at = exc.truncate_at - else: - self.truncate_at = None - - def getoffset(self) -> int: - line_start = 0 - lineno, line_offset = self.getpos() - for _ in range(lineno - 1): - line_start = self.rawdata.index("\n", line_start) + 1 - return line_start + line_offset - - def add_word(self, word_end: int) -> None: - self.words_found += 1 - self.last_word_end = None - if self.words_found == self.max_words: - raise self.TruncationCompleted(word_end) - - def add_last_word(self) -> None: - if self.last_word_end is not None: - self.add_word(self.last_word_end) - - def handle_starttag(self, tag: str, attrs: Any) -> None: - self.add_last_word() - if tag not in self._singlets: - self.open_tags.insert(0, tag) - - def handle_endtag(self, tag: str) -> None: - self.add_last_word() - try: - i = self.open_tags.index(tag) - except ValueError: - pass - else: - # SGML: An end tag closes, back to the matching start tag, - # all unclosed intervening start tags with omitted end tags - del self.open_tags[: i + 1] - - def handle_data(self, data: str) -> None: - word_end = 0 - offset = self.getoffset() - - while self.words_found < self.max_words: - match = self._word_regex.search(data, word_end) - if not match: - break - - if match.start(0) > 0: - self.add_last_word() - - word_end = match.end(0) - self.last_word_end = offset + word_end - - if word_end < len(data): - self.add_last_word() - - def _handle_ref(self, name: str, char: str) -> None: - """ - Called by handle_entityref() or handle_charref() when a ref like - `—`, `—`, or `—` is found. - - The arguments for this method are: - - - `name`: the HTML entity name (such as `mdash` or `#8212` or `#x2014`) - - `char`: the Unicode representation of the ref (such as `—`) - - This method checks whether the entity is considered to be part of a - word or not and, if not, signals the end of a word. - """ - # Compute the index of the character right after the ref. - # - # In a string like 'prefix—suffix', the end is the sum of: - # - # - `self.getoffset()` (the length of `prefix`) - # - `1` (the length of `&`) - # - `len(name)` (the length of `mdash`) - # - `1` (the length of `;`) - # - # Note that, in case of malformed HTML, the ';' character may - # not be present. - - offset = self.getoffset() - ref_end = offset + len(name) + 1 - - try: - if self.rawdata[ref_end] == ";": - ref_end += 1 - except IndexError: - # We are at the end of the string and there's no ';' - pass - - if self.last_word_end is None: - if self._word_prefix_regex.match(char): - self.last_word_end = ref_end - elif self._word_regex.match(char): - self.last_word_end = ref_end - else: - self.add_last_word() - - def handle_entityref(self, name: str) -> None: - """ - Called when an entity ref like '—' is found - - `name` is the entity ref without ampersand and semicolon (e.g. `mdash`) - """ - try: - codepoint = entities.name2codepoint[name] - char = chr(codepoint) - except KeyError: - char = "" - self._handle_ref(name, char) - - def handle_charref(self, name: str) -> None: - """ - Called when a char ref like '—' or '—' is found - - `name` is the char ref without ampersand and semicolon (e.g. `#8212` or - `#x2014`) - """ - try: - if name.startswith("x"): - codepoint = int(name[1:], 16) - else: - codepoint = int(name) - char = chr(codepoint) - except (ValueError, OverflowError): - char = "" - self._handle_ref("#" + name, char) - - -def truncate_html_words(s: str, num: int, end_text: str = "…") -> str: - """Truncates HTML to a certain number of words. - - (not counting tags and comments). Closes opened tags if they were correctly - closed in the given html. Takes an optional argument of what should be used - to notify that the string has been truncated, defaulting to ellipsis (…). - - Newlines in the HTML are preserved. (From the django framework). - """ - length = int(num) - if length <= 0: - return "" - truncator = _HTMLWordTruncator(length) - truncator.feed(s) - if truncator.truncate_at is None: - return s - out = s[: truncator.truncate_at] - if end_text: - out += " " + end_text - # Close any tags still open - for tag in truncator.open_tags: - out += f"" - # Return string - return out - - -def truncate_html_paragraphs(s, count): - """Truncate HTML to a certain number of paragraphs. - - :param count: number of paragraphs to keep - - Newlines in the HTML are preserved. - """ - paragraphs = [] - tag_stop = 0 - substr = s[:] - for _ in range(count): - substr = substr[tag_stop:] - tag_start = substr.find("

      ") - tag_stop = substr.find("

      ") + len("

      ") - paragraphs.append(substr[tag_start:tag_stop]) - - return "".join(paragraphs) - - -def process_translations( - content_list: list[Content], - translation_id: str | Collection[str] | None = None, -) -> tuple[list[Content], list[Content]]: - """Finds translations and returns them. - - For each content_list item, populates the 'translations' attribute, and - returns a tuple with two lists (index, translations). Index list includes - items in default language or items which have no variant in default - language. Items with the `translation` metadata set to something else than - `False` or `false` will be used as translations, unless all the items in - the same group have that metadata. - - Translations and original items are determined relative to one another - amongst items in the same group. Items are in the same group if they - have the same value(s) for the metadata attribute(s) specified by the - 'translation_id', which must be a string or a collection of strings. - If 'translation_id' is falsy, the identification of translations is skipped - and all items are returned as originals. - """ - - if not translation_id: - return content_list, [] - - if isinstance(translation_id, str): - translation_id = {translation_id} - - index = [] - - try: - content_list.sort(key=attrgetter(*translation_id)) - except TypeError: - raise TypeError( - f"Cannot unpack {translation_id}, 'translation_id' must be falsy, a" - " string or a collection of strings" - ) from None - except AttributeError: - raise AttributeError( - f"Cannot use {translation_id} as 'translation_id', there " - "appear to be items without these metadata " - "attributes" - ) from None - - for id_vals, items in groupby(content_list, attrgetter(*translation_id)): - # prepare warning string - id_vals = (id_vals,) if len(translation_id) == 1 else id_vals - with_str = "with" + ", ".join([' {} "{{}}"'] * len(translation_id)).format( - *translation_id - ).format(*id_vals) - - items = list(items) - original_items = get_original_items(items, with_str) - index.extend(original_items) - for a in items: - a.translations = [x for x in items if x != a] - - translations = [x for x in content_list if x not in index] - - return index, translations - - -def get_original_items(items: list[Content], with_str: str) -> list[Content]: - def _warn_source_paths(msg, items, *extra): - args = [len(items)] - args.extend(extra) - args.extend(x.source_path for x in items) - logger.warning("{}: {}".format(msg, "\n%s" * len(items)), *args) - - # warn if several items have the same lang - for lang, lang_items in groupby(items, attrgetter("lang")): - lang_items = list(lang_items) - if len(lang_items) > 1: - _warn_source_paths( - 'There are %s items "%s" with lang %s', lang_items, with_str, lang - ) - - # items with `translation` metadata will be used as translations... - candidate_items = [ - i for i in items if i.metadata.get("translation", "false").lower() == "false" - ] - - # ...unless all items with that slug are translations - if not candidate_items: - _warn_source_paths('All items ("%s") "%s" are translations', items, with_str) - candidate_items = items - - # find items with default language - original_items = [i for i in candidate_items if i.in_default_lang] - - # if there is no article with default language, go back one step - if not original_items: - original_items = candidate_items - - # warn if there are several original items - if len(original_items) > 1: - _warn_source_paths( - "There are %s original (not translated) items %s", original_items, with_str - ) - return original_items - - -def order_content( - content_list: list[Content], - order_by: str | Callable[[Content], Any] | None = "slug", -) -> list[Content]: - """Sorts content. - - order_by can be a string of an attribute or sorting function. If order_by - is defined, content will be ordered by that attribute or sorting function. - By default, content is ordered by slug. - - Different content types can have default order_by attributes defined - in settings, e.g. PAGES_ORDER_BY='sort-order', in which case `sort-order` - should be a defined metadata attribute in each page. - """ - - if order_by: - if callable(order_by): - try: - content_list.sort(key=order_by) - except Exception: - logger.error("Error sorting with function %s", order_by) - elif isinstance(order_by, str): - if order_by.startswith("reversed-"): - order_reversed = True - order_by = order_by.replace("reversed-", "", 1) - else: - order_reversed = False - - if order_by == "basename": - content_list.sort( - key=lambda x: os.path.basename(x.source_path or ""), - reverse=order_reversed, - ) - else: - try: - content_list.sort(key=attrgetter(order_by), reverse=order_reversed) - except AttributeError: - for content in content_list: - try: - getattr(content, order_by) - except AttributeError: - logger.warning( - 'There is no "%s" attribute in "%s". ' - "Defaulting to slug order.", - order_by, - content.get_relative_source_path(), - extra={ - "limit_msg": ( - "More files are missing " - "the needed attribute." - ) - }, - ) - else: - logger.warning( - "Invalid *_ORDER_BY setting (%s). " - "Valid options are strings and functions.", - order_by, - ) - - return content_list - - -def wait_for_changes( - settings_file: str, - settings: Settings, -) -> set[tuple[Change, str]]: - content_path = settings.get("PATH", "") - theme_path = settings.get("THEME", "") - ignore_files = { - fnmatch.translate(pattern) for pattern in settings.get("IGNORE_FILES", []) - } - - candidate_paths = [ - settings_file, - theme_path, - content_path, - ] - - candidate_paths.extend( - os.path.join(content_path, path) for path in settings.get("STATIC_PATHS", []) - ) - - watching_paths = [] - for path in candidate_paths: - if not path: - continue - path = os.path.abspath(path) - if not os.path.exists(path): - logger.warning("Unable to watch path '%s' as it does not exist.", path) - else: - watching_paths.append(path) - - return next( - watchfiles.watch( - *watching_paths, - watch_filter=watchfiles.DefaultFilter(ignore_entity_patterns=ignore_files), # type: ignore - rust_timeout=0, - ) - ) - - -def set_date_tzinfo( - d: datetime.datetime, tz_name: str | None = None -) -> datetime.datetime: - """Set the timezone for dates that don't have tzinfo""" - if tz_name and not d.tzinfo: - timezone = ZoneInfo(tz_name) - d = d.replace(tzinfo=timezone) - return SafeDatetime( - d.year, d.month, d.day, d.hour, d.minute, d.second, d.microsecond, d.tzinfo - ) - return d - - -def mkdir_p(path: str) -> None: - os.makedirs(path, exist_ok=True) - - -def split_all(path: str | pathlib.Path | None) -> Sequence[str] | None: - """Split a path into a list of components - - While os.path.split() splits a single component off the back of - `path`, this function splits all components: - - >>> split_all(os.path.join('a', 'b', 'c')) - ['a', 'b', 'c'] - """ - if isinstance(path, str): - components = [] - path = path.lstrip("/") - while path: - head, tail = os.path.split(path) - if tail: - components.insert(0, tail) - elif head == path: - components.insert(0, head) - break - path = head - return components - elif isinstance(path, pathlib.Path): - return path.parts - elif path is None: - return None - else: - raise TypeError( - f'"path" was {type(path)}, must be string, None, or pathlib.Path' - ) - - -def path_to_file_url(path: str) -> str: - """Convert file-system path to file:// URL""" - return urllib.parse.urljoin("file://", urllib.request.pathname2url(path)) - - -def maybe_pluralize(count: int, singular: str, plural: str) -> str: - """ - Returns a formatted string containing count and plural if count is not 1 - Returns count and singular if count is 1 - - maybe_pluralize(0, 'Article', 'Articles') -> '0 Articles' - maybe_pluralize(1, 'Article', 'Articles') -> '1 Article' - maybe_pluralize(2, 'Article', 'Articles') -> '2 Articles' - - """ - selection = plural - if count == 1: - selection = singular - return f"{count} {selection}" - - -@contextmanager -def temporary_locale( - temp_locale: str | None = None, lc_category: int = locale.LC_ALL -) -> Generator[None, None, None]: - """ - Enable code to run in a context with a temporary locale - Resets the locale back when exiting context. - - Use tests.support.TestCaseWithCLocale if you want every unit test in a - class to use the C locale. - """ - orig_locale = locale.setlocale(lc_category) - # python has issue with Turkish_Türkiye.1254 locale, replace it to - # something accepted: Turkish - if orig_locale == "Turkish_Türkiye.1254": - orig_locale = "Turkish" - if temp_locale: - locale.setlocale(lc_category, temp_locale) - yield - locale.setlocale(lc_category, orig_locale) - - -def file_suffix(path: str) -> str: - """Return the suffix of a filename in a path.""" - _, ext = os.path.splitext(os.path.basename(path)) - ret = "" - if len(ext) > 1: - # drop the ".", e.g., "exe", not ".exe" - ret = ext[1:] - return ret diff --git a/pelican/writers.py b/pelican/writers.py deleted file mode 100644 index 1a2cf7b0..00000000 --- a/pelican/writers.py +++ /dev/null @@ -1,295 +0,0 @@ -import logging -import os -from posixpath import join as posix_join -from urllib.parse import urljoin - -from feedgenerator import Atom1Feed, Rss201rev2Feed, get_tag_uri -from markupsafe import Markup - -from pelican.paginator import Paginator -from pelican.plugins import signals -from pelican.utils import ( - get_relative_path, - path_to_url, - sanitised_join, - set_date_tzinfo, -) - -logger = logging.getLogger(__name__) - - -class Writer: - def __init__(self, output_path, settings=None): - self.output_path = output_path - self.reminder = {} - self.settings = settings or {} - self._written_files = set() - self._overridden_files = set() - - # See Content._link_replacer for details - if self.settings.get("RELATIVE_URLS"): - self.urljoiner = posix_join - else: - self.urljoiner = lambda base, url: urljoin( - base if base.endswith("/") else base + "/", str(url) - ) - - def _create_new_feed(self, feed_type, feed_title, context): - feed_class = Rss201rev2Feed if feed_type == "rss" else Atom1Feed - if feed_title: - feed_title = context["SITENAME"] + " - " + feed_title - else: - feed_title = context["SITENAME"] - return feed_class( - title=Markup(feed_title).striptags(), - link=(self.site_url + "/"), - feed_url=self.feed_url, - description=context.get("SITESUBTITLE", ""), - subtitle=context.get("SITESUBTITLE", None), - ) - - def _add_item_to_the_feed(self, feed, item): - title = Markup(item.title).striptags() - link = self.urljoiner(self.site_url, item.url) - - if self.settings["FEED_APPEND_REF"]: - link = link + "?ref=feed" - - if isinstance(feed, Rss201rev2Feed): - # RSS feeds use a single tag called 'description' for both the full - # content and the summary - content = None - if self.settings.get("RSS_FEED_SUMMARY_ONLY"): - description = item.summary - else: - description = item.get_content(self.site_url) - - else: - # Atom feeds have two different tags for full content (called - # 'content' by feedgenerator) and summary (called 'description' by - # feedgenerator). - # - # It does not make sense to have the summary be the - # exact same thing as the full content. If we detect that - # they are we just remove the summary. - content = item.get_content(self.site_url) - description = item.summary - if description == content: - description = None - - categories = [] - if hasattr(item, "category"): - categories.append(item.category) - if hasattr(item, "tags"): - categories.extend(item.tags) - - feed.add_item( - title=title, - link=link, - unique_id=get_tag_uri(link, item.date), - description=description, - content=content, - categories=categories or None, - author_name=getattr(item, "author", ""), - pubdate=set_date_tzinfo(item.date, self.settings.get("TIMEZONE", None)), - updateddate=set_date_tzinfo( - item.modified, self.settings.get("TIMEZONE", None) - ) - if hasattr(item, "modified") - else None, - ) - - def _open_w(self, filename, encoding, override=False): - """Open a file to write some content to it. - - Exit if we have already written to that file, unless one (and no more - than one) of the writes has the override parameter set to True. - """ - if filename in self._overridden_files: - if override: - raise RuntimeError(f"File {filename} is set to be overridden twice") - logger.info("Skipping %s", filename) - filename = os.devnull - elif filename in self._written_files: - if override: - logger.info("Overwriting %s", filename) - else: - raise RuntimeError(f"File {filename} is to be overwritten") - if override: - self._overridden_files.add(filename) - self._written_files.add(filename) - return open(filename, "w", encoding=encoding) - - def write_feed( - self, - elements, - context, - path=None, - url=None, - feed_type="atom", - override_output=False, - feed_title=None, - ): - """Generate a feed with the list of articles provided - - Return the feed. If no path or output_path is specified, just - return the feed object. - - :param elements: the articles to put on the feed. - :param context: the context to get the feed metadata. - :param path: the path to output. - :param url: the publicly visible feed URL; if None, path is used - instead - :param feed_type: the feed type to use (atom or rss) - :param override_output: boolean telling if we can override previous - output with the same name (and if next files written with the same - name should be skipped to keep that one) - :param feed_title: the title of the feed.o - """ - self.site_url = context.get("SITEURL", path_to_url(get_relative_path(path))) - - self.feed_domain = context.get("FEED_DOMAIN") - self.feed_url = self.urljoiner(self.feed_domain, url or path) - - feed = self._create_new_feed(feed_type, feed_title, context) - - # FEED_MAX_ITEMS = None means [:None] to get every element - for element in elements[: self.settings["FEED_MAX_ITEMS"]]: - self._add_item_to_the_feed(feed, element) - - signals.feed_generated.send(context, feed=feed) - if path: - complete_path = sanitised_join(self.output_path, path) - - try: - os.makedirs(os.path.dirname(complete_path)) - except Exception: - pass - - with self._open_w(complete_path, "utf-8", override_output) as fp: - feed.write(fp, "utf-8") - logger.info("Writing %s", complete_path) - - signals.feed_written.send(complete_path, context=context, feed=feed) - return feed - - def write_file( - self, - name, - template, - context, - relative_urls=False, - paginated=None, - template_name=None, - override_output=False, - url=None, - **kwargs, - ): - """Render the template and write the file. - - :param name: name of the file to output - :param template: template to use to generate the content - :param context: dict to pass to the templates. - :param relative_urls: use relative urls or absolutes ones - :param paginated: dict of article list to paginate - must have the - same length (same list in different orders) - :param template_name: the template name, for pagination - :param override_output: boolean telling if we can override previous - output with the same name (and if next files written with the same - name should be skipped to keep that one) - :param url: url of the file (needed by the paginator) - :param **kwargs: additional variables to pass to the templates - """ - - if name is False or name == "": - return - elif not name: - # other stuff, just return for now - return - - def _write_file(template, localcontext, output_path, name, override): - """Render the template write the file.""" - # set localsiteurl for context so that Contents can adjust links - if localcontext["localsiteurl"]: - context["localsiteurl"] = localcontext["localsiteurl"] - output = template.render(localcontext) - path = sanitised_join(output_path, name) - - try: - os.makedirs(os.path.dirname(path)) - except Exception: - pass - - with self._open_w(path, "utf-8", override=override) as f: - f.write(output) - logger.info("Writing %s", path) - - # Send a signal to say we're writing a file with some specific - # local context. - signals.content_written.send(path, context=localcontext) - - def _get_localcontext(context, name, kwargs, relative_urls): - localcontext = context.copy() - localcontext["localsiteurl"] = localcontext.get("localsiteurl", None) - if relative_urls: - relative_url = path_to_url(get_relative_path(name)) - localcontext["SITEURL"] = relative_url - localcontext["localsiteurl"] = relative_url - localcontext["output_file"] = name - localcontext.update(kwargs) - return localcontext - - if paginated is None: - paginated = { - key: val for key, val in kwargs.items() if key in {"articles", "dates"} - } - - # pagination - if paginated and template_name in self.settings["PAGINATED_TEMPLATES"]: - # pagination needed - per_page = ( - self.settings["PAGINATED_TEMPLATES"][template_name] - or self.settings["DEFAULT_PAGINATION"] - ) - - # init paginators - paginators = { - key: Paginator(name, url, val, self.settings, per_page) - for key, val in paginated.items() - } - - # generated pages, and write - for page_num in range(next(iter(paginators.values())).num_pages): - paginated_kwargs = kwargs.copy() - for key in paginators.keys(): - paginator = paginators[key] - previous_page = paginator.page(page_num) if page_num > 0 else None - page = paginator.page(page_num + 1) - next_page = ( - paginator.page(page_num + 2) - if page_num + 1 < paginator.num_pages - else None - ) - paginated_kwargs.update( - { - f"{key}_paginator": paginator, - f"{key}_page": page, - f"{key}_previous_page": previous_page, - f"{key}_next_page": next_page, - } - ) - - localcontext = _get_localcontext( - context, page.save_as, paginated_kwargs, relative_urls - ) - _write_file( - template, - localcontext, - self.output_path, - page.save_as, - override_output, - ) - else: - # no pagination - localcontext = _get_localcontext(context, name, kwargs, relative_urls) - _write_file(template, localcontext, self.output_path, name, override_output) diff --git a/static/css/in.css b/static/css/in.css new file mode 100644 index 00000000..9d0f136f --- /dev/null +++ b/static/css/in.css @@ -0,0 +1,59 @@ +@tailwind base; /* Preflight is injected here */ +@tailwind components; +@tailwind utilities; + +@layer base { + html { + /* text-lg == prose-lg */ + /* text-xl == prose-xl */ + @apply md:text-lg lg:text-xl font-texts text-rp-dawn-text dark:text-rp-moon-iris; + } + text { + @apply text-rp-dawn-text dark:text-rp-moon-iris; + } + a { + @apply underline decoration-2 underline-offset-4 decoration-rp-dawn-gold dark:decoration-rp-moon-pine; + } + a:hover { + @apply underline decoration-2 underline-offset-4 decoration-rp-dawn-foam dark:decoration-rp-moon-rose; + } + h1, + h2, + h3, + h4, + h5, + h6 { + @apply font-headings text-rp-dawn-text dark:text-rp-moon-love; + } + h1 { + @apply text-7xl mb-9; + } + h2 { + @apply text-5xl mb-9; + } + h3 { + @apply text-4xl; + } + h4 { + @apply text-3xl; + } + h5 { + @apply text-2xl; + } + h6 { + @apply text-xl; + } + img { + @apply drop-shadow-lg; + } + dd { + @apply ml-24; + } +} + +@layer components { + /*This does not seem to affect prismjs which is good*/ + code { + @apply bg-rp-dawn-highlight-low dark:bg-rp-moon-highlight-low; + } +} diff --git a/static/css/out.css b/static/css/out.css new file mode 100644 index 00000000..5fe8c5e0 --- /dev/null +++ b/static/css/out.css @@ -0,0 +1,2023 @@ +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +/* +! tailwindcss v3.4.13 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-feature-settings: normal; + /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + letter-spacing: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +input:where([type='button']), +input:where([type='reset']), +input:where([type='submit']) { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden] { + display: none; +} + +html { + /* text-lg == prose-lg */ + /* text-xl == prose-xl */ + font-family: Erode, serif; + --tw-text-opacity: 1; + color: rgb(87 82 121 / var(--tw-text-opacity)); +} + +@media (min-width: 768px) { + html { + font-size: 1.125rem; + line-height: 1.75rem; + } +} + +@media (min-width: 1024px) { + html { + font-size: 1.25rem; + line-height: 1.75rem; + } +} + +@media (prefers-color-scheme: dark) { + html { + --tw-text-opacity: 1; + color: rgb(196 167 231 / var(--tw-text-opacity)); + } +} + +text { + --tw-text-opacity: 1; + color: rgb(87 82 121 / var(--tw-text-opacity)); +} + +@media (prefers-color-scheme: dark) { + text { + --tw-text-opacity: 1; + color: rgb(196 167 231 / var(--tw-text-opacity)); + } +} + +a { + text-decoration-line: underline; + text-decoration-color: #ea9d34; + text-decoration-thickness: 2px; + text-underline-offset: 4px; +} + +@media (prefers-color-scheme: dark) { + a { + text-decoration-color: #3e8fb0; + } +} + +a:hover { + text-decoration-line: underline; + text-decoration-color: #56949f; + text-decoration-thickness: 2px; + text-underline-offset: 4px; +} + +@media (prefers-color-scheme: dark) { + a:hover { + text-decoration-color: #ea9a97; + } +} + +h1, + h2, + h3, + h4, + h5, + h6 { + font-family: Fira Sans, sans-serif; + --tw-text-opacity: 1; + color: rgb(87 82 121 / var(--tw-text-opacity)); +} + +@media (prefers-color-scheme: dark) { + h1, + h2, + h3, + h4, + h5, + h6 { + --tw-text-opacity: 1; + color: rgb(235 111 146 / var(--tw-text-opacity)); + } +} + +h1 { + margin-bottom: 2.25rem; + font-size: 4.5rem; + line-height: 1; +} + +h2 { + margin-bottom: 2.25rem; + font-size: 3rem; + line-height: 1; +} + +h3 { + font-size: 2.25rem; + line-height: 2.5rem; +} + +h4 { + font-size: 1.875rem; + line-height: 2.25rem; +} + +h5 { + font-size: 1.5rem; + line-height: 2rem; +} + +h6 { + font-size: 1.25rem; + line-height: 1.75rem; +} + +img { + --tw-drop-shadow: drop-shadow(0 10px 8px rgb(0 0 0 / 0.04)) drop-shadow(0 4px 3px rgb(0 0 0 / 0.1)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} + +dd { + margin-left: 6rem; +} + +/* Preflight is injected here */ + +.prose { + color: #575279; + max-width: 65ch; +} + +.prose :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + margin-bottom: 1.25em; +} + +.prose :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-lead); + font-size: 1.25em; + line-height: 1.6; + margin-top: 1.2em; + margin-bottom: 1.2em; +} + +.prose :where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: #575279; + text-decoration: underline; + font-weight: 500; + text-decoration-color: #ea9d34; + text-decoration-thickness: 2px; +} + +.prose :where(strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: #575279; + font-weight: 800; +} + +.prose :where(a strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; +} + +.prose :where(blockquote strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; +} + +.prose :where(thead th strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; +} + +.prose :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: decimal; + margin-top: 1.25em; + margin-bottom: 1.25em; + padding-inline-start: 1.625em; +} + +.prose :where(ol[type="A"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: upper-alpha; +} + +.prose :where(ol[type="a"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: lower-alpha; +} + +.prose :where(ol[type="A" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: upper-alpha; +} + +.prose :where(ol[type="a" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: lower-alpha; +} + +.prose :where(ol[type="I"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: upper-roman; +} + +.prose :where(ol[type="i"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: lower-roman; +} + +.prose :where(ol[type="I" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: upper-roman; +} + +.prose :where(ol[type="i" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: lower-roman; +} + +.prose :where(ol[type="1"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: decimal; +} + +.prose :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + list-style-type: disc; + margin-top: 1.25em; + margin-bottom: 1.25em; + padding-inline-start: 1.625em; +} + +.prose :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { + font-weight: 400; + color: var(--tw-prose-counters); +} + +.prose :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { + color: var(--tw-prose-bullets); +} + +.prose :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 600; + margin-top: 1.25em; +} + +.prose :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + border-color: var(--tw-prose-hr); + border-top-width: 1px; + margin-top: 3em; + margin-bottom: 3em; +} + +.prose :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 500; + font-style: italic; + color: #575279; + border-inline-start-width: 0.25rem; + border-inline-start-color: var(--tw-prose-quote-borders); + quotes: "\201C""\201D""\2018""\2019"; + margin-top: 1.6em; + margin-bottom: 1.6em; + padding-inline-start: 1em; + border-color: #9893a5; + background-color: #f2e9e1; +} + +.prose :where(blockquote p:first-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { + content: open-quote; +} + +.prose :where(blockquote p:last-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { + content: close-quote; +} + +.prose :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 800; + font-size: 2.25em; + margin-top: 0; + margin-bottom: 0.8888889em; + line-height: 1.1111111; +} + +.prose :where(h1 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 900; + color: inherit; +} + +.prose :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 700; + font-size: 1.5em; + margin-top: 2em; + margin-bottom: 1em; + line-height: 1.3333333; +} + +.prose :where(h2 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 800; + color: inherit; +} + +.prose :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 600; + font-size: 1.25em; + margin-top: 1.6em; + margin-bottom: 0.6em; + line-height: 1.6; +} + +.prose :where(h3 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 700; + color: inherit; +} + +.prose :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 600; + margin-top: 1.5em; + margin-bottom: 0.5em; + line-height: 1.5; +} + +.prose :where(h4 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 700; + color: inherit; +} + +.prose :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 2em; + margin-bottom: 2em; +} + +.prose :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + display: block; + margin-top: 2em; + margin-bottom: 2em; +} + +.prose :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 2em; + margin-bottom: 2em; +} + +.prose :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-weight: 500; + font-family: inherit; + color: var(--tw-prose-kbd); + box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%); + font-size: 0.875em; + border-radius: 0.3125rem; + padding-top: 0.1875em; + padding-inline-end: 0.375em; + padding-bottom: 0.1875em; + padding-inline-start: 0.375em; +} + +.prose :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { + content: ""; +} + +.prose :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { + content: ""; +} + +.prose :where(a code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; +} + +.prose :where(h1 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; +} + +.prose :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + font-size: 0.875em; +} + +.prose :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; + font-size: 0.9em; +} + +.prose :where(h4 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; +} + +.prose :where(blockquote code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; +} + +.prose :where(thead th code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: inherit; +} + +.prose :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + width: 100%; + table-layout: auto; + margin-top: 2em; + margin-bottom: 2em; + font-size: 0.875em; + line-height: 1.7142857; +} + +.prose :where(thead):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + border-bottom-width: 1px; + border-bottom-color: var(--tw-prose-th-borders); +} + +.prose :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-headings); + font-weight: 600; + vertical-align: bottom; + padding-inline-end: 0.5714286em; + padding-bottom: 0.5714286em; + padding-inline-start: 0.5714286em; +} + +.prose :where(tbody tr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + border-bottom-width: 1px; + border-bottom-color: var(--tw-prose-td-borders); +} + +.prose :where(tbody tr:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + border-bottom-width: 0; +} + +.prose :where(tbody td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + vertical-align: baseline; +} + +.prose :where(tfoot):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + border-top-width: 1px; + border-top-color: var(--tw-prose-th-borders); +} + +.prose :where(tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + vertical-align: top; +} + +.prose :where(th, td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + text-align: start; +} + +.prose :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + margin-bottom: 0; +} + +.prose :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: var(--tw-prose-captions); + font-size: 0.875em; + line-height: 1.4285714; + margin-top: 0.8571429em; +} + +.prose { + --tw-prose-body: #374151; + --tw-prose-headings: #111827; + --tw-prose-lead: #4b5563; + --tw-prose-links: #111827; + --tw-prose-bold: #111827; + --tw-prose-counters: #6b7280; + --tw-prose-bullets: #d1d5db; + --tw-prose-hr: #e5e7eb; + --tw-prose-quotes: #111827; + --tw-prose-quote-borders: #e5e7eb; + --tw-prose-captions: #6b7280; + --tw-prose-kbd: #111827; + --tw-prose-kbd-shadows: 17 24 39; + --tw-prose-code: #111827; + --tw-prose-pre-code: #e5e7eb; + --tw-prose-pre-bg: #1f2937; + --tw-prose-th-borders: #d1d5db; + --tw-prose-td-borders: #e5e7eb; + --tw-prose-invert-body: #d1d5db; + --tw-prose-invert-headings: #fff; + --tw-prose-invert-lead: #9ca3af; + --tw-prose-invert-links: #fff; + --tw-prose-invert-bold: #fff; + --tw-prose-invert-counters: #9ca3af; + --tw-prose-invert-bullets: #4b5563; + --tw-prose-invert-hr: #374151; + --tw-prose-invert-quotes: #f3f4f6; + --tw-prose-invert-quote-borders: #374151; + --tw-prose-invert-captions: #9ca3af; + --tw-prose-invert-kbd: #fff; + --tw-prose-invert-kbd-shadows: 255 255 255; + --tw-prose-invert-code: #fff; + --tw-prose-invert-pre-code: #d1d5db; + --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); + --tw-prose-invert-th-borders: #4b5563; + --tw-prose-invert-td-borders: #374151; + font-size: 1rem; + line-height: 1.75; +} + +.prose :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + margin-bottom: 0; +} + +.prose :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +.prose :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0.375em; +} + +.prose :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0.375em; +} + +.prose :where(.prose > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.75em; + margin-bottom: 0.75em; +} + +.prose :where(.prose > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; +} + +.prose :where(.prose > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 1.25em; +} + +.prose :where(.prose > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; +} + +.prose :where(.prose > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 1.25em; +} + +.prose :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.75em; + margin-bottom: 0.75em; +} + +.prose :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + margin-bottom: 1.25em; +} + +.prose :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.5em; + padding-inline-start: 1.625em; +} + +.prose :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; +} + +.prose :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; +} + +.prose :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; +} + +.prose :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; +} + +.prose :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0; +} + +.prose :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-end: 0; +} + +.prose :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-top: 0.5714286em; + padding-inline-end: 0.5714286em; + padding-bottom: 0.5714286em; + padding-inline-start: 0.5714286em; +} + +.prose :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0; +} + +.prose :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-end: 0; +} + +.prose :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 2em; + margin-bottom: 2em; +} + +.prose :where(.prose > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; +} + +.prose :where(.prose > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 0; +} + +.prose :where(h1, h2, h3, h4, h5, h6):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: #575279; +} + +/*This does not seem to affect prismjs which is good*/ + +code { + --tw-bg-opacity: 1; + background-color: rgb(244 237 232 / var(--tw-bg-opacity)); +} + +@media (prefers-color-scheme: dark) { + code { + --tw-bg-opacity: 1; + background-color: rgb(42 40 62 / var(--tw-bg-opacity)); + } +} + +.col-span-1 { + grid-column: span 1 / span 1; +} + +.col-span-2 { + grid-column: span 2 / span 2; +} + +.col-span-3 { + grid-column: span 3 / span 3; +} + +.m-10 { + margin: 2.5rem; +} + +.m-4 { + margin: 1rem; +} + +.mb-3 { + margin-bottom: 0.75rem; +} + +.block { + display: block; +} + +.inline-block { + display: inline-block; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.inline-grid { + display: inline-grid; +} + +.size-5 { + width: 1.25rem; + height: 1.25rem; +} + +.w-12 { + width: 3rem; +} + +.w-8 { + width: 2rem; +} + +.list-none { + list-style-type: none; +} + +.grid-cols-1 { + grid-template-columns: repeat(1, minmax(0, 1fr)); +} + +.grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.grid-cols-5 { + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + +.grid-cols-\[max-content_max-content_max-content\] { + grid-template-columns: max-content max-content max-content; +} + +.grid-cols-\[max-content_max-content_max-content_max-content_max-content\] { + grid-template-columns: max-content max-content max-content max-content max-content; +} + +.items-center { + align-items: center; +} + +.justify-center { + justify-content: center; +} + +.gap-8 { + gap: 2rem; +} + +.hyphens-auto { + -webkit-hyphens: auto; + hyphens: auto; +} + +.border-b-2 { + border-bottom-width: 2px; +} + +.border-b-4 { + border-bottom-width: 4px; +} + +.border-t-2 { + border-top-width: 2px; +} + +.border-rp-dawn-overlay { + --tw-border-opacity: 1; + border-color: rgb(242 233 225 / var(--tw-border-opacity)); +} + +.bg-rp-dawn-base { + --tw-bg-opacity: 1; + background-color: rgb(250 244 237 / var(--tw-bg-opacity)); +} + +.bg-rp-dawn-overlay { + --tw-bg-opacity: 1; + background-color: rgb(242 233 225 / var(--tw-bg-opacity)); +} + +.bg-rp-dawn-surface { + --tw-bg-opacity: 1; + background-color: rgb(255 250 243 / var(--tw-bg-opacity)); +} + +.p-1 { + padding: 0.25rem; +} + +.p-4 { + padding: 1rem; +} + +.p-5 { + padding: 1.25rem; +} + +.p-8 { + padding: 2rem; +} + +.pb-60 { + padding-bottom: 15rem; +} + +.pl-4 { + padding-left: 1rem; +} + +.pt-20 { + padding-top: 5rem; +} + +.text-center { + text-align: center; +} + +.align-top { + vertical-align: top; +} + +.font-tags { + font-family: ui-sans-serif, sans-serif; +} + +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} + +.text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; +} + +.text-5xl { + font-size: 3rem; + line-height: 1; +} + +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} + +.text-xs { + font-size: 0.75rem; + line-height: 1rem; +} + +.font-bold { + font-weight: 700; +} + +.italic { + font-style: italic; +} + +.text-rp-dawn-foam { + --tw-text-opacity: 1; + color: rgb(86 148 159 / var(--tw-text-opacity)); +} + +.text-rp-dawn-overlay { + --tw-text-opacity: 1; + color: rgb(242 233 225 / var(--tw-text-opacity)); +} + +.text-rp-dawn-pine { + --tw-text-opacity: 1; + color: rgb(40 105 131 / var(--tw-text-opacity)); +} + +.text-rp-dawn-text { + --tw-text-opacity: 1; + color: rgb(87 82 121 / var(--tw-text-opacity)); +} + +.no-underline { + text-decoration-line: none; +} + +.shadow { + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +@media (min-width: 768px) { + .md\:prose-base { + font-size: 1rem; + line-height: 1.75; + } + + .md\:prose-base :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + margin-bottom: 1.25em; + } + + .md\:prose-base :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 1.25em; + line-height: 1.6; + margin-top: 1.2em; + margin-bottom: 1.2em; + } + + .md\:prose-base :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.6em; + margin-bottom: 1.6em; + padding-inline-start: 1em; + } + + .md\:prose-base :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 2.25em; + margin-top: 0; + margin-bottom: 0.8888889em; + line-height: 1.1111111; + } + + .md\:prose-base :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 1.5em; + margin-top: 2em; + margin-bottom: 1em; + line-height: 1.3333333; + } + + .md\:prose-base :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 1.25em; + margin-top: 1.6em; + margin-bottom: 0.6em; + line-height: 1.6; + } + + .md\:prose-base :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.5em; + margin-bottom: 0.5em; + line-height: 1.5; + } + + .md\:prose-base :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 2em; + margin-bottom: 2em; + } + + .md\:prose-base :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 2em; + margin-bottom: 2em; + } + + .md\:prose-base :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + margin-bottom: 0; + } + + .md\:prose-base :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 2em; + margin-bottom: 2em; + } + + .md\:prose-base :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.875em; + border-radius: 0.3125rem; + padding-top: 0.1875em; + padding-inline-end: 0.375em; + padding-bottom: 0.1875em; + padding-inline-start: 0.375em; + } + + .md\:prose-base :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.875em; + } + + .md\:prose-base :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.875em; + } + + .md\:prose-base :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.9em; + } + + .md\:prose-base :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.875em; + line-height: 1.7142857; + margin-top: 1.7142857em; + margin-bottom: 1.7142857em; + border-radius: 0.375rem; + padding-top: 0.8571429em; + padding-inline-end: 1.1428571em; + padding-bottom: 0.8571429em; + padding-inline-start: 1.1428571em; + } + + .md\:prose-base :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + margin-bottom: 1.25em; + padding-inline-start: 1.625em; + } + + .md\:prose-base :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + margin-bottom: 1.25em; + padding-inline-start: 1.625em; + } + + .md\:prose-base :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.5em; + margin-bottom: 0.5em; + } + + .md\:prose-base :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0.375em; + } + + .md\:prose-base :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0.375em; + } + + .md\:prose-base :where(.md\:prose-base > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.75em; + margin-bottom: 0.75em; + } + + .md\:prose-base :where(.md\:prose-base > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + } + + .md\:prose-base :where(.md\:prose-base > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 1.25em; + } + + .md\:prose-base :where(.md\:prose-base > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + } + + .md\:prose-base :where(.md\:prose-base > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 1.25em; + } + + .md\:prose-base :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.75em; + margin-bottom: 0.75em; + } + + .md\:prose-base :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + margin-bottom: 1.25em; + } + + .md\:prose-base :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.25em; + } + + .md\:prose-base :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.5em; + padding-inline-start: 1.625em; + } + + .md\:prose-base :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 3em; + margin-bottom: 3em; + } + + .md\:prose-base :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + + .md\:prose-base :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + + .md\:prose-base :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + + .md\:prose-base :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + + .md\:prose-base :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.875em; + line-height: 1.7142857; + } + + .md\:prose-base :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-end: 0.5714286em; + padding-bottom: 0.5714286em; + padding-inline-start: 0.5714286em; + } + + .md\:prose-base :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0; + } + + .md\:prose-base :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-end: 0; + } + + .md\:prose-base :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-top: 0.5714286em; + padding-inline-end: 0.5714286em; + padding-bottom: 0.5714286em; + padding-inline-start: 0.5714286em; + } + + .md\:prose-base :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0; + } + + .md\:prose-base :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-end: 0; + } + + .md\:prose-base :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 2em; + margin-bottom: 2em; + } + + .md\:prose-base :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + margin-bottom: 0; + } + + .md\:prose-base :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.875em; + line-height: 1.4285714; + margin-top: 0.8571429em; + } + + .md\:prose-base :where(.md\:prose-base > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + + .md\:prose-base :where(.md\:prose-base > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 0; + } +} + +@media (min-width: 1024px) { + .lg\:prose-lg { + font-size: 1.125rem; + line-height: 1.7777778; + } + + .lg\:prose-lg :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.3333333em; + margin-bottom: 1.3333333em; + } + + .lg\:prose-lg :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 1.2222222em; + line-height: 1.4545455; + margin-top: 1.0909091em; + margin-bottom: 1.0909091em; + } + + .lg\:prose-lg :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.6666667em; + margin-bottom: 1.6666667em; + padding-inline-start: 1em; + } + + .lg\:prose-lg :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 2.6666667em; + margin-top: 0; + margin-bottom: 0.8333333em; + line-height: 1; + } + + .lg\:prose-lg :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 1.6666667em; + margin-top: 1.8666667em; + margin-bottom: 1.0666667em; + line-height: 1.3333333; + } + + .lg\:prose-lg :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 1.3333333em; + margin-top: 1.6666667em; + margin-bottom: 0.6666667em; + line-height: 1.5; + } + + .lg\:prose-lg :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.7777778em; + margin-bottom: 0.4444444em; + line-height: 1.5555556; + } + + .lg\:prose-lg :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.7777778em; + margin-bottom: 1.7777778em; + } + + .lg\:prose-lg :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.7777778em; + margin-bottom: 1.7777778em; + } + + .lg\:prose-lg :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + margin-bottom: 0; + } + + .lg\:prose-lg :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.7777778em; + margin-bottom: 1.7777778em; + } + + .lg\:prose-lg :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.8888889em; + border-radius: 0.3125rem; + padding-top: 0.2222222em; + padding-inline-end: 0.4444444em; + padding-bottom: 0.2222222em; + padding-inline-start: 0.4444444em; + } + + .lg\:prose-lg :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.8888889em; + } + + .lg\:prose-lg :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.8666667em; + } + + .lg\:prose-lg :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.875em; + } + + .lg\:prose-lg :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.8888889em; + line-height: 1.75; + margin-top: 2em; + margin-bottom: 2em; + border-radius: 0.375rem; + padding-top: 1em; + padding-inline-end: 1.5em; + padding-bottom: 1em; + padding-inline-start: 1.5em; + } + + .lg\:prose-lg :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.3333333em; + margin-bottom: 1.3333333em; + padding-inline-start: 1.5555556em; + } + + .lg\:prose-lg :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.3333333em; + margin-bottom: 1.3333333em; + padding-inline-start: 1.5555556em; + } + + .lg\:prose-lg :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.6666667em; + margin-bottom: 0.6666667em; + } + + .lg\:prose-lg :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0.4444444em; + } + + .lg\:prose-lg :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0.4444444em; + } + + .lg\:prose-lg :where(.lg\:prose-lg > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.8888889em; + margin-bottom: 0.8888889em; + } + + .lg\:prose-lg :where(.lg\:prose-lg > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.3333333em; + } + + .lg\:prose-lg :where(.lg\:prose-lg > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 1.3333333em; + } + + .lg\:prose-lg :where(.lg\:prose-lg > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.3333333em; + } + + .lg\:prose-lg :where(.lg\:prose-lg > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 1.3333333em; + } + + .lg\:prose-lg :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.8888889em; + margin-bottom: 0.8888889em; + } + + .lg\:prose-lg :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.3333333em; + margin-bottom: 1.3333333em; + } + + .lg\:prose-lg :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.3333333em; + } + + .lg\:prose-lg :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0.6666667em; + padding-inline-start: 1.5555556em; + } + + .lg\:prose-lg :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 3.1111111em; + margin-bottom: 3.1111111em; + } + + .lg\:prose-lg :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + + .lg\:prose-lg :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + + .lg\:prose-lg :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + + .lg\:prose-lg :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + + .lg\:prose-lg :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.8888889em; + line-height: 1.5; + } + + .lg\:prose-lg :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-end: 0.75em; + padding-bottom: 0.75em; + padding-inline-start: 0.75em; + } + + .lg\:prose-lg :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0; + } + + .lg\:prose-lg :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-end: 0; + } + + .lg\:prose-lg :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-top: 0.75em; + padding-inline-end: 0.75em; + padding-bottom: 0.75em; + padding-inline-start: 0.75em; + } + + .lg\:prose-lg :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-start: 0; + } + + .lg\:prose-lg :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + padding-inline-end: 0; + } + + .lg\:prose-lg :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 1.7777778em; + margin-bottom: 1.7777778em; + } + + .lg\:prose-lg :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + margin-bottom: 0; + } + + .lg\:prose-lg :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + font-size: 0.8888889em; + line-height: 1.5; + margin-top: 1em; + } + + .lg\:prose-lg :where(.lg\:prose-lg > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-top: 0; + } + + .lg\:prose-lg :where(.lg\:prose-lg > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + margin-bottom: 0; + } +} + +@media (prefers-color-scheme: dark) { + .dark\:prose-dark { + color: #c4a7e7; + } + + .dark\:prose-dark :where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: #c4a7e7; + text-decoration-color: #3e8fb0; + text-decoration-thickness: 2px; + } + + .dark\:prose-dark :where(h1, h2, h3, h4, h5, h6):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: #eb6f92; + } + + .dark\:prose-dark :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + border-color: #393552; + background-color: #2a273f; + color: #e0def4; + } + + .dark\:prose-dark :where(strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { + color: #c4a7e7; + font-weight: 800; + } +} + +.hover\:no-underline:hover { + text-decoration-line: none; +} + +.prose-img\:rounded :is(:where(img):not(:where([class~="not-prose"],[class~="not-prose"] *))) { + border-radius: 0.25rem; +} + +@media (min-width: 768px) { + .md\:grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .md\:border-l-4 { + border-left-width: 4px; + } + + .md\:text-2xl { + font-size: 1.5rem; + line-height: 2rem; + } + + .md\:text-7xl { + font-size: 4.5rem; + line-height: 1; + } + + .md\:text-base { + font-size: 1rem; + line-height: 1.5rem; + } +} + +@media (min-width: 1024px) { + .lg\:grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .lg\:text-lg { + font-size: 1.125rem; + line-height: 1.75rem; + } +} + +@media (min-width: 1280px) { + .xl\:grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +@media (prefers-color-scheme: dark) { + .dark\:border-rp-moon-overlay { + --tw-border-opacity: 1; + border-color: rgb(57 53 82 / var(--tw-border-opacity)); + } + + .dark\:bg-rp-moon-base { + --tw-bg-opacity: 1; + background-color: rgb(35 33 54 / var(--tw-bg-opacity)); + } + + .dark\:bg-rp-moon-overlay { + --tw-bg-opacity: 1; + background-color: rgb(57 53 82 / var(--tw-bg-opacity)); + } + + .dark\:bg-rp-moon-surface { + --tw-bg-opacity: 1; + background-color: rgb(42 39 63 / var(--tw-bg-opacity)); + } + + .dark\:text-rp-moon-foam { + --tw-text-opacity: 1; + color: rgb(156 207 216 / var(--tw-text-opacity)); + } + + .dark\:text-rp-moon-rose { + --tw-text-opacity: 1; + color: rgb(234 154 151 / var(--tw-text-opacity)); + } + + .dark\:text-rp-moon-text { + --tw-text-opacity: 1; + color: rgb(224 222 244 / var(--tw-text-opacity)); + } +} diff --git a/static/css/prism-rose-pine-moon-alt.css b/static/css/prism-rose-pine-moon-alt.css new file mode 100644 index 00000000..6ceaebae --- /dev/null +++ b/static/css/prism-rose-pine-moon-alt.css @@ -0,0 +1,201 @@ +/** + * MIT License + * Rosé Pine Theme + * https://github.com/rose-pine + * Ported for PrismJS by fvrests [@fvrests] + */ + +code[class*="language-"], +pre[class*="language-"] { + color: #e0def4; + background: #2a273f; + font-family: "Cartograph CF", ui-monospace, SFMono-Regular, Menlo, Monaco, + Consolas, "Liberation Mono", "Courier New", monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; + + @media print { + text-shadow: none; + } +} + +/* Selection */ +code[class*="language-"]::-moz-selection, +pre[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection, +pre[class*="language-"] ::-moz-selection { + background: #44415a; +} + +code[class*="language-"]::selection, +pre[class*="language-"]::selection, +code[class*="language-"] ::selection, +pre[class*="language-"] ::selection { + background: #44415a; +} + +/* Code (block & inline) */ +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + color: #e0def4; + background: #2a273f; +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; + color: #e0def4; + background: #2a273f; +} + +/* Text style & opacity */ +.token.entity { + cursor: help; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic, +.token.selector, +.token.doctype, +.token.attr-name, +.token.inserted, +.token.deleted, +.token.comment, +.token.prolog, +.token.cdata, +.token.constant, +.token.parameter, +.token.url { + font-style: italic; +} + +.token.url { + text-decoration: underline; +} + +.namespace { + opacity: 0.7; +} + +/* Syntax highlighting */ +.token.constant { + color: #e0def4; +} + +.token.comment, +.token.prolog, +.token.cdata, +.token.punctuation { + color: #908caa; +} + +.token.delimiter, +.token.important, +.token.atrule, +.token.operator, +.token.keyword { + color: #3e8fb0; +} + +.token.tag, +.token.tag .punctuation, +.token.doctype, +.token.variable, +.token.regex, +.token.class-name, +.token.selector, +.token.inserted { + color: #9ccfd8; +} + +.token.boolean, +.token.entity, +.token.number, +.token.symbol, +.token.function { + color: #ea9a97; +} + +.token.string, +.token.char, +.token.property, +.token.attr-value, +.token.attr-value .punctuation { + color: #f6c177; +} + +.token.parameter, +.token.url, +.token.name, +.token.attr-name, +.token.builtin { + color: #c4a7e7; +} + +.token.deleted { + color: #eb6f92; +} + +/* Insertions & deletions */ +.token.inserted { + background: rgba(156 207 216 0.12); +} + +.token.deleted { + background: rgba(235 111 146 0.12); +} + +/* Line highlighting */ +pre[data-line] { + position: relative; +} + +pre[class*="language-"] > code[class*="language-"] { + position: relative; + z-index: 1; +} + +.line-highlight, +.highlight-lines .highlighted { + position: absolute; + left: 0; + right: 0; + padding: inherit 0; + margin-top: 1em; + + background: #44415a; + box-shadow: inset 5px 0 0 #e0def4; + + z-index: 0; + + pointer-events: none; + + line-height: inherit; + white-space: pre; +} diff --git a/static/css/prism-rose-pine-moon.css b/static/css/prism-rose-pine-moon.css new file mode 100644 index 00000000..fd4353cc --- /dev/null +++ b/static/css/prism-rose-pine-moon.css @@ -0,0 +1,201 @@ +/** + * MIT License + * Rosé Pine Theme + * https://github.com/rose-pine + * Ported for PrismJS by fvrests [@fvrests] + */ + +code[class*="language-"], +pre[class*="language-"] { + color: #e0def4; + background: #232136; + font-family: "Cartograph CF", ui-monospace, SFMono-Regular, Menlo, Monaco, + Consolas, "Liberation Mono", "Courier New", monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; + + @media print { + text-shadow: none; + } +} + +/* Selection */ +code[class*="language-"]::-moz-selection, +pre[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection, +pre[class*="language-"] ::-moz-selection { + background: #44415a; +} + +code[class*="language-"]::selection, +pre[class*="language-"]::selection, +code[class*="language-"] ::selection, +pre[class*="language-"] ::selection { + background: #44415a; +} + +/* Code (block & inline) */ +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + color: #e0def4; + background: #232136; +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; + color: #e0def4; + background: #232136; +} + +/* Text style & opacity */ +.token.entity { + cursor: help; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic, +.token.selector, +.token.doctype, +.token.attr-name, +.token.inserted, +.token.deleted, +.token.comment, +.token.prolog, +.token.cdata, +.token.constant, +.token.parameter, +.token.url { + font-style: italic; +} + +.token.url { + text-decoration: underline; +} + +.namespace { + opacity: 0.7; +} + +/* Syntax highlighting */ +.token.constant { + color: #e0def4; +} + +.token.comment, +.token.prolog, +.token.cdata, +.token.punctuation { + color: #908caa; +} + +.token.delimiter, +.token.important, +.token.atrule, +.token.operator, +.token.keyword { + color: #3e8fb0; +} + +.token.tag, +.token.tag .punctuation, +.token.doctype, +.token.variable, +.token.regex, +.token.class-name, +.token.selector, +.token.inserted { + color: #9ccfd8; +} + +.token.boolean, +.token.entity, +.token.number, +.token.symbol, +.token.function { + color: #ea9a97; +} + +.token.string, +.token.char, +.token.property, +.token.attr-value, +.token.attr-value .punctuation { + color: #f6c177; +} + +.token.parameter, +.token.url, +.token.name, +.token.attr-name, +.token.builtin { + color: #c4a7e7; +} + +.token.deleted { + color: #eb6f92; +} + +/* Insertions & deletions */ +.token.inserted { + background: rgba(156 207 216 0.12); +} + +.token.deleted { + background: rgba(235 111 146 0.12); +} + +/* Line highlighting */ +pre[data-line] { + position: relative; +} + +pre[class*="language-"] > code[class*="language-"] { + position: relative; + z-index: 1; +} + +.line-highlight, +.highlight-lines .highlighted { + position: absolute; + left: 0; + right: 0; + padding: inherit 0; + margin-top: 1em; + + background: #44415a; + box-shadow: inset 5px 0 0 #e0def4; + + z-index: 0; + + pointer-events: none; + + line-height: inherit; + white-space: pre; +} diff --git a/static/css/prism.css b/static/css/prism.css new file mode 100644 index 00000000..6d73b1fb --- /dev/null +++ b/static/css/prism.css @@ -0,0 +1,3 @@ +/* PrismJS 1.29.0 +https://prismjs.com/download.html?themes#themes=prism&languages=markup+css+clike+javascript+bash+diff+django+dns-zone-file+docker+dot+elixir+erlang+git+go+go-module+hcl+ini+jq+lua+makefile+markdown+markup-templating+nginx+properties+python+r+rest+sql+toml+vim+yaml */ +code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help} diff --git a/static/js/prism.js b/static/js/prism.js new file mode 100644 index 00000000..f65c9412 --- /dev/null +++ b/static/js/prism.js @@ -0,0 +1,34 @@ +/* PrismJS 1.29.0 +https://prismjs.com/download.html?themes#themes=prism&languages=markup+css+clike+javascript+bash+diff+django+dns-zone-file+docker+dot+elixir+erlang+git+go+go-module+hcl+ini+jq+lua+makefile+markdown+markup-templating+nginx+properties+python+r+rest+sql+toml+vim+yaml */ +var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=g.reach);A+=w.value.length,w=w.next){var E=w.value;if(n.length>e.length)return;if(!(E instanceof i)){var P,L=1;if(y){if(!(P=l(b,A,e,m))||P.index>=e.length)break;var S=P.index,O=P.index+P[0].length,j=A;for(j+=w.value.length;S>=j;)j+=(w=w.next).value.length;if(A=j-=w.value.length,w.value instanceof i)continue;for(var C=w;C!==n.tail&&(jg.reach&&(g.reach=W);var z=w.prev;if(_&&(z=u(n,z,_),A+=_.length),c(n,z,L),w=u(n,z,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),L>1){var I={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,I),g&&I.reach>g.reach&&(g.reach=I.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a"+i.content+""},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); +Prism.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",(function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))})),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var t={"included-cdata":{pattern://i,inside:s}};t["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var n={};n[a]={pattern:RegExp("(<__[^>]*>)(?:))*\\]\\]>|(?!)".replace(/__/g,(function(){return a})),"i"),lookbehind:!0,greedy:!0,inside:t},Prism.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(Prism.languages.markup.tag,"addAttribute",{value:function(a,e){Prism.languages.markup.tag.inside["special-attr"].push({pattern:RegExp("(^|[\"'\\s])(?:"+a+")\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))","i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[e,"language-"+e],inside:Prism.languages[e]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml; +!function(s){var e=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;s.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:[^;{\\s\"']|\\s+(?!\\s)|"+e.source+")*?(?:;|(?=\\s*\\{))"),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+e.source+"|(?:[^\\\\\r\n()\"']|\\\\[^])*)\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+e.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+e.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:e,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var t=s.languages.markup;t&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))}(Prism); +Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/}; +Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp("(^|[^\\w$])(?:NaN|Infinity|0[bB][01]+(?:_[01]+)*n?|0[oO][0-7]+(?:_[0-7]+)*n?|0[xX][\\dA-Fa-f]+(?:_[\\dA-Fa-f]+)*n?|\\d+(?:_\\d+)*n|(?:\\d+(?:_\\d+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\.\\d+(?:_\\d+)*)(?:[Ee][+-]?\\d+(?:_\\d+)*)?)(?![\\w$])"),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp("((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s]|\\b(?:return|yield))\\s*)/(?:(?:\\[(?:[^\\]\\\\\r\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}|(?:\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.)*\\])*\\])*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}v[dgimyus]{0,7})(?=(?:\\s|/\\*(?:[^*]|\\*(?!/))*\\*/)*(?:$|[\r\n,.;:})\\]]|//))"),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:Prism.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),Prism.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.markup.tag.addAttribute("on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)","javascript")),Prism.languages.js=Prism.languages.javascript; +!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",a={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},n={bash:a,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:n},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:a}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:n},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:n.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:n.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},a.inside=e.languages.bash;for(var s=["comment","function-name","for-or-select","assign-left","parameter","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=n.variable[1].inside,i=0;i",unchanged:" ",diff:"!"};Object.keys(n).forEach((function(a){var i=n[a],r=[];/^\w+$/.test(a)||r.push(/\w+/.exec(a)[0]),"diff"===a&&r.push("bold"),e.languages.diff[a]={pattern:RegExp("^(?:["+i+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:r,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(a)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:n})}(Prism); +!function(e){function n(e,n){return"___"+e.toUpperCase()+n+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(t,a,r,o){if(t.language===a){var c=t.tokenStack=[];t.code=t.code.replace(r,(function(e){if("function"==typeof o&&!o(e))return e;for(var r,i=c.length;-1!==t.code.indexOf(r=n(a,i));)++i;return c[i]=e,r})),t.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(t,a){if(t.language===a&&t.tokenStack){t.grammar=e.languages[a];var r=0,o=Object.keys(t.tokenStack);!function c(i){for(var u=0;u=o.length);u++){var g=i[u];if("string"==typeof g||g.content&&"string"==typeof g.content){var l=o[r],s=t.tokenStack[l],f="string"==typeof g?g:g.content,p=n(a,l),k=f.indexOf(p);if(k>-1){++r;var m=f.substring(0,k),d=new e.Token(a,e.tokenize(s,t.grammar),"language-"+a,s),h=f.substring(k+p.length),v=[];m&&v.push.apply(v,c([m])),v.push(d),h&&v.push.apply(v,c([h])),"string"==typeof g?i.splice.apply(i,[u,1].concat(v)):g.content=v}}else g.content&&c(g.content)}return i}(t.tokens)}}}})}(Prism); +!function(e){e.languages.django={comment:/^\{#[\s\S]*?#\}$/,tag:{pattern:/(^\{%[+-]?\s*)\w+/,lookbehind:!0,alias:"keyword"},delimiter:{pattern:/^\{[{%][+-]?|[+-]?[}%]\}$/,alias:"punctuation"},string:{pattern:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},filter:{pattern:/(\|)\w+/,lookbehind:!0,alias:"function"},test:{pattern:/(\bis\s+(?:not\s+)?)(?!not\b)\w+/,lookbehind:!0,alias:"function"},function:/\b[a-z_]\w+(?=\s*\()/i,keyword:/\b(?:and|as|by|else|for|if|import|in|is|loop|not|or|recursive|with|without)\b/,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,number:/\b\d+(?:\.\d+)?\b/,boolean:/[Ff]alse|[Nn]one|[Tt]rue/,variable:/\b\w+\b/,punctuation:/[{}[\](),.:;]/};var n=/\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}|\{#[\s\S]*?#\}/g,o=e.languages["markup-templating"];e.hooks.add("before-tokenize",(function(e){o.buildPlaceholders(e,"django",n)})),e.hooks.add("after-tokenize",(function(e){o.tokenizePlaceholders(e,"django")})),e.languages.jinja2=e.languages.django,e.hooks.add("before-tokenize",(function(e){o.buildPlaceholders(e,"jinja2",n)})),e.hooks.add("after-tokenize",(function(e){o.tokenizePlaceholders(e,"jinja2")}))}(Prism); +Prism.languages["dns-zone-file"]={comment:/;.*/,string:{pattern:/"(?:\\.|[^"\\\r\n])*"/,greedy:!0},variable:[{pattern:/(^\$ORIGIN[ \t]+)\S+/m,lookbehind:!0},{pattern:/(^|\s)@(?=\s|$)/,lookbehind:!0}],keyword:/^\$(?:INCLUDE|ORIGIN|TTL)(?=\s|$)/m,class:{pattern:/(^|\s)(?:CH|CS|HS|IN)(?=\s|$)/,lookbehind:!0,alias:"keyword"},type:{pattern:/(^|\s)(?:A|A6|AAAA|AFSDB|APL|ATMA|CAA|CDNSKEY|CDS|CERT|CNAME|DHCID|DLV|DNAME|DNSKEY|DS|EID|GID|GPOS|HINFO|HIP|IPSECKEY|ISDN|KEY|KX|LOC|MAILA|MAILB|MB|MD|MF|MG|MINFO|MR|MX|NAPTR|NB|NBSTAT|NIMLOC|NINFO|NS|NSAP|NSAP-PTR|NSEC|NSEC3|NSEC3PARAM|NULL|NXT|OPENPGPKEY|PTR|PX|RKEY|RP|RRSIG|RT|SIG|SINK|SMIMEA|SOA|SPF|SRV|SSHFP|TA|TKEY|TLSA|TSIG|TXT|UID|UINFO|UNSPEC|URI|WKS|X25)(?=\s|$)/,lookbehind:!0,alias:"keyword"},punctuation:/[()]/},Prism.languages["dns-zone"]=Prism.languages["dns-zone-file"]; +!function(e){var n="(?:[ \t]+(?![ \t])(?:)?|)".replace(//g,(function(){return"\\\\[\r\n](?:\\s|\\\\[\r\n]|#.*(?!.))*(?![\\s#]|\\\\[\r\n])"})),r="\"(?:[^\"\\\\\r\n]|\\\\(?:\r\n|[^]))*\"|'(?:[^'\\\\\r\n]|\\\\(?:\r\n|[^]))*'",t="--[\\w-]+=(?:|(?![\"'])(?:[^\\s\\\\]|\\\\.)+)".replace(//g,(function(){return r})),o={pattern:RegExp(r),greedy:!0},i={pattern:/(^[ \t]*)#.*/m,lookbehind:!0,greedy:!0};function a(e,r){return e=e.replace(//g,(function(){return t})).replace(//g,(function(){return n})),RegExp(e,r)}e.languages.docker={instruction:{pattern:/(^[ \t]*)(?:ADD|ARG|CMD|COPY|ENTRYPOINT|ENV|EXPOSE|FROM|HEALTHCHECK|LABEL|MAINTAINER|ONBUILD|RUN|SHELL|STOPSIGNAL|USER|VOLUME|WORKDIR)(?=\s)(?:\\.|[^\r\n\\])*(?:\\$(?:\s|#.*$)*(?![\s#])(?:\\.|[^\r\n\\])*)*/im,lookbehind:!0,greedy:!0,inside:{options:{pattern:a("(^(?:ONBUILD)?\\w+)(?:)*","i"),lookbehind:!0,greedy:!0,inside:{property:{pattern:/(^|\s)--[\w-]+/,lookbehind:!0},string:[o,{pattern:/(=)(?!["'])(?:[^\s\\]|\\.)+/,lookbehind:!0}],operator:/\\$/m,punctuation:/=/}},keyword:[{pattern:a("(^(?:ONBUILD)?HEALTHCHECK(?:)*)(?:CMD|NONE)\\b","i"),lookbehind:!0,greedy:!0},{pattern:a("(^(?:ONBUILD)?FROM(?:)*(?!--)[^ \t\\\\]+)AS","i"),lookbehind:!0,greedy:!0},{pattern:a("(^ONBUILD)\\w+","i"),lookbehind:!0,greedy:!0},{pattern:/^\w+/,greedy:!0}],comment:i,string:o,variable:/\$(?:\w+|\{[^{}"'\\]*\})/,operator:/\\$/m}},comment:i},e.languages.dockerfile=e.languages.docker}(Prism); +!function(e){var a="(?:"+["[a-zA-Z_\\x80-\\uFFFF][\\w\\x80-\\uFFFF]*","-?(?:\\.\\d+|\\d+(?:\\.\\d*)?)",'"[^"\\\\]*(?:\\\\[^][^"\\\\]*)*"',"<(?:[^<>]|(?!\x3c!--)<(?:[^<>\"']|\"[^\"]*\"|'[^']*')+>|\x3c!--(?:[^-]|-(?!->))*--\x3e)*>"].join("|")+")",n={markup:{pattern:/(^<)[\s\S]+(?=>$)/,lookbehind:!0,alias:["language-markup","language-html","language-xml"],inside:e.languages.markup}};function r(e,n){return RegExp(e.replace(//g,(function(){return a})),n)}e.languages.dot={comment:{pattern:/\/\/.*|\/\*[\s\S]*?\*\/|^#.*/m,greedy:!0},"graph-name":{pattern:r("(\\b(?:digraph|graph|subgraph)[ \t\r\n]+)","i"),lookbehind:!0,greedy:!0,alias:"class-name",inside:n},"attr-value":{pattern:r("(=[ \t\r\n]*)"),lookbehind:!0,greedy:!0,inside:n},"attr-name":{pattern:r("([\\[;, \t\r\n])(?=[ \t\r\n]*=)"),lookbehind:!0,greedy:!0,inside:n},keyword:/\b(?:digraph|edge|graph|node|strict|subgraph)\b/i,"compass-point":{pattern:/(:[ \t\r\n]*)(?:[ewc_]|[ns][ew]?)(?![\w\x80-\uFFFF])/,lookbehind:!0,alias:"builtin"},node:{pattern:r("(^|[^-.\\w\\x80-\\uFFFF\\\\])"),lookbehind:!0,greedy:!0,inside:n},operator:/[=:]|-[->]/,punctuation:/[\[\]{};,]/},e.languages.gv=e.languages.dot}(Prism); +Prism.languages.elixir={doc:{pattern:/@(?:doc|moduledoc)\s+(?:("""|''')[\s\S]*?\1|("|')(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2)/,inside:{attribute:/^@\w+/,string:/['"][\s\S]+/}},comment:{pattern:/#.*/,greedy:!0},regex:{pattern:/~[rR](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|[^\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[uismxfr]*/,greedy:!0},string:[{pattern:/~[cCsSwW](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|#\{[^}]+\}|#(?!\{)|[^#\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[csa]?/,greedy:!0,inside:{}},{pattern:/("""|''')[\s\S]*?\1/,greedy:!0,inside:{}},{pattern:/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0,inside:{}}],atom:{pattern:/(^|[^:]):\w+/,lookbehind:!0,alias:"symbol"},module:{pattern:/\b[A-Z]\w*\b/,alias:"class-name"},"attr-name":/\b\w+\??:(?!:)/,argument:{pattern:/(^|[^&])&\d+/,lookbehind:!0,alias:"variable"},attribute:{pattern:/@\w+/,alias:"variable"},function:/\b[_a-zA-Z]\w*[?!]?(?:(?=\s*(?:\.\s*)?\()|(?=\/\d))/,number:/\b(?:0[box][a-f\d_]+|\d[\d_]*)(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?\b/i,keyword:/\b(?:after|alias|and|case|catch|cond|def(?:callback|delegate|exception|impl|macro|module|n|np|p|protocol|struct)?|do|else|end|fn|for|if|import|not|or|quote|raise|require|rescue|try|unless|unquote|use|when)\b/,boolean:/\b(?:false|nil|true)\b/,operator:[/\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/,{pattern:/([^<])<(?!<)/,lookbehind:!0},{pattern:/([^>])>(?!>)/,lookbehind:!0}],punctuation:/<<|>>|[.,%\[\]{}()]/},Prism.languages.elixir.string.forEach((function(e){e.inside={interpolation:{pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"},rest:Prism.languages.elixir}}}})); +Prism.languages.erlang={comment:/%.+/,string:{pattern:/"(?:\\.|[^\\"\r\n])*"/,greedy:!0},"quoted-function":{pattern:/'(?:\\.|[^\\'\r\n])+'(?=\()/,alias:"function"},"quoted-atom":{pattern:/'(?:\\.|[^\\'\r\n])+'/,alias:"atom"},boolean:/\b(?:false|true)\b/,keyword:/\b(?:after|begin|case|catch|end|fun|if|of|receive|try|when)\b/,number:[/\$\\?./,/\b\d+#[a-z0-9]+/i,/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i],function:/\b[a-z][\w@]*(?=\()/,variable:{pattern:/(^|[^@])(?:\b|\?)[A-Z_][\w@]*/,lookbehind:!0},operator:[/[=\/<>:]=|=[:\/]=|\+\+?|--?|[=*\/!]|\b(?:and|andalso|band|bnot|bor|bsl|bsr|bxor|div|not|or|orelse|rem|xor)\b/,{pattern:/(^|[^<])<(?!<)/,lookbehind:!0},{pattern:/(^|[^>])>(?!>)/,lookbehind:!0}],atom:/\b[a-z][\w@]*/,punctuation:/[()[\]{}:;,.#|]|<<|>>/}; +Prism.languages.git={comment:/^#.*/m,deleted:/^[-–].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m}; +Prism.languages.go=Prism.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),Prism.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete Prism.languages.go["class-name"]; +Prism.languages["go-mod"]=Prism.languages["go-module"]={comment:{pattern:/\/\/.*/,greedy:!0},version:{pattern:/(^|[\s()[\],])v\d+\.\d+\.\d+(?:[+-][-+.\w]*)?(?![^\s()[\],])/,lookbehind:!0,alias:"number"},"go-version":{pattern:/((?:^|\s)go\s+)\d+(?:\.\d+){1,2}/,lookbehind:!0,alias:"number"},keyword:{pattern:/^([ \t]*)(?:exclude|go|module|replace|require|retract)\b/m,lookbehind:!0},operator:/=>/,punctuation:/[()[\],]/}; +Prism.languages.hcl={comment:/(?:\/\/|#).*|\/\*[\s\S]*?(?:\*\/|$)/,heredoc:{pattern:/<<-?(\w+\b)[\s\S]*?^[ \t]*\1/m,greedy:!0,alias:"string"},keyword:[{pattern:/(?:data|resource)\s+(?:"(?:\\[\s\S]|[^\\"])*")(?=\s+"[\w-]+"\s+\{)/i,inside:{type:{pattern:/(resource|data|\s+)(?:"(?:\\[\s\S]|[^\\"])*")/i,lookbehind:!0,alias:"variable"}}},{pattern:/(?:backend|module|output|provider|provisioner|variable)\s+(?:[\w-]+|"(?:\\[\s\S]|[^\\"])*")\s+(?=\{)/i,inside:{type:{pattern:/(backend|module|output|provider|provisioner|variable)\s+(?:[\w-]+|"(?:\\[\s\S]|[^\\"])*")\s+/i,lookbehind:!0,alias:"variable"}}},/[\w-]+(?=\s+\{)/],property:[/[-\w\.]+(?=\s*=(?!=))/,/"(?:\\[\s\S]|[^\\"])+"(?=\s*[:=])/],string:{pattern:/"(?:[^\\$"]|\\[\s\S]|\$(?:(?=")|\$+(?!\$)|[^"${])|\$\{(?:[^{}"]|"(?:[^\\"]|\\[\s\S])*")*\})*"/,greedy:!0,inside:{interpolation:{pattern:/(^|[^$])\$\{(?:[^{}"]|"(?:[^\\"]|\\[\s\S])*")*\}/,lookbehind:!0,inside:{type:{pattern:/(\b(?:count|data|local|module|path|self|terraform|var)\b\.)[\w\*]+/i,lookbehind:!0,alias:"variable"},keyword:/\b(?:count|data|local|module|path|self|terraform|var)\b/i,function:/\w+(?=\()/,string:{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0},number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?(?:e[+-]?\d+)?/i,punctuation:/[!\$#%&'()*+,.\/;<=>@\[\\\]^`{|}~?:]/}}}},number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?(?:e[+-]?\d+)?/i,boolean:/\b(?:false|true)\b/i,punctuation:/[=\[\]{}]/}; +Prism.languages.ini={comment:{pattern:/(^[ \f\t\v]*)[#;][^\n\r]*/m,lookbehind:!0},section:{pattern:/(^[ \f\t\v]*)\[[^\n\r\]]*\]?/m,lookbehind:!0,inside:{"section-name":{pattern:/(^\[[ \f\t\v]*)[^ \f\t\v\]]+(?:[ \f\t\v]+[^ \f\t\v\]]+)*/,lookbehind:!0,alias:"selector"},punctuation:/\[|\]/}},key:{pattern:/(^[ \f\t\v]*)[^ \f\n\r\t\v=]+(?:[ \f\t\v]+[^ \f\n\r\t\v=]+)*(?=[ \f\t\v]*=)/m,lookbehind:!0,alias:"attr-name"},value:{pattern:/(=[ \f\t\v]*)[^ \f\n\r\t\v]+(?:[ \f\t\v]+[^ \f\n\r\t\v]+)*/,lookbehind:!0,alias:"attr-value",inside:{"inner-value":{pattern:/^("|').+(?=\1$)/,lookbehind:!0}}},punctuation:/=/}; +!function(e){var n="\\\\\\((?:[^()]|\\([^()]*\\))*\\)",t=RegExp('(^|[^\\\\])"(?:[^"\r\n\\\\]|\\\\[^\r\n(]|__)*"'.replace(/__/g,(function(){return n}))),i={interpolation:{pattern:RegExp("((?:^|[^\\\\])(?:\\\\{2})*)"+n),lookbehind:!0,inside:{content:{pattern:/^(\\\()[\s\S]+(?=\)$)/,lookbehind:!0,inside:null},punctuation:/^\\\(|\)$/}}},a=e.languages.jq={comment:/#.*/,property:{pattern:RegExp(t.source+"(?=\\s*:(?!:))"),lookbehind:!0,greedy:!0,inside:i},string:{pattern:t,lookbehind:!0,greedy:!0,inside:i},function:{pattern:/(\bdef\s+)[a-z_]\w+/i,lookbehind:!0},variable:/\B\$\w+/,"property-literal":{pattern:/\b[a-z_]\w*(?=\s*:(?!:))/i,alias:"property"},keyword:/\b(?:as|break|catch|def|elif|else|end|foreach|if|import|include|label|module|modulemeta|null|reduce|then|try|while)\b/,boolean:/\b(?:false|true)\b/,number:/(?:\b\d+\.|\B\.)?\b\d+(?:[eE][+-]?\d+)?\b/,operator:[{pattern:/\|=?/,alias:"pipe"},/\.\.|[!=<>]?=|\?\/\/|\/\/=?|[-+*/%]=?|[<>?]|\b(?:and|not|or)\b/],"c-style-function":{pattern:/\b[a-z_]\w*(?=\s*\()/i,alias:"function"},punctuation:/::|[()\[\]{},:;]|\.(?=\s*[\[\w$])/,dot:{pattern:/\./,alias:"important"}};i.interpolation.inside.content.inside=a}(Prism); +Prism.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[^z]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+(?:\.[a-f\d]*)?(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|(?:\.\d*)?(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,function:/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/}; +Prism.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/}; +!function(n){function e(n){return n=n.replace(//g,(function(){return"(?:\\\\.|[^\\\\\n\r]|(?:\n|\r\n?)(?![\r\n]))"})),RegExp("((?:^|[^\\\\])(?:\\\\{2})*)(?:"+n+")")}var t="(?:\\\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\\\|\r\n`])+",a="\\|?__(?:\\|__)+\\|?(?:(?:\n|\r\n?)|(?![^]))".replace(/__/g,(function(){return t})),i="\\|?[ \t]*:?-{3,}:?[ \t]*(?:\\|[ \t]*:?-{3,}:?[ \t]*)+\\|?(?:\n|\r\n?)";n.languages.markdown=n.languages.extend("markup",{}),n.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:n.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+i+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+i+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(t),inside:n.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+i+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(t),alias:"important",inside:n.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:e("\\b__(?:(?!_)|_(?:(?!_))+_)+__\\b|\\*\\*(?:(?!\\*)|\\*(?:(?!\\*))+\\*)+\\*\\*"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:e("\\b_(?:(?!_)|__(?:(?!_))+__)+_\\b|\\*(?:(?!\\*)|\\*\\*(?:(?!\\*))+\\*\\*)+\\*"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:e("(~~?)(?:(?!~))+\\2"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:e('!?\\[(?:(?!\\]))+\\](?:\\([^\\s)]+(?:[\t ]+"(?:\\\\.|[^"\\\\])*")?\\)|[ \t]?\\[(?:(?!\\]))+\\])'),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(e){["url","bold","italic","strike","code-snippet"].forEach((function(t){e!==t&&(n.languages.markdown[e].inside.content.inside[t]=n.languages.markdown[t])}))})),n.hooks.add("after-tokenize",(function(n){"markdown"!==n.language&&"md"!==n.language||function n(e){if(e&&"string"!=typeof e)for(var t=0,a=e.length;t",quot:'"'},l=String.fromCodePoint||String.fromCharCode;n.languages.md=n.languages.markdown}(Prism); +!function(e){var n=/\$(?:\w[a-z\d]*(?:_[^\x00-\x1F\s"'\\()$]*)?|\{[^}\s"'\\]+\})/i;e.languages.nginx={comment:{pattern:/(^|[\s{};])#.*/,lookbehind:!0,greedy:!0},directive:{pattern:/(^|\s)\w(?:[^;{}"'\\\s]|\\.|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\s+(?:#.*(?!.)|(?![#\s])))*?(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:{string:{pattern:/((?:^|[^\\])(?:\\\\)*)(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,lookbehind:!0,greedy:!0,inside:{escape:{pattern:/\\["'\\nrt]/,alias:"entity"},variable:n}},comment:{pattern:/(\s)#.*/,lookbehind:!0,greedy:!0},keyword:{pattern:/^\S+/,greedy:!0},boolean:{pattern:/(\s)(?:off|on)(?!\S)/,lookbehind:!0},number:{pattern:/(\s)\d+[a-z]*(?!\S)/i,lookbehind:!0},variable:n}},punctuation:/[{};]/}}(Prism); +Prism.languages.properties={comment:/^[ \t]*[#!].*$/m,value:{pattern:/(^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+(?: *[=:] *(?! )| ))(?:\\(?:\r\n|[\s\S])|[^\\\r\n])+/m,lookbehind:!0,alias:"attr-value"},key:{pattern:/^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+(?= *[=:]| )/m,alias:"attr-name"},punctuation:/[=:]/}; +Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python; +Prism.languages.r={comment:/#.*/,string:{pattern:/(['"])(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},"percent-operator":{pattern:/%[^%\s]*%/,alias:"operator"},boolean:/\b(?:FALSE|TRUE)\b/,ellipsis:/\.\.(?:\.|\d+)/,number:[/\b(?:Inf|NaN)\b/,/(?:\b0x[\dA-Fa-f]+(?:\.\d*)?|\b\d+(?:\.\d*)?|\B\.\d+)(?:[EePp][+-]?\d+)?[iL]?/],keyword:/\b(?:NA|NA_character_|NA_complex_|NA_integer_|NA_real_|NULL|break|else|for|function|if|in|next|repeat|while)\b/,operator:/->?>?|<(?:=|=!]=?|::?|&&?|\|\|?|[+*\/^$@~]/,punctuation:/[(){}\[\],;]/}; +Prism.languages.rest={table:[{pattern:/(^[\t ]*)(?:\+[=-]+)+\+(?:\r?\n|\r)(?:\1[+|].+[+|](?:\r?\n|\r))+\1(?:\+[=-]+)+\+/m,lookbehind:!0,inside:{punctuation:/\||(?:\+[=-]+)+\+/}},{pattern:/(^[\t ]*)=+ [ =]*=(?:(?:\r?\n|\r)\1.+)+(?:\r?\n|\r)\1=+ [ =]*=(?=(?:\r?\n|\r){2}|\s*$)/m,lookbehind:!0,inside:{punctuation:/[=-]+/}}],"substitution-def":{pattern:/(^[\t ]*\.\. )\|(?:[^|\s](?:[^|]*[^|\s])?)\| [^:]+::/m,lookbehind:!0,inside:{substitution:{pattern:/^\|(?:[^|\s]|[^|\s][^|]*[^|\s])\|/,alias:"attr-value",inside:{punctuation:/^\||\|$/}},directive:{pattern:/( )(?! )[^:]+::/,lookbehind:!0,alias:"function",inside:{punctuation:/::$/}}}},"link-target":[{pattern:/(^[\t ]*\.\. )\[[^\]]+\]/m,lookbehind:!0,alias:"string",inside:{punctuation:/^\[|\]$/}},{pattern:/(^[\t ]*\.\. )_(?:`[^`]+`|(?:[^:\\]|\\.)+):/m,lookbehind:!0,alias:"string",inside:{punctuation:/^_|:$/}}],directive:{pattern:/(^[\t ]*\.\. )[^:]+::/m,lookbehind:!0,alias:"function",inside:{punctuation:/::$/}},comment:{pattern:/(^[\t ]*\.\.)(?:(?: .+)?(?:(?:\r?\n|\r).+)+| .+)(?=(?:\r?\n|\r){2}|$)/m,lookbehind:!0},title:[{pattern:/^(([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2+)(?:\r?\n|\r).+(?:\r?\n|\r)\1$/m,inside:{punctuation:/^[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+|[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+$/,important:/.+/}},{pattern:/(^|(?:\r?\n|\r){2}).+(?:\r?\n|\r)([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2+(?=\r?\n|\r|$)/,lookbehind:!0,inside:{punctuation:/[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+$/,important:/.+/}}],hr:{pattern:/((?:\r?\n|\r){2})([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2{3,}(?=(?:\r?\n|\r){2})/,lookbehind:!0,alias:"punctuation"},field:{pattern:/(^[\t ]*):[^:\r\n]+:(?= )/m,lookbehind:!0,alias:"attr-name"},"command-line-option":{pattern:/(^[\t ]*)(?:[+-][a-z\d]|(?:--|\/)[a-z\d-]+)(?:[ =](?:[a-z][\w-]*|<[^<>]+>))?(?:, (?:[+-][a-z\d]|(?:--|\/)[a-z\d-]+)(?:[ =](?:[a-z][\w-]*|<[^<>]+>))?)*(?=(?:\r?\n|\r)? {2,}\S)/im,lookbehind:!0,alias:"symbol"},"literal-block":{pattern:/::(?:\r?\n|\r){2}([ \t]+)(?![ \t]).+(?:(?:\r?\n|\r)\1.+)*/,inside:{"literal-block-punctuation":{pattern:/^::/,alias:"punctuation"}}},"quoted-literal-block":{pattern:/::(?:\r?\n|\r){2}([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]).*(?:(?:\r?\n|\r)\1.*)*/,inside:{"literal-block-punctuation":{pattern:/^(?:::|([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\1*)/m,alias:"punctuation"}}},"list-bullet":{pattern:/(^[\t ]*)(?:[*+\-•‣⁃]|\(?(?:\d+|[a-z]|[ivxdclm]+)\)|(?:\d+|[a-z]|[ivxdclm]+)\.)(?= )/im,lookbehind:!0,alias:"punctuation"},"doctest-block":{pattern:/(^[\t ]*)>>> .+(?:(?:\r?\n|\r).+)*/m,lookbehind:!0,inside:{punctuation:/^>>>/}},inline:[{pattern:/(^|[\s\-:\/'"<(\[{])(?::[^:]+:`.*?`|`.*?`:[^:]+:|(\*\*?|``?|\|)(?!\s)(?:(?!\2).)*\S\2(?=[\s\-.,:;!?\\\/'")\]}]|$))/m,lookbehind:!0,inside:{bold:{pattern:/(^\*\*).+(?=\*\*$)/,lookbehind:!0},italic:{pattern:/(^\*).+(?=\*$)/,lookbehind:!0},"inline-literal":{pattern:/(^``).+(?=``$)/,lookbehind:!0,alias:"symbol"},role:{pattern:/^:[^:]+:|:[^:]+:$/,alias:"function",inside:{punctuation:/^:|:$/}},"interpreted-text":{pattern:/(^`).+(?=`$)/,lookbehind:!0,alias:"attr-value"},substitution:{pattern:/(^\|).+(?=\|$)/,lookbehind:!0,alias:"attr-value"},punctuation:/\*\*?|``?|\|/}}],link:[{pattern:/\[[^\[\]]+\]_(?=[\s\-.,:;!?\\\/'")\]}]|$)/,alias:"string",inside:{punctuation:/^\[|\]_$/}},{pattern:/(?:\b[a-z\d]+(?:[_.:+][a-z\d]+)*_?_|`[^`]+`_?_|_`[^`]+`)(?=[\s\-.,:;!?\\\/'")\]}]|$)/i,alias:"string",inside:{punctuation:/^_?`|`$|`?_?_$/}}],punctuation:{pattern:/(^[\t ]*)(?:\|(?= |$)|(?:---?|—|\.\.|__)(?= )|\.\.$)/m,lookbehind:!0}}; +Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/}; +!function(e){function n(e){return e.replace(/__/g,(function(){return"(?:[\\w-]+|'[^'\n\r]*'|\"(?:\\\\.|[^\\\\\"\r\n])*\")"}))}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n("(^[\t ]*\\[\\s*(?:\\[\\s*)?)__(?:\\s*\\.\\s*__)*(?=\\s*\\])"),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n("(^[\t ]*|[{,]\\s*)__(?:\\s*\\.\\s*__)*(?=\\s*=)"),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:false|true)\b/,punctuation:/[.,=[\]{}]/}}(Prism); +Prism.languages.vim={string:/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\r\n]|'')*'/,comment:/".*/,function:/\b\w+(?=\()/,keyword:/\b(?:N|Next|P|Print|X|XMLent|XMLns|ab|abbreviate|abc|abclear|abo|aboveleft|al|all|ar|arga|argadd|argd|argdelete|argdo|arge|argedit|argg|argglobal|argl|arglocal|args|argu|argument|as|ascii|b|bN|bNext|ba|bad|badd|ball|bd|bdelete|be|bel|belowright|bf|bfirst|bl|blast|bm|bmodified|bn|bnext|bo|botright|bp|bprevious|br|brea|break|breaka|breakadd|breakd|breakdel|breakl|breaklist|brewind|bro|browse|bufdo|buffer|buffers|bun|bunload|bw|bwipeout|c|cN|cNext|cNfcNfile|ca|cabbrev|cabc|cabclear|cad|caddb|caddbuffer|caddexpr|caddf|caddfile|cal|call|cat|catch|cb|cbuffer|cc|ccl|cclose|cd|ce|center|cex|cexpr|cf|cfile|cfir|cfirst|cg|cgetb|cgetbuffer|cgete|cgetexpr|cgetfile|change|changes|chd|chdir|che|checkpath|checkt|checktime|cl|cla|clast|clist|clo|close|cmapc|cmapclear|cn|cnew|cnewer|cnext|cnf|cnfile|cnorea|cnoreabbrev|co|col|colder|colo|colorscheme|comc|comclear|comp|compiler|con|conf|confirm|continue|cope|copen|copy|cp|cpf|cpfile|cprevious|cq|cquit|cr|crewind|cu|cuna|cunabbrev|cunmap|cw|cwindow|d|debugg|debuggreedy|delc|delcommand|delete|delf|delfunction|delm|delmarks|di|diffg|diffget|diffoff|diffpatch|diffpu|diffput|diffsplit|diffthis|diffu|diffupdate|dig|digraphs|display|dj|djump|dl|dlist|dr|drop|ds|dsearch|dsp|dsplit|e|earlier|echoe|echoerr|echom|echomsg|echon|edit|el|else|elsei|elseif|em|emenu|en|endf|endfo|endfor|endfun|endfunction|endif|endt|endtry|endw|endwhile|ene|enew|ex|exi|exit|exu|exusage|f|file|files|filetype|fin|fina|finally|find|fini|finish|fir|first|fix|fixdel|fo|fold|foldc|foldclose|foldd|folddoc|folddoclosed|folddoopen|foldo|foldopen|for|fu|fun|function|go|goto|gr|grep|grepa|grepadd|h|ha|hardcopy|help|helpf|helpfind|helpg|helpgrep|helpt|helptags|hid|hide|his|history|ia|iabbrev|iabc|iabclear|if|ij|ijump|il|ilist|imapc|imapclear|in|inorea|inoreabbrev|isearch|isp|isplit|iu|iuna|iunabbrev|iunmap|j|join|ju|jumps|k|kee|keepalt|keepj|keepjumps|keepmarks|l|lN|lNext|lNf|lNfile|la|lad|laddb|laddbuffer|laddexpr|laddf|laddfile|lan|language|last|later|lb|lbuffer|lc|lcd|lch|lchdir|lcl|lclose|left|lefta|leftabove|let|lex|lexpr|lf|lfile|lfir|lfirst|lg|lgetb|lgetbuffer|lgete|lgetexpr|lgetfile|lgr|lgrep|lgrepa|lgrepadd|lh|lhelpgrep|list|ll|lla|llast|lli|llist|lm|lmak|lmake|lmap|lmapc|lmapclear|ln|lne|lnew|lnewer|lnext|lnf|lnfile|lnoremap|lo|loadview|loc|lockmarks|lockv|lockvar|lol|lolder|lop|lopen|lp|lpf|lpfile|lprevious|lr|lrewind|ls|lt|ltag|lu|lunmap|lv|lvimgrep|lvimgrepa|lvimgrepadd|lw|lwindow|m|ma|mak|make|mark|marks|mat|match|menut|menutranslate|mk|mkexrc|mks|mksession|mksp|mkspell|mkv|mkvie|mkview|mkvimrc|mod|mode|move|mz|mzf|mzfile|mzscheme|n|nbkey|new|next|nmapc|nmapclear|noh|nohlsearch|norea|noreabbrev|nu|number|nun|nunmap|o|omapc|omapclear|on|only|open|opt|options|ou|ounmap|p|pc|pclose|pe|ped|pedit|perl|perld|perldo|po|pop|popu|popup|pp|ppop|pre|preserve|prev|previous|print|prof|profd|profdel|profile|promptf|promptfind|promptr|promptrepl|ps|psearch|ptN|ptNext|pta|ptag|ptf|ptfirst|ptj|ptjump|ptl|ptlast|ptn|ptnext|ptp|ptprevious|ptr|ptrewind|pts|ptselect|pu|put|pw|pwd|py|pyf|pyfile|python|q|qa|qall|quit|quita|quitall|r|read|rec|recover|red|redi|redir|redo|redr|redraw|redraws|redrawstatus|reg|registers|res|resize|ret|retab|retu|return|rew|rewind|ri|right|rightb|rightbelow|ru|rub|ruby|rubyd|rubydo|rubyf|rubyfile|runtime|rv|rviminfo|sN|sNext|sa|sal|sall|san|sandbox|sargument|sav|saveas|sb|sbN|sbNext|sba|sball|sbf|sbfirst|sbl|sblast|sbm|sbmodified|sbn|sbnext|sbp|sbprevious|sbr|sbrewind|sbuffer|scrip|scripte|scriptencoding|scriptnames|se|set|setf|setfiletype|setg|setglobal|setl|setlocal|sf|sfind|sfir|sfirst|sh|shell|sign|sil|silent|sim|simalt|sl|sla|slast|sleep|sm|smagic|smap|smapc|smapclear|sme|smenu|sn|snext|sni|sniff|sno|snomagic|snor|snoremap|snoreme|snoremenu|so|sor|sort|source|sp|spe|spelld|spelldump|spellgood|spelli|spellinfo|spellr|spellrepall|spellu|spellundo|spellw|spellwrong|split|spr|sprevious|sre|srewind|st|sta|stag|star|startg|startgreplace|startinsert|startr|startreplace|stj|stjump|stop|stopi|stopinsert|sts|stselect|sun|sunhide|sunm|sunmap|sus|suspend|sv|sview|syncbind|t|tN|tNext|ta|tab|tabN|tabNext|tabc|tabclose|tabd|tabdo|tabe|tabedit|tabf|tabfind|tabfir|tabfirst|tabl|tablast|tabm|tabmove|tabn|tabnew|tabnext|tabo|tabonly|tabp|tabprevious|tabr|tabrewind|tabs|tag|tags|tc|tcl|tcld|tcldo|tclf|tclfile|te|tearoff|tf|tfirst|th|throw|tj|tjump|tl|tlast|tm|tmenu|tn|tnext|to|topleft|tp|tprevious|tr|trewind|try|ts|tselect|tu|tunmenu|u|una|unabbreviate|undo|undoj|undojoin|undol|undolist|unh|unhide|unlet|unlo|unlockvar|unm|unmap|up|update|ve|verb|verbose|version|vert|vertical|vi|vie|view|vim|vimgrep|vimgrepa|vimgrepadd|visual|viu|viusage|vmapc|vmapclear|vne|vnew|vs|vsplit|vu|vunmap|w|wN|wNext|wa|wall|wh|while|win|winc|wincmd|windo|winp|winpos|winsize|wn|wnext|wp|wprevious|wq|wqa|wqall|write|ws|wsverb|wv|wviminfo|x|xa|xall|xit|xm|xmap|xmapc|xmapclear|xme|xmenu|xn|xnoremap|xnoreme|xnoremenu|xu|xunmap|y|yank)\b/,builtin:/\b(?:acd|ai|akm|aleph|allowrevins|altkeymap|ambiwidth|ambw|anti|antialias|arab|arabic|arabicshape|ari|arshape|autochdir|autocmd|autoindent|autoread|autowrite|autowriteall|aw|awa|background|backspace|backup|backupcopy|backupdir|backupext|backupskip|balloondelay|ballooneval|balloonexpr|bdir|bdlay|beval|bex|bexpr|bg|bh|bin|binary|biosk|bioskey|bk|bkc|bomb|breakat|brk|browsedir|bs|bsdir|bsk|bt|bufhidden|buflisted|buftype|casemap|ccv|cdpath|cedit|cfu|ch|charconvert|ci|cin|cindent|cink|cinkeys|cino|cinoptions|cinw|cinwords|clipboard|cmdheight|cmdwinheight|cmp|cms|columns|com|comments|commentstring|compatible|complete|completefunc|completeopt|consk|conskey|copyindent|cot|cpo|cpoptions|cpt|cscopepathcomp|cscopeprg|cscopequickfix|cscopetag|cscopetagorder|cscopeverbose|cspc|csprg|csqf|cst|csto|csverb|cuc|cul|cursorcolumn|cursorline|cwh|debug|deco|def|define|delcombine|dex|dg|dict|dictionary|diff|diffexpr|diffopt|digraph|dip|dir|directory|dy|ea|ead|eadirection|eb|ed|edcompatible|ef|efm|ei|ek|enc|encoding|endofline|eol|ep|equalalways|equalprg|errorbells|errorfile|errorformat|esckeys|et|eventignore|expandtab|exrc|fcl|fcs|fdc|fde|fdi|fdl|fdls|fdm|fdn|fdo|fdt|fen|fenc|fencs|fex|ff|ffs|fileencoding|fileencodings|fileformat|fileformats|fillchars|fk|fkmap|flp|fml|fmr|foldcolumn|foldenable|foldexpr|foldignore|foldlevel|foldlevelstart|foldmarker|foldmethod|foldminlines|foldnestmax|foldtext|formatexpr|formatlistpat|formatoptions|formatprg|fp|fs|fsync|ft|gcr|gd|gdefault|gfm|gfn|gfs|gfw|ghr|gp|grepformat|grepprg|gtl|gtt|guicursor|guifont|guifontset|guifontwide|guiheadroom|guioptions|guipty|guitablabel|guitabtooltip|helpfile|helpheight|helplang|hf|hh|hi|hidden|highlight|hk|hkmap|hkmapp|hkp|hl|hlg|hls|hlsearch|ic|icon|iconstring|ignorecase|im|imactivatekey|imak|imc|imcmdline|imd|imdisable|imi|iminsert|ims|imsearch|inc|include|includeexpr|incsearch|inde|indentexpr|indentkeys|indk|inex|inf|infercase|insertmode|invacd|invai|invakm|invallowrevins|invaltkeymap|invanti|invantialias|invar|invarab|invarabic|invarabicshape|invari|invarshape|invautochdir|invautoindent|invautoread|invautowrite|invautowriteall|invaw|invawa|invbackup|invballooneval|invbeval|invbin|invbinary|invbiosk|invbioskey|invbk|invbl|invbomb|invbuflisted|invcf|invci|invcin|invcindent|invcompatible|invconfirm|invconsk|invconskey|invcopyindent|invcp|invcscopetag|invcscopeverbose|invcst|invcsverb|invcuc|invcul|invcursorcolumn|invcursorline|invdeco|invdelcombine|invdg|invdiff|invdigraph|invdisable|invea|inveb|inved|invedcompatible|invek|invendofline|inveol|invequalalways|inverrorbells|invesckeys|invet|invex|invexpandtab|invexrc|invfen|invfk|invfkmap|invfoldenable|invgd|invgdefault|invguipty|invhid|invhidden|invhk|invhkmap|invhkmapp|invhkp|invhls|invhlsearch|invic|invicon|invignorecase|invim|invimc|invimcmdline|invimd|invincsearch|invinf|invinfercase|invinsertmode|invis|invjoinspaces|invjs|invlazyredraw|invlbr|invlinebreak|invlisp|invlist|invloadplugins|invlpl|invlz|invma|invmacatsui|invmagic|invmh|invml|invmod|invmodeline|invmodifiable|invmodified|invmore|invmousef|invmousefocus|invmousehide|invnu|invnumber|invodev|invopendevice|invpaste|invpi|invpreserveindent|invpreviewwindow|invprompt|invpvw|invreadonly|invremap|invrestorescreen|invrevins|invri|invrightleft|invrightleftcmd|invrl|invrlc|invro|invrs|invru|invruler|invsb|invsc|invscb|invscrollbind|invscs|invsecure|invsft|invshellslash|invshelltemp|invshiftround|invshortname|invshowcmd|invshowfulltag|invshowmatch|invshowmode|invsi|invsm|invsmartcase|invsmartindent|invsmarttab|invsmd|invsn|invsol|invspell|invsplitbelow|invsplitright|invspr|invsr|invssl|invsta|invstartofline|invstmp|invswapfile|invswf|invta|invtagbsearch|invtagrelative|invtagstack|invtbi|invtbidi|invtbs|invtermbidi|invterse|invtextauto|invtextmode|invtf|invtgst|invtildeop|invtimeout|invtitle|invto|invtop|invtr|invttimeout|invttybuiltin|invttyfast|invtx|invvb|invvisualbell|invwa|invwarn|invwb|invweirdinvert|invwfh|invwfw|invwildmenu|invwinfixheight|invwinfixwidth|invwiv|invwmnu|invwrap|invwrapscan|invwrite|invwriteany|invwritebackup|invws|isf|isfname|isi|isident|isk|iskeyword|isprint|joinspaces|js|key|keymap|keymodel|keywordprg|km|kmp|kp|langmap|langmenu|laststatus|lazyredraw|lbr|lcs|linebreak|lines|linespace|lisp|lispwords|listchars|loadplugins|lpl|lsp|lz|macatsui|magic|makeef|makeprg|matchpairs|matchtime|maxcombine|maxfuncdepth|maxmapdepth|maxmem|maxmempattern|maxmemtot|mco|mef|menuitems|mfd|mh|mis|mkspellmem|ml|mls|mm|mmd|mmp|mmt|modeline|modelines|modifiable|modified|more|mouse|mousef|mousefocus|mousehide|mousem|mousemodel|mouses|mouseshape|mouset|mousetime|mp|mps|msm|mzq|mzquantum|nf|noacd|noai|noakm|noallowrevins|noaltkeymap|noanti|noantialias|noar|noarab|noarabic|noarabicshape|noari|noarshape|noautochdir|noautoindent|noautoread|noautowrite|noautowriteall|noaw|noawa|nobackup|noballooneval|nobeval|nobin|nobinary|nobiosk|nobioskey|nobk|nobl|nobomb|nobuflisted|nocf|noci|nocin|nocindent|nocompatible|noconfirm|noconsk|noconskey|nocopyindent|nocp|nocscopetag|nocscopeverbose|nocst|nocsverb|nocuc|nocul|nocursorcolumn|nocursorline|nodeco|nodelcombine|nodg|nodiff|nodigraph|nodisable|noea|noeb|noed|noedcompatible|noek|noendofline|noeol|noequalalways|noerrorbells|noesckeys|noet|noex|noexpandtab|noexrc|nofen|nofk|nofkmap|nofoldenable|nogd|nogdefault|noguipty|nohid|nohidden|nohk|nohkmap|nohkmapp|nohkp|nohls|noic|noicon|noignorecase|noim|noimc|noimcmdline|noimd|noincsearch|noinf|noinfercase|noinsertmode|nois|nojoinspaces|nojs|nolazyredraw|nolbr|nolinebreak|nolisp|nolist|noloadplugins|nolpl|nolz|noma|nomacatsui|nomagic|nomh|noml|nomod|nomodeline|nomodifiable|nomodified|nomore|nomousef|nomousefocus|nomousehide|nonu|nonumber|noodev|noopendevice|nopaste|nopi|nopreserveindent|nopreviewwindow|noprompt|nopvw|noreadonly|noremap|norestorescreen|norevins|nori|norightleft|norightleftcmd|norl|norlc|noro|nors|noru|noruler|nosb|nosc|noscb|noscrollbind|noscs|nosecure|nosft|noshellslash|noshelltemp|noshiftround|noshortname|noshowcmd|noshowfulltag|noshowmatch|noshowmode|nosi|nosm|nosmartcase|nosmartindent|nosmarttab|nosmd|nosn|nosol|nospell|nosplitbelow|nosplitright|nospr|nosr|nossl|nosta|nostartofline|nostmp|noswapfile|noswf|nota|notagbsearch|notagrelative|notagstack|notbi|notbidi|notbs|notermbidi|noterse|notextauto|notextmode|notf|notgst|notildeop|notimeout|notitle|noto|notop|notr|nottimeout|nottybuiltin|nottyfast|notx|novb|novisualbell|nowa|nowarn|nowb|noweirdinvert|nowfh|nowfw|nowildmenu|nowinfixheight|nowinfixwidth|nowiv|nowmnu|nowrap|nowrapscan|nowrite|nowriteany|nowritebackup|nows|nrformats|numberwidth|nuw|odev|oft|ofu|omnifunc|opendevice|operatorfunc|opfunc|osfiletype|pa|para|paragraphs|paste|pastetoggle|patchexpr|patchmode|path|pdev|penc|pex|pexpr|pfn|ph|pheader|pi|pm|pmbcs|pmbfn|popt|preserveindent|previewheight|previewwindow|printdevice|printencoding|printexpr|printfont|printheader|printmbcharset|printmbfont|printoptions|prompt|pt|pumheight|pvh|pvw|qe|quoteescape|readonly|remap|report|restorescreen|revins|rightleft|rightleftcmd|rl|rlc|ro|rs|rtp|ruf|ruler|rulerformat|runtimepath|sbo|sc|scb|scr|scroll|scrollbind|scrolljump|scrolloff|scrollopt|scs|sect|sections|secure|sel|selection|selectmode|sessionoptions|sft|shcf|shellcmdflag|shellpipe|shellquote|shellredir|shellslash|shelltemp|shelltype|shellxquote|shiftround|shiftwidth|shm|shortmess|shortname|showbreak|showcmd|showfulltag|showmatch|showmode|showtabline|shq|si|sidescroll|sidescrolloff|siso|sj|slm|smartcase|smartindent|smarttab|smc|smd|softtabstop|sol|spc|spell|spellcapcheck|spellfile|spelllang|spellsuggest|spf|spl|splitbelow|splitright|sps|sr|srr|ss|ssl|ssop|stal|startofline|statusline|stl|stmp|su|sua|suffixes|suffixesadd|sw|swapfile|swapsync|swb|swf|switchbuf|sws|sxq|syn|synmaxcol|syntax|t_AB|t_AF|t_AL|t_CS|t_CV|t_Ce|t_Co|t_Cs|t_DL|t_EI|t_F1|t_F2|t_F3|t_F4|t_F5|t_F6|t_F7|t_F8|t_F9|t_IE|t_IS|t_K1|t_K3|t_K4|t_K5|t_K6|t_K7|t_K8|t_K9|t_KA|t_KB|t_KC|t_KD|t_KE|t_KF|t_KG|t_KH|t_KI|t_KJ|t_KK|t_KL|t_RI|t_RV|t_SI|t_Sb|t_Sf|t_WP|t_WS|t_ZH|t_ZR|t_al|t_bc|t_cd|t_ce|t_cl|t_cm|t_cs|t_da|t_db|t_dl|t_fs|t_k1|t_k2|t_k3|t_k4|t_k5|t_k6|t_k7|t_k8|t_k9|t_kB|t_kD|t_kI|t_kN|t_kP|t_kb|t_kd|t_ke|t_kh|t_kl|t_kr|t_ks|t_ku|t_le|t_mb|t_md|t_me|t_mr|t_ms|t_nd|t_op|t_se|t_so|t_sr|t_te|t_ti|t_ts|t_ue|t_us|t_ut|t_vb|t_ve|t_vi|t_vs|t_xs|tabline|tabpagemax|tabstop|tagbsearch|taglength|tagrelative|tagstack|tal|tb|tbi|tbidi|tbis|tbs|tenc|term|termbidi|termencoding|terse|textauto|textmode|textwidth|tgst|thesaurus|tildeop|timeout|timeoutlen|title|titlelen|titleold|titlestring|toolbar|toolbariconsize|top|tpm|tsl|tsr|ttimeout|ttimeoutlen|ttm|tty|ttybuiltin|ttyfast|ttym|ttymouse|ttyscroll|ttytype|tw|tx|uc|ul|undolevels|updatecount|updatetime|ut|vb|vbs|vdir|verbosefile|vfile|viewdir|viewoptions|viminfo|virtualedit|visualbell|vop|wak|warn|wb|wc|wcm|wd|weirdinvert|wfh|wfw|whichwrap|wi|wig|wildchar|wildcharm|wildignore|wildmenu|wildmode|wildoptions|wim|winaltkeys|window|winfixheight|winfixwidth|winheight|winminheight|winminwidth|winwidth|wiv|wiw|wm|wmh|wmnu|wmw|wop|wrap|wrapmargin|wrapscan|writeany|writebackup|writedelay|ww)\b/,number:/\b(?:0x[\da-f]+|\d+(?:\.\d+)?)\b/i,operator:/\|\||&&|[-+.]=?|[=!](?:[=~][#?]?)?|[<>]=?[#?]?|[*\/%?]|\b(?:is(?:not)?)\b/,punctuation:/[{}[\](),;:]/}; +!function(e){var n=/[*&][^\s[\]{},]+/,r=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,t="(?:"+r.source+"(?:[ \t]+"+n.source+")?|"+n.source+"(?:[ \t]+"+r.source+")?)",a="(?:[^\\s\\x00-\\x08\\x0e-\\x1f!\"#%&'*,\\-:>?@[\\]`{|}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*".replace(//g,(function(){return"[^\\s\\x00-\\x08\\x0e-\\x1f,[\\]{}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]"})),d="\"(?:[^\"\\\\\r\n]|\\\\.)*\"|'(?:[^'\\\\\r\n]|\\\\.)*'";function o(e,n){n=(n||"").replace(/m/g,"")+"m";var r="([:\\-,[{]\\s*(?:\\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\\]|\\}|(?:[\r\n]\\s*)?#))".replace(/<>/g,(function(){return t})).replace(/<>/g,(function(){return e}));return RegExp(r,n)}e.languages.yaml={scalar:{pattern:RegExp("([\\-:]\\s*(?:\\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\\S[^\r\n]*(?:\\2[^\r\n]+)*)".replace(/<>/g,(function(){return t}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp("((?:^|[:\\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\\s*:\\s)".replace(/<>/g,(function(){return t})).replace(/<>/g,(function(){return"(?:"+a+"|"+d+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:o("\\d{4}-\\d\\d?-\\d\\d?(?:[tT]|[ \t]+)\\d\\d?:\\d{2}:\\d{2}(?:\\.\\d*)?(?:[ \t]*(?:Z|[-+]\\d\\d?(?::\\d{2})?))?|\\d{4}-\\d{2}-\\d{2}|\\d\\d?:\\d{2}(?::\\d{2}(?:\\.\\d*)?)?"),lookbehind:!0,alias:"number"},boolean:{pattern:o("false|true","i"),lookbehind:!0,alias:"important"},null:{pattern:o("null|~","i"),lookbehind:!0,alias:"important"},string:{pattern:o(d),lookbehind:!0,greedy:!0},number:{pattern:o("[+-]?(?:0x[\\da-f]+|0o[0-7]+|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?|\\.inf|\\.nan)","i"),lookbehind:!0},tag:r,important:n,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(Prism); diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 00000000..320ce9d1 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,124 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ["./templates/*.html"], + plugins: [require("@tailwindcss/typography")], + variants: { + typography: ["dark"], + }, + theme: { + fontFamily: { + texts: ["Erode", "serif"], + headings: ["Fira Sans", "sans-serif"], + tags: ["ui-sans-serif", "sans-serif"], + }, + extend: { + // NOTE: this is for non-prose (so not Markdown rendered with typography plugin) + colors: { + // https://rosepinetheme.com/palette/ + "rp-dawn-base": "#faf4ed", // main background + "rp-dawn-surface": "#fffaf3", // navigation background + "rp-dawn-overlay": "#f2e9e1", // content background + "rp-dawn-muted": "#9893a5", + "rp-dawn-subtle": "#797593", + "rp-dawn-text": "#575279", // text + "rp-dawn-love": "#b4637a", + "rp-dawn-gold": "#ea9d34", + "rp-dawn-rose": "#d7827e", + "rp-dawn-pine": "#286983", + "rp-dawn-foam": "#56949f", // main site title + "rp-dawn-iris": "#907aa9", // links + "rp-dawn-highlight-low": "#f4ede8", + "rp-dawn-highlight-med": "#dfdad9", // footer + "rp-dawn-highlight-high": "#cecacd", + "rp-moon-base": "#232136", // main background + "rp-moon-surface": "#2a273f", // navigation background + "rp-moon-overlay": "#393552", // content background + "rp-moon-muted": "#6e6a86", + "rp-moon-subtle": "#908caa", + "rp-moon-text": "#e0def4", + "rp-moon-love": "#eb6f92", + "rp-moon-gold": "#f6c177", + "rp-moon-rose": "#ea9a97", + "rp-moon-pine": "#3e8fb0", + "rp-moon-foam": "#9ccfd8", // main site title + "rp-moon-iris": "#c4a7e7", // text, + "rp-moon-highlight-low": "#2a283e", + "rp-moon-highlight-med": "#44415a", // footer + "rp-moon-highlight-high": "#56526e", + }, + typography: (theme) => ({ + // NOTE: This is for prose (Markdown) in LIGHT mode + DEFAULT: { + css: { + pre: null, + code: null, + "code::before": null, + "code::after": null, + "pre code": null, + "pre code::before": null, + "pre code::after": null, + // remove backticks from typography for inline code + "code::before": { + content: '""', + }, + "code::after": { + content: '""', + }, + color: theme("colors.rp-dawn-text"), // main text + a: { + color: theme("colors.rp-dawn-text"), // align w/ in.css + "text-decoration-color": theme( + "colors.rp-dawn-gold", + ), // align w/ in.css + "text-decoration-thickness": "2px", // align w/ in.css + }, + "h1, h2, h3, h4, h5, h6": { + color: theme("colors.rp-dawn-text"), + }, + blockquote: { + "border-color": theme("colors.rp-dawn-muted"), + "background-color": theme("colors.rp-dawn-overlay"), + color: theme("colors.rp-dawn-text"), + }, + strong: { + color: theme("colors.rp-dawn-text"), // align w/ main text color + fontWeight: "800", + }, + }, + }, + // NOTE: This is for prose (Markdown) in DARK mode + dark: { + css: { + pre: null, + code: null, + "pre code": null, + color: theme("colors.rp-moon-iris"), // main text + a: { + color: theme("colors.rp-moon-iris"), // align w/ in.css + "text-decoration-color": theme( + "colors.rp-moon-pine", + ), // align w/ in.css + "text-decoration-thickness": "2px", // align w/ in.css + }, + "h1, h2, h3, h4, h5, h6": { + color: theme("colors.rp-moon-love"), + }, + blockquote: { + "border-color": theme("colors.rp-moon-overlay"), + "background-color": theme("colors.rp-moon-surface"), + color: theme("colors.rp-moon-text"), + }, + strong: { + color: theme("colors.rp-moon-iris"), // align w/ main text color + fontWeight: "800", + }, + }, + }, + }), + }, + }, + corePlugins: { + // preflight: false, + divideStyle: true, + }, +}; diff --git a/pelican/themes/simple/templates/archives.html b/templates/archives.html similarity index 70% rename from pelican/themes/simple/templates/archives.html rename to templates/archives.html index ac774074..393a37d5 100644 --- a/pelican/themes/simple/templates/archives.html +++ b/templates/archives.html @@ -3,12 +3,8 @@ {% block title %}{{ SITENAME|striptags }} - Archives{% endblock %} {% block content %} - -
      - -

      Blog post archive

      - - All blog posts ever published. +
      +

      Blog archive

      {% for article in dates %} @@ -16,5 +12,5 @@
      {{ article.title }}
      {% endfor %}
      -
      +
      {% endblock %} diff --git a/templates/article.html b/templates/article.html new file mode 100644 index 00000000..a20efe84 --- /dev/null +++ b/templates/article.html @@ -0,0 +1,106 @@ +{% extends "base.html" %} +{% block html_lang %}{{ article.lang }}{% endblock %} + +{% block title %}{{ SITENAME|striptags }} - {{ article.title|striptags }}{% endblock %} + +{% block head %} + {{ super() }} + + {% if article.description %} + + {% endif %} + + {% for tag in article.tags %} + + {% endfor %} + +{% endblock %} + +{% block content %} +
      +
      +

      + {{ article.title }} + # +

      +
        +
      • + + + + +  {{ article.stats['read_mins']*1.5|round|int }} min. read + + + + + +  Flesch-Kincaid reading ease{{ article.stats['fi']|int }} + +
      • +
      • + + {% if article.modified %} + + {% endif %} +
      • +
      + + {% if article.series %} +
      +

      This post is part {{ article.series.index }} of the "{{ article.series.name }}" series: +

        + {% for part_article in article.series.all %} +
      1. + {{ part_article.title }} +
      2. + {% endfor %} +
      +
      + {% endif %} +
      + {{ article.content }} + +
      +
      + + {% if article.category %} +

      + Category +

      + {% endif %} + {% if article.tags %} +

      + Tags +

      + {% endif %} +
      +
      + {% if article.category %} +

      + {{ article.category }} +

      + {% endif %} + {% if article.tags %} +

      + {% for tag in article.tags %} + {{ tag }} + {% endfor %} +

      + {% endif %} +
      +
      +
      +{% endblock %} diff --git a/pelican/themes/simple/templates/author.html b/templates/author.html similarity index 100% rename from pelican/themes/simple/templates/author.html rename to templates/author.html diff --git a/pelican/themes/simple/templates/authors.html b/templates/authors.html similarity index 100% rename from pelican/themes/simple/templates/authors.html rename to templates/authors.html diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 00000000..e6281227 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,144 @@ + + + + {% block head %} + {% block title %}{{ SITENAME|striptags }}{% endblock title %} + + + + {% if SITESUBTITLE %} + + {% endif %} + {% if STYLESHEET_URL %} + + {% endif %} + {% if FEED_ALL_ATOM %} + + {% endif %} + {% if FEED_ALL_RSS %} + + {% endif %} + {% if FEED_ATOM %} + + {% endif %} + {% if FEED_RSS %} + + {% endif %} + {% if CATEGORY_FEED_ATOM and category %} + + {% endif %} + {% if CATEGORY_FEED_RSS and category %} + + {% endif %} + {% if TAG_FEED_ATOM and tag %} + + {% endif %} + {% if TAG_FEED_RSS and tag %} + + {% endif %} + + + + + + {% endblock head %} + + +
      + +
      +
      +
      +

      {{ SITENAME }}

      + {% if SITESUBTITLE %} +

      {{ SITESUBTITLE }}

      + {% endif %} +
      +
      +
      +
      + +
      + +
      + +
      +
      +
      + {% block content %} + {% endblock %} +
      +
      +
      + +
      + +
      + +
      +
      + +
      +
      + +
      +
      + + diff --git a/pelican/themes/simple/templates/categories.html b/templates/categories.html similarity index 82% rename from pelican/themes/simple/templates/categories.html rename to templates/categories.html index c723f8a0..c5dba7c1 100644 --- a/pelican/themes/simple/templates/categories.html +++ b/templates/categories.html @@ -3,10 +3,12 @@ {% block title %}{{ SITENAME|striptags }} - Categories{% endblock %} {% block content %} -

      Categories on {{ SITENAME }}

      +
      +

      Categories

        {% for category, articles in categories|sort %}
      • {{ category }} ({{ articles|count }})
      • {% endfor %}
      +
      {% endblock %} diff --git a/pelican/themes/simple/templates/category.html b/templates/category.html similarity index 72% rename from pelican/themes/simple/templates/category.html rename to templates/category.html index ca2db1cd..2cb03291 100644 --- a/pelican/themes/simple/templates/category.html +++ b/templates/category.html @@ -3,5 +3,5 @@ {% block title %}{{ SITENAME|striptags }} - {{ category }} category{% endblock %} {% block content_title %} -

      Articles in the "{{ category }}" category

      +

      Tales from the {{ category }} department

      {% endblock %} diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 00000000..3efe220f --- /dev/null +++ b/templates/index.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} +{% block content %} + {% block content_title %} +

      Recent blog posts

      + {% endblock %} + +
      + {% for article in articles_page.object_list %} +
      + +
      + {% endfor %} +
      + + {% if articles_page.has_other_pages() %} + {% include 'pagination.html' %} + {% endif %} +{% endblock content %} diff --git a/templates/page.html b/templates/page.html new file mode 100644 index 00000000..041e014d --- /dev/null +++ b/templates/page.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} +{% block html_lang %}{{ page.lang }}{% endblock %} + +{% block title %}{{ SITENAME|striptags }} - {{ page.title|striptags }}{%endblock%} + +{% block head %} + {{ super() }} +{% endblock %} + +{% block content %} +
      +
      +

      {{ page.title }}

      + {{ page.content }} +
      + + {% if page.modified %} +
      +

      +

      +
      + {% endif %} +
      +{% endblock %} diff --git a/templates/pagination.html b/templates/pagination.html new file mode 100644 index 00000000..b6ef2dd3 --- /dev/null +++ b/templates/pagination.html @@ -0,0 +1,46 @@ +{% if DEFAULT_PAGINATION %} {% set first_page = articles_paginator.page(1) %} {% +set last_page = articles_paginator.page(articles_paginator.num_pages) %} + +{% endif %} diff --git a/pelican/themes/simple/templates/period_archives.html b/templates/period_archives.html similarity index 100% rename from pelican/themes/simple/templates/period_archives.html rename to templates/period_archives.html diff --git a/pelican/themes/simple/templates/tag.html b/templates/tag.html similarity index 75% rename from pelican/themes/simple/templates/tag.html rename to templates/tag.html index be217783..9654e991 100644 --- a/pelican/themes/simple/templates/tag.html +++ b/templates/tag.html @@ -3,5 +3,5 @@ {% block title %}{{ SITENAME|striptags }} - {{ tag }} tag{% endblock %} {% block content_title %} -

      Articles tagged with {{ tag }}

      +

      Tales tagged with {{ tag }}

      {% endblock %} diff --git a/pelican/themes/simple/templates/tags.html b/templates/tags.html similarity index 100% rename from pelican/themes/simple/templates/tags.html rename to templates/tags.html