Пример #1
0
    def copy_static_files(self):
        # copy all static files
        self.logger.info(bold("copying static files... "), nonl=True)
        ensuredir(os.path.join(self.outdir, '_static'))
        if (self.config["jupyter_execute_notebooks"]):
            self.logger.info(
                bold("copying static files to executed folder... \n"),
                nonl=True)
            ensuredir(os.path.join(self.executed_notebook_dir, '_static'))

        # excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
        for static_path in self.config["jupyter_static_file_path"]:
            entry = os.path.join(self.confdir, static_path)
            if not os.path.exists(entry):
                self.logger.warning(
                    "jupyter_static_path entry {} does not exist".format(
                        entry))
            else:
                copy_asset(entry, os.path.join(self.outdir, "_static"))
                if (self.config["jupyter_execute_notebooks"]):
                    copy_asset(
                        entry,
                        os.path.join(self.executed_notebook_dir, "_static"))
        self.logger.info("done")
        self.copy_static_folder_to_subfolders(self.executedir, True)
Пример #2
0
def on_build_finished(app, exc):
    # type: (Sphinx, Exception) -> None
    if exc is None:
        src = path.join(sphinx.package_dir, 'templates', 'graphviz',
                        'graphviz.css')
        dst = path.join(app.outdir, '_static')
        copy_asset(src, dst)
Пример #3
0
def copy_asset_files(app, exc):

    if exc:
        return

    # The files are added to the _build/html/_static/css folder.
    if app.config.include_annotated_css:
        logger.info(
            'Copying CSS files from the annotated directive to the _static folder... '
        )
        html_static_path_css = os.path.join(assets_path, CSS_FILE)
        local_path_css = os.path.join(os.path.dirname(__file__),
                                      html_static_path_css)
        copy_asset(local_path_css, os.path.join(app.outdir, '_static', 'css'))
        logger.info('done')

    # The files are added to the _build/html/_static/js folder.
    if app.config.include_annotated_js:
        logger.info(
            'Copying JS files from the annotated directive to the _static folder... '
        )
        html_static_path_js = os.path.join(assets_path, JS_FILE)
        local_path_js = os.path.join(os.path.dirname(__file__),
                                     html_static_path_js)
        copy_asset(local_path_js, os.path.join(app.outdir, '_static', 'js'))
        logger.info('done')
Пример #4
0
def setup_theme(app, exception):
    """
    Auto-configure default settings for known themes.

    Add a small custom CSS file for a specific theme and set hoverxref configs
    (if not overwritten by the user) with better defaults for these themes.
    """
    css_file = None
    theme = app.config.html_theme
    default, rebuild, types = app.config.values.get('hoverxref_modal_class')
    if theme == 'sphinx_material':
        if app.config.hoverxref_modal_class == default:
            app.config.hoverxref_modal_class = 'md-typeset'
            css_file = 'css/sphinx_material.css'
    elif theme == 'alabaster':
        if app.config.hoverxref_modal_class == default:
            app.config.hoverxref_modal_class = 'body'
            css_file = 'css/alabaster.css'
    elif theme == 'sphinx_rtd_theme':
        if app.config.hoverxref_modal_class == default:
            css_file = 'css/sphinx_rtd_theme.css'

    if css_file:
        app.add_css_file(css_file)
        path = os.path.join(os.path.dirname(__file__), '_static', css_file)
        copy_asset(
            path,
            os.path.join(app.outdir, '_static', 'css'),
        )
Пример #5
0
 def copy_static_files(self):
     if "tomyst_static_file_path" in self.config:
         for static_path in self.config["tomyst_static_file_path"]:
             output_path = path.join(self.outdir, static_path)
             ensuredir(output_path)
             entry = path.join(self.confdir, static_path)
             copy_asset(entry, output_path)
Пример #6
0
def copy_asset_files(app, exc):
    """Copy static assets."""
    asset_files = ['bootstrap_divs.css', 'bootstrap_divs.js']
    if exc is None:  # build succeeded
        for path in asset_files:
            copy_asset(op.join(this_dir, path),
                       op.join(app.outdir, '_static'))
Пример #7
0
    def copy_static_files(self):
        # copy static files
        self.info(bold('copying static files... '), nonl=True)
        ensuredir(path.join(self.outdir, '_static'))
        # first, create pygments style file
        f = open(path.join(self.outdir, '_static', 'pygments.css'), 'w')
        f.write(self.highlighter.get_stylesheet())
        f.close()
        # then, copy translations JavaScript file
        if self.config.language is not None:
            jsfile = self._get_translations_js()
            if jsfile:
                copyfile(jsfile, path.join(self.outdir, '_static',
                                           'translations.js'))

        # copy non-minified stemmer JavaScript file
        if self.indexer is not None:
            jsfile = self.indexer.get_js_stemmer_rawcode()
            if jsfile:
                copyfile(jsfile, path.join(self.outdir, '_static', '_stemmer.js'))

        ctx = self.globalcontext.copy()

        # add context items for search function used in searchtools.js_t
        if self.indexer is not None:
            ctx.update(self.indexer.context_for_searchtool())

        # then, copy over theme-supplied static files
        if self.theme:
            for theme_path in self.theme.get_dirchain()[::-1]:
                entry = path.join(theme_path, 'static')
                copy_asset(entry, path.join(self.outdir, '_static'), excluded=DOTFILES,
                           context=ctx, renderer=self.templates)
        # then, copy over all user-supplied static files
        excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
        for static_path in self.config.html_static_path:
            entry = path.join(self.confdir, static_path)
            if not path.exists(entry):
                self.warn('html_static_path entry %r does not exist' % entry)
                continue
            copy_asset(entry, path.join(self.outdir, '_static'), excluded,
                       context=ctx, renderer=self.templates)
        # copy logo and favicon files if not already in static path
        if self.config.html_logo:
            logobase = path.basename(self.config.html_logo)
            logotarget = path.join(self.outdir, '_static', logobase)
            if not path.isfile(path.join(self.confdir, self.config.html_logo)):
                self.warn('logo file %r does not exist' % self.config.html_logo)
            elif not path.isfile(logotarget):
                copyfile(path.join(self.confdir, self.config.html_logo),
                         logotarget)
        if self.config.html_favicon:
            iconbase = path.basename(self.config.html_favicon)
            icontarget = path.join(self.outdir, '_static', iconbase)
            if not path.isfile(path.join(self.confdir, self.config.html_favicon)):
                self.warn('favicon file %r does not exist' % self.config.html_favicon)
            elif not path.isfile(icontarget):
                copyfile(path.join(self.confdir, self.config.html_favicon),
                         icontarget)
        self.info('done')
Пример #8
0
def copy_asset_files(app, exc):
    asset_files = [
        resource_filename(__name__, 'thingiview'),
    ]
    if exc is None:  # build succeeded
        for path in asset_files:
            copy_asset(path, os.path.join(app.outdir, '_static/thingiview'))
Пример #9
0
def copy_asset_files(app, exception):
    """
    Copy all assets after build finished successfully.

    Assets that are templates (ends with ``_t``) are previously rendered using
    using all the configs starting with ``hoverxref_`` as a context.
    """
    if exception is None:  # build succeeded

        context = {}
        for attr in app.config.values:
            if attr.startswith('hoverxref_'):
                # First, add the default values to the context
                context[attr] = app.config.values[attr][0]

        for attr in dir(app.config):
            if attr.startswith('hoverxref_'):
                # Then, add the values that the user overrides
                context[attr] = getattr(app.config, attr)

        for f in ASSETS_FILES:
            path = os.path.join(os.path.dirname(__file__), '_static', f)
            logger.info("Copying file to assets: %s", f)
            copy_asset(
                path,
                os.path.join(app.outdir, '_static',
                             f.split('.')[-1].replace('js_t', 'js')),
                context=context,
            )
Пример #10
0
 def copy_static_readthedocs_files(self):
     log.info(bold('copying readthedocs static files... '), nonl=True)
     for filename in self.static_readthedocs_files:
         path_dest = os.path.join(self.outdir, '_static')
         path_src = os.path.join(
             os.path.abspath(os.path.dirname(__file__)),
             '_static',
             filename
         )
         ctx = self.get_static_readthedocs_context()
         if sphinx.version_info < (1, 5):
             copy_static_entry(
                 path_src,
                 path_dest,
                 self,
                 context=ctx,
             )
         else:
             copy_asset(
                 path_src,
                 path_dest,
                 context=ctx,
                 renderer=self.templates
             )
     log.info('done')
Пример #11
0
def copy_asset_files(app, exc):
    asset_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                             '_static')
    if exc is None:  # build succeeded
        for file in os.listdir(asset_dir):
            copy_asset(os.path.join(asset_dir, file),
                       os.path.join(app.outdir, '_static'))
Пример #12
0
    def copy_static_files(self):
        # copy static files
        self.info(bold('copying static files... '), nonl=True)
        ensuredir(path.join(self.outdir, '_static'))
        # first, create pygments style file
        with open(path.join(self.outdir, '_static', 'pygments.css'), 'w') as f:
            f.write(self.highlighter.get_stylesheet())
        # then, copy translations JavaScript file
        if self.config.language is not None:
            jsfile = self._get_translations_js()
            if jsfile:
                copyfile(jsfile, path.join(self.outdir, '_static',
                                           'translations.js'))

        # copy non-minified stemmer JavaScript file
        if self.indexer is not None:
            jsfile = self.indexer.get_js_stemmer_rawcode()
            if jsfile:
                copyfile(jsfile, path.join(self.outdir, '_static', '_stemmer.js'))

        ctx = self.globalcontext.copy()

        # add context items for search function used in searchtools.js_t
        if self.indexer is not None:
            ctx.update(self.indexer.context_for_searchtool())

        # then, copy over theme-supplied static files
        if self.theme:
            for theme_path in self.theme.get_dirchain()[::-1]:
                entry = path.join(theme_path, 'static')
                copy_asset(entry, path.join(self.outdir, '_static'), excluded=DOTFILES,
                           context=ctx, renderer=self.templates)
        # then, copy over all user-supplied static files
        excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
        for static_path in self.config.html_static_path:
            entry = path.join(self.confdir, static_path)
            if not path.exists(entry):
                self.warn('html_static_path entry %r does not exist' % entry)
                continue
            copy_asset(entry, path.join(self.outdir, '_static'), excluded,
                       context=ctx, renderer=self.templates)
        # copy logo and favicon files if not already in static path
        if self.config.html_logo:
            logobase = path.basename(self.config.html_logo)
            logotarget = path.join(self.outdir, '_static', logobase)
            if not path.isfile(path.join(self.confdir, self.config.html_logo)):
                self.warn('logo file %r does not exist' % self.config.html_logo)
            elif not path.isfile(logotarget):
                copyfile(path.join(self.confdir, self.config.html_logo),
                         logotarget)
        if self.config.html_favicon:
            iconbase = path.basename(self.config.html_favicon)
            icontarget = path.join(self.outdir, '_static', iconbase)
            if not path.isfile(path.join(self.confdir, self.config.html_favicon)):
                self.warn('favicon file %r does not exist' % self.config.html_favicon)
            elif not path.isfile(icontarget):
                copyfile(path.join(self.confdir, self.config.html_favicon),
                         icontarget)
        self.info('done')
Пример #13
0
def copy_statics(app, exc):
    if exc is None:
        for srcfile in ('contentui.css', 'contentui.js'):
            src = os.path.join(os.path.dirname(__file__), srcfile)
            dst = os.path.join(app.outdir, '_static')
            assert os.path.isfile(src)
            assert os.path.isdir(dst)
            copy_asset(src, dst)
Пример #14
0
 def copy_asset_files(event_app: Sphinx, exception: Exception) -> None:
     if not exception:
         src_static_dir = path.join(path.dirname(__file__), "_static")
         dst_static_dir = path.join(event_app.outdir, "_static")
         # logger.info("__file__: %s" % __file__)
         # logger.info("src_static_dir: %s" % src_static_dir)
         # logger.info("dst_static_dir: %s" % dst_static_dir)
         copy_asset(src_static_dir, dst_static_dir, context={})
Пример #15
0
def copy_asset_files(app, exc):
    import os

    assetspath = Path(__file__).parent / "static"
    if exc is None:  # build succeeded
        for path in assetspath.glob("*.css"):
            copy_asset(str(path.absolute()),
                       os.path.join(app.outdir, "_static"))
Пример #16
0
    def copy_localized_files(self) -> None:
        source_dir = path.join(self.confdir, self.config.applehelp_locale + '.lproj')
        target_dir = self.outdir

        if path.isdir(source_dir):
            excluded = Matcher(self.config.exclude_patterns + ['**/.*'])
            copy_asset(source_dir, target_dir, excluded,
                       context=self.globalcontext, renderer=self.templates)
Пример #17
0
def setup(app):
    logger.verbose("Adding copy buttons to code blocks...")
    # Add our static path
    app.connect("builder-inited", st_static_path)

    # Set default values for the configuration
    app.connect("env-before-read-docs", init_thebe_default_config)

    # Include Thebe core docs
    app.connect("doctree-resolved", update_thebe_context)
    app.connect("env-updated", init_thebe_core)

    # configuration for this tool
    app.add_config_value("thebe_config", {}, "html")
    # override=True in case Jupyter Sphinx has already been loaded
    app.add_directive("thebe-button", ThebeButton, override=True)

    # Add relevant code to headers
    opts = {'data-aplus': 'yes'}
    app.add_css_file(CSS_FILE, **opts)

    # The files are added to the _build/html/_static/css folder.
    logger.info(
        'Copying CSS files from the thebe-button directive to the _static folder... '
    )
    html_static_path_css = os.path.join(assets_path, CSS_FILE)
    local_path_css = os.path.join(os.path.dirname(__file__),
                                  html_static_path_css)
    copy_asset(local_path_css, os.path.join(app.outdir, '_static', 'css'))
    logger.info('done')

    # The files are added to the _build/html/_static/js folder.
    logger.info(
        'Copying JS files from the thebe-button directive to the _static folder... '
    )
    html_static_path_js = os.path.join(assets_path, JS_FILE)
    local_path_js = os.path.join(os.path.dirname(__file__),
                                 html_static_path_js)
    copy_asset(local_path_js, os.path.join(app.outdir, '_static', 'js'))
    logger.info('done')

    # ThebeButtonNode is the button that activates thebe
    # and is only rendered for the HTML builder
    app.add_node(
        ThebeButtonNode,
        html=(visit_element_html, None),
        latex=(skip, None),
        textinfo=(skip, None),
        text=(skip, None),
        man=(skip, None),
        override=True,
    )

    return {
        "version": __version__,
        "parallel_read_safe": True,
        "parallel_write_safe": True,
    }
Пример #18
0
def copy_statics(app, exception):
    if exception is not None:
        return
    for srcfile in ('protobufdomain.css', ):
        src = os.path.join(os.path.dirname(__file__), srcfile)
        dst = os.path.join(app.outdir, '_static')
        assert os.path.isfile(src)
        assert os.path.isdir(dst)
        copy_asset(src, dst)
Пример #19
0
def copy_asset_files(app: Sphinx, exc: Union[bool, Exception]):
    static_path = Path(__file__).parent.joinpath("_static",
                                                 "proof.css").absolute()
    asset_files = [str(static_path)]

    if exc is None:
        for path in asset_files:
            copy_asset(path,
                       str(Path(app.outdir).joinpath("_static").absolute()))
Пример #20
0
 def copy_custom_pages(self):
      # then, copy over all user-supplied static files
     excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
     for static_path in self.config.html_static_path:
         entry = path.join(self.confdir, static_path)
         if not path.exists(entry):
             logger.warning(__('html_static_path entry %r does not exist'), entry)
             continue
         copy_asset(entry, path.join(self.outdir, '_static'), excluded,
                     context=ctx, renderer=self.templates)
Пример #21
0
 def copy_extra_files(self) -> None:
     """copy html_extra_path files."""
     try:
         with progress_message(__('copying extra files')):
             excluded = Matcher(self.config.exclude_patterns)
             for extra_path in self.config.html_extra_path:
                 entry = path.join(self.confdir, extra_path)
                 copy_asset(entry, self.outdir, excluded)
     except OSError as err:
         logger.warning(__('cannot copy extra file %r'), err)
Пример #22
0
def copy_asset_files(app: Sphinx, exc: Union[bool, Exception]):
    """ Copies required assets for formating in HTML """

    static_path = (Path(__file__).parent.joinpath("assets", "html",
                                                  "exercise.css").absolute())
    asset_files = [str(static_path)]

    if exc is None:
        for path in asset_files:
            copy_asset(path,
                       str(Path(app.outdir).joinpath("_static").absolute()))
Пример #23
0
    def add_file(self, rel_file):
        file_path = self.env.relfn2path(rel_file)[1]
        md5_hash = md5(file_path)

        # Copy file to _asset build path.
        target_dir = os.path.join(self.env.app.outdir, '_casts', md5_hash)
        copy_asset(file_path, target_dir)

        # Determine relative path from doc to _asset build path.
        target_file_uri = posixpath.join('_casts', md5_hash, rel_file)
        doc_uri = self.env.app.builder.get_target_uri(self.env.docname)
        return relative_uri(doc_uri, target_file_uri)
Пример #24
0
    def copy_extra_files(self) -> None:
        try:
            # copy html_extra_path files
            logger.info(bold(__('copying extra files... ')), nonl=True)
            excluded = Matcher(self.config.exclude_patterns)

            for extra_path in self.config.html_extra_path:
                entry = path.join(self.confdir, extra_path)
                copy_asset(entry, self.outdir, excluded)
            logger.info(__('done'))
        except OSError as err:
            logger.warning(__('cannot copy extra file %r'), err)
Пример #25
0
    def copy_localized_files(self):
        source_dir = path.join(self.confdir, self.config.applehelp_locale + '.lproj')
        target_dir = self.outdir

        if path.isdir(source_dir):
            self.info(bold('copying localized files... '), nonl=True)

            excluded = Matcher(self.config.exclude_patterns + ['**/.*'])
            copy_asset(source_dir, target_dir, excluded,
                       context=self.globalcontext, renderer=self.templates)

            self.info('done')
Пример #26
0
    def copy_localized_files(self):
        # type: () -> None
        source_dir = path.join(self.confdir, self.config.applehelp_locale + '.lproj')
        target_dir = self.outdir

        if path.isdir(source_dir):
            logger.info(bold(__('copying localized files... ')), nonl=True)

            excluded = Matcher(self.config.exclude_patterns + ['**/.*'])
            copy_asset(source_dir, target_dir, excluded,
                       context=self.globalcontext, renderer=self.templates)

            logger.info(__('done'))
Пример #27
0
def on_build_finished(app: Sphinx, exc: Exception) -> None:
    if exc is None:
        this_file_path = os.path.dirname(os.path.realpath(__file__))
        src = os.path.join(this_file_path, "drawio.css")
        dst = os.path.join(app.outdir, "_static")
        copy_asset(src, dst)

    if app.config._xvfb:
        app.config._xvfb.terminate()
        stdout, stderr = app.config._xvfb.communicate()
        if app.config._xvfb.poll() != 0:
            raise OSError("Encountered an issue while terminating Xvfb"
                          "\n[stdout]\n{}\n[stderr]{}".format(stdout, stderr))
Пример #28
0
    def copy_extra_files(self):
        # copy html_extra_path files
        self.info(bold('copying extra files... '), nonl=True)
        excluded = Matcher(self.config.exclude_patterns)

        for extra_path in self.config.html_extra_path:
            entry = path.join(self.confdir, extra_path)
            if not path.exists(entry):
                self.warn('html_extra_path entry %r does not exist' % entry)
                continue

            copy_asset(entry, self.outdir, excluded)
        self.info('done')
Пример #29
0
def visit_pdfobject(self, node: Node) -> None:
    pdf_file = node["pdf_file"]
    copy_asset(
        path.join(self.builder.srcdir, pdf_file),
        path.join(self.builder.outdir, "_static"),
    )

    self.body.append(
        f'<div id="pdf-{PurePath(pdf_file).stem}" class="pdfobject" style="height: 400px;"></div>'
    )
    self.body.append(
        f'<script>PDFObject.embed("_static/{pdf_file}", "#pdf-{PurePath(pdf_file).stem}");</script>'
    )
Пример #30
0
    def copy_extra_files(self):
        # copy html_extra_path files
        self.info(bold('copying extra files... '), nonl=True)
        excluded = Matcher(self.config.exclude_patterns)

        for extra_path in self.config.html_extra_path:
            entry = path.join(self.confdir, extra_path)
            if not path.exists(entry):
                self.warn('html_extra_path entry %r does not exist' % entry)
                continue

            copy_asset(entry, self.outdir, excluded)
        self.info('done')
Пример #31
0
    def copy_static_files(self):
        # copy all static files
        self.info(bold("copying static files... "), nonl=True)
        ensuredir(os.path.join(self.outdir, '_static'))

        # excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
        for static_path in self.config["jupyter_static_file_path"]:
            entry = os.path.join(self.confdir, static_path)
            if not os.path.exists(entry):
                self.warn("jupyter_static_path entry {} does not exist".format(
                    entry))
            else:
                copy_asset(entry, os.path.join(self.outdir, "_static"))
        self.info("done")
Пример #32
0
def copy_static(app: Sphinx):
    """ When used in another theme, copy static CSS etc. to _static """

    theme_name = app.config.html_theme
    if theme_name != 'bulmaio_jinja2':
        source = os.path.abspath(
            os.path.join(os.path.dirname(__file__), 'static'))
        dest = os.path.join(app.builder.outdir, '_static')
        copy_asset(source, dest)

    if 0:
        # this is to make the function a generator
        # and make work for Sphinx 'html-collect-pages'
        yield
Пример #33
0
def assets(app, exception):
    # Since '_static' directory may not exist in case of failed build, we
    # need to either ensure its existence here or do not try to copy  assets
    # in case of failure.
    if not exception:
        copy_asset(os.path.join(_HERE, 'redoc.js'),
                   os.path.join(app.builder.outdir, '_static'))

        # It's hard to keep up with ReDoc releases, especially when you don't
        # watch them closely. Hence, there should be a way to override built-in
        # ReDoc bundle with some upstream one.
        if app.config.redoc_uri:
            urllib.request.urlretrieve(
                app.config.redoc_uri,
                os.path.join(app.builder.outdir, '_static', 'redoc.js'))
Пример #34
0
def test_copy_asset(tempdir):
    renderer = DummyTemplateLoader()

    # prepare source files
    source = (tempdir / 'source')
    source.makedirs()
    (source / 'index.rst').write_text('index.rst')
    (source / 'foo.rst_t').write_text('{{var1}}.rst')
    (source / '_static').makedirs()
    (source / '_static' / 'basic.css').write_text('basic.css')
    (source / '_templates').makedirs()
    (source / '_templates' / 'layout.html').write_text('layout.html')
    (source / '_templates' / 'sidebar.html_t').write_text('sidebar: {{var2}}')

    # copy a single file
    assert not (tempdir / 'test1').exists()
    copy_asset(source / 'index.rst', tempdir / 'test1')
    assert (tempdir / 'test1').exists()
    assert (tempdir / 'test1/index.rst').exists()

    # copy directories
    destdir = tempdir / 'test2'
    copy_asset(source, destdir, context=dict(var1='bar', var2='baz'), renderer=renderer)
    assert (destdir / 'index.rst').exists()
    assert (destdir / 'foo.rst').exists()
    assert (destdir / 'foo.rst').text() == 'bar.rst'
    assert (destdir / '_static' / 'basic.css').exists()
    assert (destdir / '_templates' / 'layout.html').exists()
    assert (destdir / '_templates' / 'sidebar.html').exists()
    assert (destdir / '_templates' / 'sidebar.html').text() == 'sidebar: baz'

    # copy with exclusion
    def excluded(path):
        return ('sidebar.html' in path or 'basic.css' in path)

    destdir = tempdir / 'test3'
    copy_asset(source, destdir, excluded,
               context=dict(var1='bar', var2='baz'), renderer=renderer)
    assert (destdir / 'index.rst').exists()
    assert (destdir / 'foo.rst').exists()
    assert not (destdir / '_static' / 'basic.css').exists()
    assert (destdir / '_templates' / 'layout.html').exists()
    assert not (destdir / '_templates' / 'sidebar.html').exists()
Пример #35
0
def on_build_finished(app, exc):
    # type: (Sphinx, Exception) -> None
    if exc is None:
        src = path.join(sphinx.package_dir, 'templates', 'graphviz', 'graphviz.css')
        dst = path.join(app.outdir, '_static')
        copy_asset(src, dst)