diff --git a/contrib/get_nbconvert_minfied_css.py b/contrib/get_nbconvert_minfied_css.py new file mode 100644 index 0000000000000000000000000000000000000000..922d0a272a355854c54c14f70ca3136beaeb993d --- /dev/null +++ b/contrib/get_nbconvert_minfied_css.py @@ -0,0 +1,202 @@ +# -*- coding: utf-8 -*- +#! /usr/bin/env python3 + +""" +Generate minified stylesheet for ipython notebook +""" + +import os + +REPLACE_HIGHLIGHT_WITH_CODEHILITE = False + +NOTEBOOK_CSS_VERSION = '4.3.0' +CSS_URL = ("https://cdn.jupyter.org/notebook/%s/style/style.min.css" + % NOTEBOOK_CSS_VERSION) + +REQUEST_TIMEOUT = 6 +REQUEST_MAX_RETRIES = 5 + +IPYTHON_NOTEBOOK_DECLARE_STR = """ +/*! +* +* IPython notebook +* +*/""" + +IPYTHON_NOTEBOOK_WEBAPP_DECLARE_STR = """ +/*! +* +* IPython notebook webapp +* +*/ +""" + +HIGHLIGHT_CSS_CLASS = ".highlight" +CODEHILITE_CSS_CLASS = ".codehilite" +PYGMENTS_STYLE = "default" + +HIGHLIGT_DECLARE_STR = """ +/*! +* +* Pygments "%s" style with "%s" css_class +* +*/ +""" %(PYGMENTS_STYLE, + CODEHILITE_CSS_CLASS + if REPLACE_HIGHLIGHT_WITH_CODEHILITE else HIGHLIGHT_CSS_CLASS) + +DEST_DIR = ( + os.path.abspath( + os.path.join( + os.path.dirname(__file__), + os.path.pardir, 'relate', 'static', 'css'))) + +CSS_DEST = os.path.join(DEST_DIR, 'ipynb.style.css') +CSS_MINIFIED_DEST = os.path.join(DEST_DIR, 'ipynb.style.min.css') + + +def retry_urlopen(request, timeout=REQUEST_TIMEOUT, n_retries=REQUEST_MAX_RETRIES): + from six.moves.urllib.request import urlopen + i = 0 + while True: + try: + result = urlopen(request, timeout=timeout).read() + return result + except Exception as e: + from six.moves.urllib.error import URLError + from socket import timeout as TimeoutError + if not isinstance(e, (URLError, TimeoutError)): + raise e + if not "timed out" in str(e).lower(): + raise e + i += 1 + if i > n_retries: + raise e + print("\rRequest timed out, retry (%s/%s). " % ( + i, n_retries), flush=True, end="") + import time + time.sleep(0.1) + + +def minify_css(css_string): + url = 'https://cssminifier.com/raw' + post_fields = {'input': css_string} + from six.moves.urllib.parse import urlencode + from six.moves.urllib.request import Request + request = Request(url, urlencode(post_fields).encode()) + return retry_urlopen(request) + + +class GenerateCSS(object): + def _download(self): + try: + return retry_urlopen(CSS_URL) + except Exception as e: + if 'ssl' in str(e).lower(): + import sys + try: + import pycurl + except ImportError: + print( + "Failed, try again after installing PycURL with " + "`pip install pycurl` to avoid outdated SSL.", + file=sys.stderr) + raise e + else: + print("Failed, trying again with PycURL to avoid " + "outdated SSL.", + file=sys.stderr) + return self._download_pycurl() + raise e + + def _download_pycurl(self): + """Download CSS with pycurl, in case of old SSL (e.g. Python < 2.7.9).""" + import pycurl + c = pycurl.Curl() + c.setopt(c.URL, CSS_URL) + from io import BytesIO + buf = BytesIO() + c.setopt(c.WRITEDATA, buf) + c.perform() + return buf.getvalue().decode() + + def process_nbconvert_css(self): + print("Downloading ipython notebook CSS: %s." % CSS_URL) + try: + css = self._download() + print("Done.") + return self._process_nbconvert_css(css) + except: + raise + + def _process_nbconvert_css(self, css): + print("Processing downloaded ipython notebook CSS.") + try: + css = css.split(IPYTHON_NOTEBOOK_DECLARE_STR.encode())[1] + css = IPYTHON_NOTEBOOK_DECLARE_STR.encode() + css + except IndexError: + raise ValueError("Bad splitter for notebook css %s" + % IPYTHON_NOTEBOOK_DECLARE_STR) + + print("Done.") + if not REPLACE_HIGHLIGHT_WITH_CODEHILITE: + return css + return css.replace(HIGHLIGHT_CSS_CLASS.encode() + b" ", + CODEHILITE_CSS_CLASS.encode() + b" ") + + def process_highlight_style_defs(self, style=PYGMENTS_STYLE): + print("Processing Pygments code highlight CSS.") + def get_highlight_style_defs(): + from pygments.formatters import get_formatter_by_name + formatter = get_formatter_by_name("html", style=style) + return formatter.get_style_defs() + + style_defs = get_highlight_style_defs() + print("Done.") + if REPLACE_HIGHLIGHT_WITH_CODEHILITE: + css_class = CODEHILITE_CSS_CLASS + else: + css_class = HIGHLIGHT_CSS_CLASS + return (HIGHLIGT_DECLARE_STR + + "\n".join(["%s %s" % (css_class, line) + for line in style_defs.splitlines()])) + + def get_assembled_css(self): + try: + nbcovert_css = self.process_nbconvert_css() + highlight_css = self.process_highlight_style_defs() + except: + raise + css = "\n".join([nbcovert_css.decode(), highlight_css]) + print("CSS assembled.") + return css + + def get_minified_css(self, css): + css = (css.replace(IPYTHON_NOTEBOOK_DECLARE_STR, "") + .replace(IPYTHON_NOTEBOOK_WEBAPP_DECLARE_STR, "") + .replace(HIGHLIGT_DECLARE_STR, "") + ) + return minify_css(css) + + def run(self): + css = self.get_assembled_css() + with open(CSS_DEST, 'wb') as f: + f.write(css.encode()) + print("Succesfully generated %s" % CSS_DEST) + + print("Minifying CSS...") + minified_css = self.get_minified_css(css).decode() + print("Done.") + + with open(CSS_MINIFIED_DEST, 'wb') as f: + f.write(minified_css.encode()) + print("Succesfully generated %s" % CSS_MINIFIED_DEST) + + +def main(): + g = GenerateCSS() + g.run() + + +if __name__ == "__main__": + main() diff --git a/course/content.py b/course/content.py index eade7a0ee1739d98318fe18b76669e2772a752d3..99328765a89cd701f10aaf6322da7e13de94c8c6 100644 --- a/course/content.py +++ b/course/content.py @@ -896,14 +896,35 @@ def expand_markup( env = Environment( loader=GitTemplateLoader(repo, commit_sha), undefined=StrictUndefined) + template = env.from_string(text) - text = template.render(**jinja_env) + kwargs = {} + if jinja_env: + kwargs.update(jinja_env) + + from course.utils import ( + IpythonNotebookCellsJinjaExpansionContext as IpynbContext) + kwargs[IpynbContext.context_name] = IpynbContext(course, repo, commit_sha) + + text = template.render(**kwargs) # }}} return text +def unwrap_relate_tmp_pre_tag(html_string): + # type: (Text) -> (Text) + + from lxml.html import fromstring, tostring + tree = fromstring(html_string) + + for node in tree.iterdescendants("pre"): + if "relate_tmp_pre" in node.attrib.get("class", ""): + node.drop_tag() + return tostring(tree, encoding="unicode") + + def markup_to_html( course, # type: Optional[Course] repo, # type: Repo_ish @@ -915,6 +936,11 @@ def markup_to_html( jinja_env={}, # type: Dict ): # type: (...) -> Text + + disable_codehilite = bool( + getattr(settings, + "RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION", True)) + if course is not None and not jinja_env: try: import django.core.cache as cache @@ -922,9 +948,12 @@ def markup_to_html( cache_key = None else: import hashlib - cache_key = ("markup:v7:%s:%d:%s:%s" - % (CACHE_KEY_ROOT, course.id, str(commit_sha), - hashlib.md5(text.encode("utf-8")).hexdigest())) + cache_key = ("markup:v7:%s:%d:%s:%s%s" + % (CACHE_KEY_ROOT, + course.id, str(commit_sha), + hashlib.md5(text.encode("utf-8")).hexdigest(), + ":NOCODEHILITE" if disable_codehilite else "" + )) def_cache = cache.caches["default"] result = def_cache.get(cache_key) @@ -949,15 +978,30 @@ def markup_to_html( from course.mdx_mathjax import MathJaxExtension import markdown + + extensions = [ + LinkFixerExtension(course, commit_sha, reverse_func=reverse_func), + MathJaxExtension(), + "markdown.extensions.extra", + ] + + if not disable_codehilite: + # Note: no matter whether disable_codehilite, the code in + # the rendered ipython notebook will be highlighted. + # "css_class=highlight" is to ensure that, when codehilite extension + # is enabled, code out side of notebook uses the same html class + # attribute as the default highlight class (i.e., `highlight`) + # used by rendered ipynb notebook cells, Thus we don't need to + # make 2 copies of css for the highlight. + extensions += ["markdown.extensions.codehilite(css_class=highlight)"] + result = markdown.markdown(text, - extensions=[ - LinkFixerExtension(course, commit_sha, reverse_func=reverse_func), - MathJaxExtension(), - "markdown.extensions.extra", - "markdown.extensions.codehilite", - ], + extensions=extensions, output_format="html5") + if result.strip(): + result = unwrap_relate_tmp_pre_tag(result) + assert isinstance(result, six.text_type) if cache_key is not None: def_cache.add(cache_key, result, None) diff --git a/course/templates/course/jinja2/nbconvert_template.tpl b/course/templates/course/jinja2/nbconvert_template.tpl new file mode 100644 index 0000000000000000000000000000000000000000..f040623ae182dcd75792303c0b86b022075da044 --- /dev/null +++ b/course/templates/course/jinja2/nbconvert_template.tpl @@ -0,0 +1,10 @@ +{%- extends 'basic.tpl' -%} + +{# This is to prevent code_cell being process by markdown_to_html #} + +{% block input %}
{{ super() }}
+{%- endblock input %} + +{# This is to remove the empty cells ahead of markdown_cells #} +{% block empty_in_prompt -%} +{%- endblock empty_in_prompt %} \ No newline at end of file diff --git a/course/utils.py b/course/utils.py index 6209648783114f970cecab5494e78565367e84c5..88311ac2f8dc0d5f4cd0b5651d273919418e2f09 100644 --- a/course/utils.py +++ b/course/utils.py @@ -69,9 +69,13 @@ if False: FlowSession, FlowPageData, ) + from course.content import Repo_ish # noqa # }}} +import re +CODE_CELL_DIV_ATTRS_RE = re.compile('(
)') + def getattr_with_fallback(aggregates, attr_name, default=None): # type: (Iterable[Any], Text, Any) -> Any @@ -1181,4 +1185,110 @@ def get_course_specific_language_choices(): return tuple(filtered_options) + +class RelateJinjaExpansionContextBase(object): + def __init__(self, course, repo, commit_sha): + # type: (Optional[Course], Repo_ish, bytes) -> None + self.course = course + self.repo = repo + self.commit_sha = commit_sha + + @property + def context_name(self): + raise NotImplementedError() + + def __call__(self, *args, **kwargs): + # type: (*Any, **Any) -> Text + raise NotImplementedError() + + +# {{{ ipynb utilities + +class IpythonNotebookCellsJinjaExpansionContext(RelateJinjaExpansionContextBase): + context_name = "render_notebook_cells" + + def render_notebook_cells(self, ipynb_path, indices=None, clear_output=False, + clear_markdown=False): + # type: (Text, Optional[Any], Optional[bool], Optional[bool]) -> Text + from course.content import get_repo_blob_data_cached + try: + ipynb_source = get_repo_blob_data_cached(self.repo, ipynb_path, + self.commit_sha).decode() + + return self.render_notebook_from_source( + ipynb_source, + clear_output=clear_output, + indices=indices, + clear_markdown=clear_markdown, + ) + except ObjectDoesNotExist: + raise + + __call__ = render_notebook_cells # type: ignore + + def render_notebook_from_source(self, ipynb_source, clear_output=False, + indices=None, clear_markdown=False): + # type: (Text, Optional[bool], Optional[Any], Optional[bool]) -> Text + """ + Get HTML format of ipython notebook so as to be rendered in RELATE flow + pages. + :param ipynb_source: the :class:`text` read from a ipython notebook. + :param clear_output: a :class:`bool` instance, indicating whether existing + execution output of code cells should be removed. + :param indices: a :class:`list` instance, 0-based indices of notebook cells + which are expected to be rendered. + :param clear_markdown: a :class:`bool` instance, indicating whether markdown + cells will be ignored.. + :return: + """ + import nbformat + from nbformat.reader import parse_json + nb_source_dict = parse_json(ipynb_source) + + if indices: + nb_source_dict.update( + {"cells": [nb_source_dict["cells"][idx] for idx in indices]}) + + if clear_markdown: + nb_source_dict.update( + {"cells": [cell for cell in nb_source_dict["cells"] + if cell['cell_type'] != "markdown"]}) + + nb_source_dict.update({"cells": nb_source_dict["cells"]}) + + import json + ipynb_source = json.dumps(nb_source_dict) + notebook = nbformat.reads(ipynb_source, as_version=4) + + from traitlets.config import Config + c = Config() + + # This is to prevent execution of arbitrary code from note book + c.ExecutePreprocessor.enabled = False + if clear_output: + c.ClearOutputPreprocessor.enabled = True + + c.CSSHTMLHeaderPreprocessor.enabled = False + c.HighlightMagicsPreprocessor.enabled = False + + import os + from django.conf import settings + + # Place the template in course template dir + template_path = os.path.join( + settings.BASE_DIR, "course", "templates", "course", "jinja2") + c.TemplateExporter.template_path.append(template_path) + + from nbconvert import HTMLExporter + html_exporter = HTMLExporter( + config=c, + template_file="nbconvert_template.tpl" + ) + + (body, resources) = html_exporter.from_notebook_node(notebook) + + return body + +# }}} + # vim: foldmethod=marker diff --git a/doc/content.rst b/doc/content.rst index 610028a3903fbfe77aa91e335549e3d3ac8ca489..5d516a4b74ccea7c980aa64bd234bb59b1508281 100644 --- a/doc/content.rst +++ b/doc/content.rst @@ -319,6 +319,37 @@ The following snippet shows an interactive video viewer::

To view this video please enable JavaScript, and consider upgrading to a web browser that supports HTML5 video

+ +Ipython notebook to HTML +^^^^^^^^^^^^^^^^^^^^^^^^ + +RELATE provides the functionality of rendering `Ipython Notebooks +`_ in course pages. + +.. function:: render_notebook_cells(ipynb_path, indices=None, clear_output=False, + clear_markdown=False) + Convert an ipython notebook to markdown via nbconvert + (see http://nbconvert.readthedocs.io). + + :param ipynb_path: :class:`string`, the path of the ipython notebook in + the repo. + :param indices: :class:`list`, the indices of cells which are expected to + be rendered. For example, ``[1, 2, 3, 6]`` or ``range(3, -1)``. If not + specified, all cells will be rendered. + :param clear_output: :class:`bool`, indicating whether existing execution + output of code cells should be removed. Default: `False`. + :param clear_markdown: :class:`bool`, indicating whether all text cells + will be removed. Default: `False`. + :rtype: :class:`string`, rendered markdown which will be consequently + converted to HTML. + +For example, the following snippet shows the HTML version of ``test.ipynb`` in repo +folder ``code``, with markdown (``text_cells``) and output (execution result of +``code_cells``) removed:: + + {{ render_notebook_cells("code/test.ipynb", clear_markdown=True, clear_output=True) }} + + Macros ^^^^^^ diff --git a/local_settings.example.py b/local_settings.example.py index 6b3f43b440a453afe95e75780a4131cfb590e759..db3188ac6eeae274bcaa67f4d46939be2bff81c8 100644 --- a/local_settings.example.py +++ b/local_settings.example.py @@ -209,6 +209,11 @@ RELATE_SHOW_EDITOR_FORM = True # }}} +# Whether disable "markdown.extensions.codehilite" when rendering page markdown. +# Default to True, as enable it sometimes crashes for some pages with code fences. +# For this reason, there will be a warning when the attribute is set to False when +# starting the server. +#RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION = True # {{{ user full_name format diff --git a/relate/checks.py b/relate/checks.py index dcaa5aed2d46c601b6b9179f220eb3c616ef548b..c5468932e379a305c7ac3c75411c9773d059e51d 100644 --- a/relate/checks.py +++ b/relate/checks.py @@ -54,6 +54,8 @@ RELATE_STARTUP_CHECKS_EXTRA = "RELATE_STARTUP_CHECKS_EXTRA" RELATE_STARTUP_CHECKS_TAG = "start_up_check" RELATE_STARTUP_CHECKS_EXTRA_TAG = "startup_checks_extra" +RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION = ( + "RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION") class RelateCriticalCheckMessage(Critical): @@ -349,6 +351,35 @@ def check_relate_settings(app_configs, **kwargs): # }}} + # {{{ check RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION + relate_disable_codehilite_markdown_extension = getattr( + settings, RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION, None) + if relate_disable_codehilite_markdown_extension is not None: + if not isinstance(relate_disable_codehilite_markdown_extension, bool): + errors.append( + Warning( + msg="%(location)s is not a Boolean value: `%(value)s`, " + "assuming True" + % {"location": + RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION, + "value": + repr(relate_disable_codehilite_markdown_extension)}, + id="relate_disable_codehilite_markdown_extension.W001")) + elif not relate_disable_codehilite_markdown_extension: + errors.append( + Warning( + msg="%(location)s is set to False " + "(with 'markdown.extensions.codehilite' enabled'), " + "noticing that some pages with code fence markdown " + "might get crashed" + % {"location": + RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION, + "value": + repr(relate_disable_codehilite_markdown_extension)}, + id="relate_disable_codehilite_markdown_extension.W002")) + + # }}} + # {{{ check LANGUAGES, why this is not done in django? languages = settings.LANGUAGES @@ -468,7 +499,7 @@ def register_startup_checks_extra(): Register extra checks provided by user. Here we will have to raise error for Exceptions, as that can not be done via check: all checks, including check_relate_settings, will only be - executed after self.ready() is done. + executed after AppConfig.ready() is done. """ startup_checks_extra = getattr(settings, RELATE_STARTUP_CHECKS_EXTRA, None) if startup_checks_extra: diff --git a/relate/static/css/ipynb.style.css b/relate/static/css/ipynb.style.css new file mode 100644 index 0000000000000000000000000000000000000000..79fd18630228afa2181a2870ff7ee0e65c4f8578 --- /dev/null +++ b/relate/static/css/ipynb.style.css @@ -0,0 +1,2257 @@ + +/*! +* +* IPython notebook +* +*/ +/* CSS font colors for translated ANSI colors. */ +.ansibold { + font-weight: bold; +} +/* use dark versions for foreground, to improve visibility */ +.ansiblack { + color: black; +} +.ansired { + color: darkred; +} +.ansigreen { + color: darkgreen; +} +.ansiyellow { + color: #c4a000; +} +.ansiblue { + color: darkblue; +} +.ansipurple { + color: darkviolet; +} +.ansicyan { + color: steelblue; +} +.ansigray { + color: gray; +} +/* and light for background, for the same reason */ +.ansibgblack { + background-color: black; +} +.ansibgred { + background-color: red; +} +.ansibggreen { + background-color: green; +} +.ansibgyellow { + background-color: yellow; +} +.ansibgblue { + background-color: blue; +} +.ansibgpurple { + background-color: magenta; +} +.ansibgcyan { + background-color: cyan; +} +.ansibggray { + background-color: gray; +} +div.cell { + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: vertical; + -moz-box-align: stretch; + display: box; + box-orient: vertical; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: column; + align-items: stretch; + border-radius: 2px; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + border-width: 1px; + border-style: solid; + border-color: transparent; + width: 100%; + padding: 5px; + /* This acts as a spacer between cells, that is outside the border */ + margin: 0px; + outline: none; + border-left-width: 1px; + padding-left: 5px; + background: linear-gradient(to right, transparent -40px, transparent 1px, transparent 1px, transparent 100%); +} +div.cell.jupyter-soft-selected { + border-left-color: #90CAF9; + border-left-color: #E3F2FD; + border-left-width: 1px; + padding-left: 5px; + border-right-color: #E3F2FD; + border-right-width: 1px; + background: #E3F2FD; +} +@media print { + div.cell.jupyter-soft-selected { + border-color: transparent; + } +} +div.cell.selected { + border-color: #ababab; + border-left-width: 0px; + padding-left: 6px; + background: linear-gradient(to right, #42A5F5 -40px, #42A5F5 5px, transparent 5px, transparent 100%); +} +@media print { + div.cell.selected { + border-color: transparent; + } +} +div.cell.selected.jupyter-soft-selected { + border-left-width: 0; + padding-left: 6px; + background: linear-gradient(to right, #42A5F5 -40px, #42A5F5 7px, #E3F2FD 7px, #E3F2FD 100%); +} +.edit_mode div.cell.selected { + border-color: #66BB6A; + border-left-width: 0px; + padding-left: 6px; + background: linear-gradient(to right, #66BB6A -40px, #66BB6A 5px, transparent 5px, transparent 100%); +} +@media print { + .edit_mode div.cell.selected { + border-color: transparent; + } +} +.prompt { + /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */ + min-width: 14ex; + /* This padding is tuned to match the padding on the CodeMirror editor. */ + padding: 0.4em; + margin: 0px; + font-family: monospace; + text-align: right; + /* This has to match that of the the CodeMirror class line-height below */ + line-height: 1.21429em; + /* Don't highlight prompt number selection */ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + /* Use default cursor */ + cursor: default; +} +@media (max-width: 540px) { + .prompt { + text-align: left; + } +} +div.inner_cell { + min-width: 0; + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: vertical; + -moz-box-align: stretch; + display: box; + box-orient: vertical; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: column; + align-items: stretch; + /* Old browsers */ + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; + /* Modern browsers */ + flex: 1; +} +/* input_area and input_prompt must match in top border and margin for alignment */ +div.input_area { + border: 1px solid #cfcfcf; + border-radius: 2px; + background: #f7f7f7; + line-height: 1.21429em; +} +/* This is needed so that empty prompt areas can collapse to zero height when there + is no content in the output_subarea and the prompt. The main purpose of this is + to make sure that empty JavaScript output_subareas have no height. */ +div.prompt:empty { + padding-top: 0; + padding-bottom: 0; +} +div.unrecognized_cell { + padding: 5px 5px 5px 0px; + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: horizontal; + -moz-box-align: stretch; + display: box; + box-orient: horizontal; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: row; + align-items: stretch; +} +div.unrecognized_cell .inner_cell { + border-radius: 2px; + padding: 5px; + font-weight: bold; + color: red; + border: 1px solid #cfcfcf; + background: #eaeaea; +} +div.unrecognized_cell .inner_cell a { + color: inherit; + text-decoration: none; +} +div.unrecognized_cell .inner_cell a:hover { + color: inherit; + text-decoration: none; +} +@media (max-width: 540px) { + div.unrecognized_cell > div.prompt { + display: none; + } +} +div.code_cell { + /* avoid page breaking on code cells when printing */ +} +@media print { + div.code_cell { + page-break-inside: avoid; + } +} +/* any special styling for code cells that are currently running goes here */ +div.input { + page-break-inside: avoid; + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: horizontal; + -moz-box-align: stretch; + display: box; + box-orient: horizontal; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: row; + align-items: stretch; +} +@media (max-width: 540px) { + div.input { + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: vertical; + -moz-box-align: stretch; + display: box; + box-orient: vertical; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: column; + align-items: stretch; + } +} +/* input_area and input_prompt must match in top border and margin for alignment */ +div.input_prompt { + color: #303F9F; + border-top: 1px solid transparent; +} +div.input_area > div.highlight { + margin: 0.4em; + border: none; + padding: 0px; + background-color: transparent; +} +div.input_area > div.highlight > pre { + margin: 0px; + border: none; + padding: 0px; + background-color: transparent; +} +/* The following gets added to the if it is detected that the user has a + * monospace font with inconsistent normal/bold/italic height. See + * notebookmain.js. Such fonts will have keywords vertically offset with + * respect to the rest of the text. The user should select a better font. + * See: https://github.com/ipython/ipython/issues/1503 + * + * .CodeMirror span { + * vertical-align: bottom; + * } + */ +.CodeMirror { + line-height: 1.21429em; + /* Changed from 1em to our global default */ + font-size: 14px; + height: auto; + /* Changed to auto to autogrow */ + background: none; + /* Changed from white to allow our bg to show through */ +} +.CodeMirror-scroll { + /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/ + /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/ + overflow-y: hidden; + overflow-x: auto; +} +.CodeMirror-lines { + /* In CM2, this used to be 0.4em, but in CM3 it went to 4px. We need the em value because */ + /* we have set a different line-height and want this to scale with that. */ + padding: 0.4em; +} +.CodeMirror-linenumber { + padding: 0 8px 0 4px; +} +.CodeMirror-gutters { + border-bottom-left-radius: 2px; + border-top-left-radius: 2px; +} +.CodeMirror pre { + /* In CM3 this went to 4px from 0 in CM2. We need the 0 value because of how we size */ + /* .CodeMirror-lines */ + padding: 0; + border: 0; + border-radius: 0; +} +/* + +Original style from softwaremaniacs.org (c) Ivan Sagalaev +Adapted from GitHub theme + +*/ +.highlight-base { + color: #000; +} +.highlight-variable { + color: #000; +} +.highlight-variable-2 { + color: #1a1a1a; +} +.highlight-variable-3 { + color: #333333; +} +.highlight-string { + color: #BA2121; +} +.highlight-comment { + color: #408080; + font-style: italic; +} +.highlight-number { + color: #080; +} +.highlight-atom { + color: #88F; +} +.highlight-keyword { + color: #008000; + font-weight: bold; +} +.highlight-builtin { + color: #008000; +} +.highlight-error { + color: #f00; +} +.highlight-operator { + color: #AA22FF; + font-weight: bold; +} +.highlight-meta { + color: #AA22FF; +} +/* previously not defined, copying from default codemirror */ +.highlight-def { + color: #00f; +} +.highlight-string-2 { + color: #f50; +} +.highlight-qualifier { + color: #555; +} +.highlight-bracket { + color: #997; +} +.highlight-tag { + color: #170; +} +.highlight-attribute { + color: #00c; +} +.highlight-header { + color: blue; +} +.highlight-quote { + color: #090; +} +.highlight-link { + color: #00c; +} +/* apply the same style to codemirror */ +.cm-s-ipython span.cm-keyword { + color: #008000; + font-weight: bold; +} +.cm-s-ipython span.cm-atom { + color: #88F; +} +.cm-s-ipython span.cm-number { + color: #080; +} +.cm-s-ipython span.cm-def { + color: #00f; +} +.cm-s-ipython span.cm-variable { + color: #000; +} +.cm-s-ipython span.cm-operator { + color: #AA22FF; + font-weight: bold; +} +.cm-s-ipython span.cm-variable-2 { + color: #1a1a1a; +} +.cm-s-ipython span.cm-variable-3 { + color: #333333; +} +.cm-s-ipython span.cm-comment { + color: #408080; + font-style: italic; +} +.cm-s-ipython span.cm-string { + color: #BA2121; +} +.cm-s-ipython span.cm-string-2 { + color: #f50; +} +.cm-s-ipython span.cm-meta { + color: #AA22FF; +} +.cm-s-ipython span.cm-qualifier { + color: #555; +} +.cm-s-ipython span.cm-builtin { + color: #008000; +} +.cm-s-ipython span.cm-bracket { + color: #997; +} +.cm-s-ipython span.cm-tag { + color: #170; +} +.cm-s-ipython span.cm-attribute { + color: #00c; +} +.cm-s-ipython span.cm-header { + color: blue; +} +.cm-s-ipython span.cm-quote { + color: #090; +} +.cm-s-ipython span.cm-link { + color: #00c; +} +.cm-s-ipython span.cm-error { + color: #f00; +} +.cm-s-ipython span.cm-tab { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=); + background-position: right; + background-repeat: no-repeat; +} +div.output_wrapper { + /* this position must be relative to enable descendents to be absolute within it */ + position: relative; + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: vertical; + -moz-box-align: stretch; + display: box; + box-orient: vertical; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: column; + align-items: stretch; + z-index: 1; +} +/* class for the output area when it should be height-limited */ +div.output_scroll { + /* ideally, this would be max-height, but FF barfs all over that */ + height: 24em; + /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */ + width: 100%; + overflow: auto; + border-radius: 2px; + -webkit-box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.8); + box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.8); + display: block; +} +/* output div while it is collapsed */ +div.output_collapsed { + margin: 0px; + padding: 0px; + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: vertical; + -moz-box-align: stretch; + display: box; + box-orient: vertical; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: column; + align-items: stretch; +} +div.out_prompt_overlay { + height: 100%; + padding: 0px 0.4em; + position: absolute; + border-radius: 2px; +} +div.out_prompt_overlay:hover { + /* use inner shadow to get border that is computed the same on WebKit/FF */ + -webkit-box-shadow: inset 0 0 1px #000; + box-shadow: inset 0 0 1px #000; + background: rgba(240, 240, 240, 0.5); +} +div.output_prompt { + color: #D84315; +} +/* This class is the outer container of all output sections. */ +div.output_area { + padding: 0px; + page-break-inside: avoid; + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: horizontal; + -moz-box-align: stretch; + display: box; + box-orient: horizontal; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: row; + align-items: stretch; +} +div.output_area .MathJax_Display { + text-align: left !important; +} +div.output_area .rendered_html table { + margin-left: 0; + margin-right: 0; +} +div.output_area .rendered_html img { + margin-left: 0; + margin-right: 0; +} +div.output_area img, +div.output_area svg { + max-width: 100%; + height: auto; +} +div.output_area img.unconfined, +div.output_area svg.unconfined { + max-width: none; +} +/* This is needed to protect the pre formating from global settings such + as that of bootstrap */ +.output { + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: vertical; + -moz-box-align: stretch; + display: box; + box-orient: vertical; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: column; + align-items: stretch; +} +@media (max-width: 540px) { + div.output_area { + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: vertical; + -moz-box-align: stretch; + display: box; + box-orient: vertical; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: column; + align-items: stretch; + } +} +div.output_area pre { + margin: 0; + padding: 0; + border: 0; + vertical-align: baseline; + color: black; + background-color: transparent; + border-radius: 0; +} +/* This class is for the output subarea inside the output_area and after + the prompt div. */ +div.output_subarea { + overflow-x: auto; + padding: 0.4em; + /* Old browsers */ + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; + /* Modern browsers */ + flex: 1; + max-width: calc(100% - 14ex); +} +div.output_scroll div.output_subarea { + overflow-x: visible; +} +/* The rest of the output_* classes are for special styling of the different + output types */ +/* all text output has this class: */ +div.output_text { + text-align: left; + color: #000; + /* This has to match that of the the CodeMirror class line-height below */ + line-height: 1.21429em; +} +/* stdout/stderr are 'text' as well as 'stream', but execute_result/error are *not* streams */ +div.output_stderr { + background: #fdd; + /* very light red background for stderr */ +} +div.output_latex { + text-align: left; +} +/* Empty output_javascript divs should have no height */ +div.output_javascript:empty { + padding: 0; +} +.js-error { + color: darkred; +} +/* raw_input styles */ +div.raw_input_container { + line-height: 1.21429em; + padding-top: 5px; +} +pre.raw_input_prompt { + /* nothing needed here. */ +} +input.raw_input { + font-family: monospace; + font-size: inherit; + color: inherit; + width: auto; + /* make sure input baseline aligns with prompt */ + vertical-align: baseline; + /* padding + margin = 0.5em between prompt and cursor */ + padding: 0em 0.25em; + margin: 0em 0.25em; +} +input.raw_input:focus { + box-shadow: none; +} +p.p-space { + margin-bottom: 10px; +} +div.output_unrecognized { + padding: 5px; + font-weight: bold; + color: red; +} +div.output_unrecognized a { + color: inherit; + text-decoration: none; +} +div.output_unrecognized a:hover { + color: inherit; + text-decoration: none; +} +.rendered_html { + color: #000; + /* any extras will just be numbers: */ +} +.rendered_html em { + font-style: italic; +} +.rendered_html strong { + font-weight: bold; +} +.rendered_html u { + text-decoration: underline; +} +.rendered_html :link { + text-decoration: underline; +} +.rendered_html :visited { + text-decoration: underline; +} +.rendered_html h1 { + font-size: 185.7%; + margin: 1.08em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h2 { + font-size: 157.1%; + margin: 1.27em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h3 { + font-size: 128.6%; + margin: 1.55em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h4 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h5 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; + font-style: italic; +} +.rendered_html h6 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; + font-style: italic; +} +.rendered_html h1:first-child { + margin-top: 0.538em; +} +.rendered_html h2:first-child { + margin-top: 0.636em; +} +.rendered_html h3:first-child { + margin-top: 0.777em; +} +.rendered_html h4:first-child { + margin-top: 1em; +} +.rendered_html h5:first-child { + margin-top: 1em; +} +.rendered_html h6:first-child { + margin-top: 1em; +} +.rendered_html ul { + list-style: disc; + margin: 0em 2em; + padding-left: 0px; +} +.rendered_html ul ul { + list-style: square; + margin: 0em 2em; +} +.rendered_html ul ul ul { + list-style: circle; + margin: 0em 2em; +} +.rendered_html ol { + list-style: decimal; + margin: 0em 2em; + padding-left: 0px; +} +.rendered_html ol ol { + list-style: upper-alpha; + margin: 0em 2em; +} +.rendered_html ol ol ol { + list-style: lower-alpha; + margin: 0em 2em; +} +.rendered_html ol ol ol ol { + list-style: lower-roman; + margin: 0em 2em; +} +.rendered_html ol ol ol ol ol { + list-style: decimal; + margin: 0em 2em; +} +.rendered_html * + ul { + margin-top: 1em; +} +.rendered_html * + ol { + margin-top: 1em; +} +.rendered_html hr { + color: black; + background-color: black; +} +.rendered_html pre { + margin: 1em 2em; +} +.rendered_html pre, +.rendered_html code { + border: 0; + background-color: #fff; + color: #000; + font-size: 100%; + padding: 0px; +} +.rendered_html blockquote { + margin: 1em 2em; +} +.rendered_html table { + margin-left: auto; + margin-right: auto; + border: 1px solid black; + border-collapse: collapse; +} +.rendered_html tr, +.rendered_html th, +.rendered_html td { + border: 1px solid black; + border-collapse: collapse; + margin: 1em 2em; +} +.rendered_html td, +.rendered_html th { + text-align: left; + vertical-align: middle; + padding: 4px; +} +.rendered_html th { + font-weight: bold; +} +.rendered_html * + table { + margin-top: 1em; +} +.rendered_html p { + text-align: left; +} +.rendered_html * + p { + margin-top: 1em; +} +.rendered_html img { + display: block; + margin-left: auto; + margin-right: auto; +} +.rendered_html * + img { + margin-top: 1em; +} +.rendered_html img, +.rendered_html svg { + max-width: 100%; + height: auto; +} +.rendered_html img.unconfined, +.rendered_html svg.unconfined { + max-width: none; +} +div.text_cell { + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: horizontal; + -moz-box-align: stretch; + display: box; + box-orient: horizontal; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: row; + align-items: stretch; +} +@media (max-width: 540px) { + div.text_cell > div.prompt { + display: none; + } +} +div.text_cell_render { + /*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/ + outline: none; + resize: none; + width: inherit; + border-style: none; + padding: 0.5em 0.5em 0.5em 0.4em; + color: #000; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} +a.anchor-link:link { + text-decoration: none; + padding: 0px 20px; + visibility: hidden; +} +h1:hover .anchor-link, +h2:hover .anchor-link, +h3:hover .anchor-link, +h4:hover .anchor-link, +h5:hover .anchor-link, +h6:hover .anchor-link { + visibility: visible; +} +.text_cell.rendered .input_area { + display: none; +} +.text_cell.rendered .rendered_html { + overflow-x: auto; + overflow-y: hidden; +} +.text_cell.unrendered .text_cell_render { + display: none; +} +.cm-header-1, +.cm-header-2, +.cm-header-3, +.cm-header-4, +.cm-header-5, +.cm-header-6 { + font-weight: bold; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +.cm-header-1 { + font-size: 185.7%; +} +.cm-header-2 { + font-size: 157.1%; +} +.cm-header-3 { + font-size: 128.6%; +} +.cm-header-4 { + font-size: 110%; +} +.cm-header-5 { + font-size: 100%; + font-style: italic; +} +.cm-header-6 { + font-size: 100%; + font-style: italic; +} +/*! +* +* IPython notebook webapp +* +*/ +@media (max-width: 767px) { + .notebook_app { + padding-left: 0px; + padding-right: 0px; + } +} +#ipython-main-app { + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + height: 100%; +} +div#notebook_panel { + margin: 0px; + padding: 0px; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + height: 100%; +} +div#notebook { + font-size: 14px; + line-height: 20px; + overflow-y: hidden; + overflow-x: auto; + width: 100%; + /* This spaces the page away from the edge of the notebook area */ + padding-top: 20px; + margin: 0px; + outline: none; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + min-height: 100%; +} +@media not print { + #notebook-container { + padding: 15px; + background-color: #fff; + min-height: 0; + -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); + box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); + } +} +@media print { + #notebook-container { + width: 100%; + } +} +div.ui-widget-content { + border: 1px solid #ababab; + outline: none; +} +pre.dialog { + background-color: #f7f7f7; + border: 1px solid #ddd; + border-radius: 2px; + padding: 0.4em; + padding-left: 2em; +} +p.dialog { + padding: 0.2em; +} +/* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems + to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do. + */ +pre, +code, +kbd, +samp { + white-space: pre-wrap; +} +#fonttest { + font-family: monospace; +} +p { + margin-bottom: 0; +} +.end_space { + min-height: 100px; + transition: height .2s ease; +} +.notebook_app > #header { + -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); + box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); +} +@media not print { + .notebook_app { + background-color: #EEE; + } +} +kbd { + border-style: solid; + border-width: 1px; + box-shadow: none; + margin: 2px; + padding-left: 2px; + padding-right: 2px; + padding-top: 1px; + padding-bottom: 1px; +} +/* CSS for the cell toolbar */ +.celltoolbar { + border: thin solid #CFCFCF; + border-bottom: none; + background: #EEE; + border-radius: 2px 2px 0px 0px; + width: 100%; + height: 29px; + padding-right: 4px; + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: horizontal; + -moz-box-align: stretch; + display: box; + box-orient: horizontal; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: row; + align-items: stretch; + /* Old browsers */ + -webkit-box-pack: end; + -moz-box-pack: end; + box-pack: end; + /* Modern browsers */ + justify-content: flex-end; + display: -webkit-flex; +} +@media print { + .celltoolbar { + display: none; + } +} +.ctb_hideshow { + display: none; + vertical-align: bottom; +} +/* ctb_show is added to the ctb_hideshow div to show the cell toolbar. + Cell toolbars are only shown when the ctb_global_show class is also set. +*/ +.ctb_global_show .ctb_show.ctb_hideshow { + display: block; +} +.ctb_global_show .ctb_show + .input_area, +.ctb_global_show .ctb_show + div.text_cell_input, +.ctb_global_show .ctb_show ~ div.text_cell_render { + border-top-right-radius: 0px; + border-top-left-radius: 0px; +} +.ctb_global_show .ctb_show ~ div.text_cell_render { + border: 1px solid #cfcfcf; +} +.celltoolbar { + font-size: 87%; + padding-top: 3px; +} +.celltoolbar select { + display: block; + width: 100%; + height: 32px; + padding: 6px 12px; + font-size: 13px; + line-height: 1.42857143; + color: #555555; + background-color: #fff; + background-image: none; + border: 1px solid #ccc; + border-radius: 2px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 1px; + width: inherit; + font-size: inherit; + height: 22px; + padding: 0px; + display: inline-block; +} +.celltoolbar select:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); +} +.celltoolbar select::-moz-placeholder { + color: #999; + opacity: 1; +} +.celltoolbar select:-ms-input-placeholder { + color: #999; +} +.celltoolbar select::-webkit-input-placeholder { + color: #999; +} +.celltoolbar select::-ms-expand { + border: 0; + background-color: transparent; +} +.celltoolbar select[disabled], +.celltoolbar select[readonly], +fieldset[disabled] .celltoolbar select { + background-color: #eeeeee; + opacity: 1; +} +.celltoolbar select[disabled], +fieldset[disabled] .celltoolbar select { + cursor: not-allowed; +} +textarea.celltoolbar select { + height: auto; +} +select.celltoolbar select { + height: 30px; + line-height: 30px; +} +textarea.celltoolbar select, +select[multiple].celltoolbar select { + height: auto; +} +.celltoolbar label { + margin-left: 5px; + margin-right: 5px; +} +.completions { + position: absolute; + z-index: 110; + overflow: hidden; + border: 1px solid #ababab; + border-radius: 2px; + -webkit-box-shadow: 0px 6px 10px -1px #adadad; + box-shadow: 0px 6px 10px -1px #adadad; + line-height: 1; +} +.completions select { + background: white; + outline: none; + border: none; + padding: 0px; + margin: 0px; + overflow: auto; + font-family: monospace; + font-size: 110%; + color: #000; + width: auto; +} +.completions select option.context { + color: #286090; +} +#kernel_logo_widget { + float: right !important; + float: right; +} +#kernel_logo_widget .current_kernel_logo { + display: none; + margin-top: -1px; + margin-bottom: -1px; + width: 32px; + height: 32px; +} +#menubar { + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + margin-top: 1px; +} +#menubar .navbar { + border-top: 1px; + border-radius: 0px 0px 2px 2px; + margin-bottom: 0px; +} +#menubar .navbar-toggle { + float: left; + padding-top: 7px; + padding-bottom: 7px; + border: none; +} +#menubar .navbar-collapse { + clear: left; +} +.nav-wrapper { + border-bottom: 1px solid #e7e7e7; +} +i.menu-icon { + padding-top: 4px; +} +ul#help_menu li a { + overflow: hidden; + padding-right: 2.2em; +} +ul#help_menu li a i { + margin-right: -1.2em; +} +.dropdown-submenu { + position: relative; +} +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; +} +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} +.dropdown-submenu > a:after { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + display: block; + content: "\f0da"; + float: right; + color: #333333; + margin-top: 2px; + margin-right: -10px; +} +.dropdown-submenu > a:after.pull-left { + margin-right: .3em; +} +.dropdown-submenu > a:after.pull-right { + margin-left: .3em; +} +.dropdown-submenu:hover > a:after { + color: #262626; +} +.dropdown-submenu.pull-left { + float: none; +} +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; +} +#notification_area { + float: right !important; + float: right; + z-index: 10; +} +.indicator_area { + float: right !important; + float: right; + color: #777; + margin-left: 5px; + margin-right: 5px; + width: 11px; + z-index: 10; + text-align: center; + width: auto; +} +#kernel_indicator { + float: right !important; + float: right; + color: #777; + margin-left: 5px; + margin-right: 5px; + width: 11px; + z-index: 10; + text-align: center; + width: auto; + border-left: 1px solid; +} +#kernel_indicator .kernel_indicator_name { + padding-left: 5px; + padding-right: 5px; +} +#modal_indicator { + float: right !important; + float: right; + color: #777; + margin-left: 5px; + margin-right: 5px; + width: 11px; + z-index: 10; + text-align: center; + width: auto; +} +#readonly-indicator { + float: right !important; + float: right; + color: #777; + margin-left: 5px; + margin-right: 5px; + width: 11px; + z-index: 10; + text-align: center; + width: auto; + margin-top: 2px; + margin-bottom: 0px; + margin-left: 0px; + margin-right: 0px; + display: none; +} +.modal_indicator:before { + width: 1.28571429em; + text-align: center; +} +.edit_mode .modal_indicator:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f040"; +} +.edit_mode .modal_indicator:before.pull-left { + margin-right: .3em; +} +.edit_mode .modal_indicator:before.pull-right { + margin-left: .3em; +} +.command_mode .modal_indicator:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: ' '; +} +.command_mode .modal_indicator:before.pull-left { + margin-right: .3em; +} +.command_mode .modal_indicator:before.pull-right { + margin-left: .3em; +} +.kernel_idle_icon:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f10c"; +} +.kernel_idle_icon:before.pull-left { + margin-right: .3em; +} +.kernel_idle_icon:before.pull-right { + margin-left: .3em; +} +.kernel_busy_icon:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f111"; +} +.kernel_busy_icon:before.pull-left { + margin-right: .3em; +} +.kernel_busy_icon:before.pull-right { + margin-left: .3em; +} +.kernel_dead_icon:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f1e2"; +} +.kernel_dead_icon:before.pull-left { + margin-right: .3em; +} +.kernel_dead_icon:before.pull-right { + margin-left: .3em; +} +.kernel_disconnected_icon:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f127"; +} +.kernel_disconnected_icon:before.pull-left { + margin-right: .3em; +} +.kernel_disconnected_icon:before.pull-right { + margin-left: .3em; +} +.notification_widget { + color: #777; + z-index: 10; + background: rgba(240, 240, 240, 0.5); + margin-right: 4px; + color: #333; + background-color: #fff; + border-color: #ccc; +} +.notification_widget:focus, +.notification_widget.focus { + color: #333; + background-color: #e6e6e6; + border-color: #8c8c8c; +} +.notification_widget:hover { + color: #333; + background-color: #e6e6e6; + border-color: #adadad; +} +.notification_widget:active, +.notification_widget.active, +.open > .dropdown-toggle.notification_widget { + color: #333; + background-color: #e6e6e6; + border-color: #adadad; +} +.notification_widget:active:hover, +.notification_widget.active:hover, +.open > .dropdown-toggle.notification_widget:hover, +.notification_widget:active:focus, +.notification_widget.active:focus, +.open > .dropdown-toggle.notification_widget:focus, +.notification_widget:active.focus, +.notification_widget.active.focus, +.open > .dropdown-toggle.notification_widget.focus { + color: #333; + background-color: #d4d4d4; + border-color: #8c8c8c; +} +.notification_widget:active, +.notification_widget.active, +.open > .dropdown-toggle.notification_widget { + background-image: none; +} +.notification_widget.disabled:hover, +.notification_widget[disabled]:hover, +fieldset[disabled] .notification_widget:hover, +.notification_widget.disabled:focus, +.notification_widget[disabled]:focus, +fieldset[disabled] .notification_widget:focus, +.notification_widget.disabled.focus, +.notification_widget[disabled].focus, +fieldset[disabled] .notification_widget.focus { + background-color: #fff; + border-color: #ccc; +} +.notification_widget .badge { + color: #fff; + background-color: #333; +} +.notification_widget.warning { + color: #fff; + background-color: #f0ad4e; + border-color: #eea236; +} +.notification_widget.warning:focus, +.notification_widget.warning.focus { + color: #fff; + background-color: #ec971f; + border-color: #985f0d; +} +.notification_widget.warning:hover { + color: #fff; + background-color: #ec971f; + border-color: #d58512; +} +.notification_widget.warning:active, +.notification_widget.warning.active, +.open > .dropdown-toggle.notification_widget.warning { + color: #fff; + background-color: #ec971f; + border-color: #d58512; +} +.notification_widget.warning:active:hover, +.notification_widget.warning.active:hover, +.open > .dropdown-toggle.notification_widget.warning:hover, +.notification_widget.warning:active:focus, +.notification_widget.warning.active:focus, +.open > .dropdown-toggle.notification_widget.warning:focus, +.notification_widget.warning:active.focus, +.notification_widget.warning.active.focus, +.open > .dropdown-toggle.notification_widget.warning.focus { + color: #fff; + background-color: #d58512; + border-color: #985f0d; +} +.notification_widget.warning:active, +.notification_widget.warning.active, +.open > .dropdown-toggle.notification_widget.warning { + background-image: none; +} +.notification_widget.warning.disabled:hover, +.notification_widget.warning[disabled]:hover, +fieldset[disabled] .notification_widget.warning:hover, +.notification_widget.warning.disabled:focus, +.notification_widget.warning[disabled]:focus, +fieldset[disabled] .notification_widget.warning:focus, +.notification_widget.warning.disabled.focus, +.notification_widget.warning[disabled].focus, +fieldset[disabled] .notification_widget.warning.focus { + background-color: #f0ad4e; + border-color: #eea236; +} +.notification_widget.warning .badge { + color: #f0ad4e; + background-color: #fff; +} +.notification_widget.success { + color: #fff; + background-color: #5cb85c; + border-color: #4cae4c; +} +.notification_widget.success:focus, +.notification_widget.success.focus { + color: #fff; + background-color: #449d44; + border-color: #255625; +} +.notification_widget.success:hover { + color: #fff; + background-color: #449d44; + border-color: #398439; +} +.notification_widget.success:active, +.notification_widget.success.active, +.open > .dropdown-toggle.notification_widget.success { + color: #fff; + background-color: #449d44; + border-color: #398439; +} +.notification_widget.success:active:hover, +.notification_widget.success.active:hover, +.open > .dropdown-toggle.notification_widget.success:hover, +.notification_widget.success:active:focus, +.notification_widget.success.active:focus, +.open > .dropdown-toggle.notification_widget.success:focus, +.notification_widget.success:active.focus, +.notification_widget.success.active.focus, +.open > .dropdown-toggle.notification_widget.success.focus { + color: #fff; + background-color: #398439; + border-color: #255625; +} +.notification_widget.success:active, +.notification_widget.success.active, +.open > .dropdown-toggle.notification_widget.success { + background-image: none; +} +.notification_widget.success.disabled:hover, +.notification_widget.success[disabled]:hover, +fieldset[disabled] .notification_widget.success:hover, +.notification_widget.success.disabled:focus, +.notification_widget.success[disabled]:focus, +fieldset[disabled] .notification_widget.success:focus, +.notification_widget.success.disabled.focus, +.notification_widget.success[disabled].focus, +fieldset[disabled] .notification_widget.success.focus { + background-color: #5cb85c; + border-color: #4cae4c; +} +.notification_widget.success .badge { + color: #5cb85c; + background-color: #fff; +} +.notification_widget.info { + color: #fff; + background-color: #5bc0de; + border-color: #46b8da; +} +.notification_widget.info:focus, +.notification_widget.info.focus { + color: #fff; + background-color: #31b0d5; + border-color: #1b6d85; +} +.notification_widget.info:hover { + color: #fff; + background-color: #31b0d5; + border-color: #269abc; +} +.notification_widget.info:active, +.notification_widget.info.active, +.open > .dropdown-toggle.notification_widget.info { + color: #fff; + background-color: #31b0d5; + border-color: #269abc; +} +.notification_widget.info:active:hover, +.notification_widget.info.active:hover, +.open > .dropdown-toggle.notification_widget.info:hover, +.notification_widget.info:active:focus, +.notification_widget.info.active:focus, +.open > .dropdown-toggle.notification_widget.info:focus, +.notification_widget.info:active.focus, +.notification_widget.info.active.focus, +.open > .dropdown-toggle.notification_widget.info.focus { + color: #fff; + background-color: #269abc; + border-color: #1b6d85; +} +.notification_widget.info:active, +.notification_widget.info.active, +.open > .dropdown-toggle.notification_widget.info { + background-image: none; +} +.notification_widget.info.disabled:hover, +.notification_widget.info[disabled]:hover, +fieldset[disabled] .notification_widget.info:hover, +.notification_widget.info.disabled:focus, +.notification_widget.info[disabled]:focus, +fieldset[disabled] .notification_widget.info:focus, +.notification_widget.info.disabled.focus, +.notification_widget.info[disabled].focus, +fieldset[disabled] .notification_widget.info.focus { + background-color: #5bc0de; + border-color: #46b8da; +} +.notification_widget.info .badge { + color: #5bc0de; + background-color: #fff; +} +.notification_widget.danger { + color: #fff; + background-color: #d9534f; + border-color: #d43f3a; +} +.notification_widget.danger:focus, +.notification_widget.danger.focus { + color: #fff; + background-color: #c9302c; + border-color: #761c19; +} +.notification_widget.danger:hover { + color: #fff; + background-color: #c9302c; + border-color: #ac2925; +} +.notification_widget.danger:active, +.notification_widget.danger.active, +.open > .dropdown-toggle.notification_widget.danger { + color: #fff; + background-color: #c9302c; + border-color: #ac2925; +} +.notification_widget.danger:active:hover, +.notification_widget.danger.active:hover, +.open > .dropdown-toggle.notification_widget.danger:hover, +.notification_widget.danger:active:focus, +.notification_widget.danger.active:focus, +.open > .dropdown-toggle.notification_widget.danger:focus, +.notification_widget.danger:active.focus, +.notification_widget.danger.active.focus, +.open > .dropdown-toggle.notification_widget.danger.focus { + color: #fff; + background-color: #ac2925; + border-color: #761c19; +} +.notification_widget.danger:active, +.notification_widget.danger.active, +.open > .dropdown-toggle.notification_widget.danger { + background-image: none; +} +.notification_widget.danger.disabled:hover, +.notification_widget.danger[disabled]:hover, +fieldset[disabled] .notification_widget.danger:hover, +.notification_widget.danger.disabled:focus, +.notification_widget.danger[disabled]:focus, +fieldset[disabled] .notification_widget.danger:focus, +.notification_widget.danger.disabled.focus, +.notification_widget.danger[disabled].focus, +fieldset[disabled] .notification_widget.danger.focus { + background-color: #d9534f; + border-color: #d43f3a; +} +.notification_widget.danger .badge { + color: #d9534f; + background-color: #fff; +} +div#pager { + background-color: #fff; + font-size: 14px; + line-height: 20px; + overflow: hidden; + display: none; + position: fixed; + bottom: 0px; + width: 100%; + max-height: 50%; + padding-top: 8px; + -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); + box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); + /* Display over codemirror */ + z-index: 100; + /* Hack which prevents jquery ui resizable from changing top. */ + top: auto !important; +} +div#pager pre { + line-height: 1.21429em; + color: #000; + background-color: #f7f7f7; + padding: 0.4em; +} +div#pager #pager-button-area { + position: absolute; + top: 8px; + right: 20px; +} +div#pager #pager-contents { + position: relative; + overflow: auto; + width: 100%; + height: 100%; +} +div#pager #pager-contents #pager-container { + position: relative; + padding: 15px 0px; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} +div#pager .ui-resizable-handle { + top: 0px; + height: 8px; + background: #f7f7f7; + border-top: 1px solid #cfcfcf; + border-bottom: 1px solid #cfcfcf; + /* This injects handle bars (a short, wide = symbol) for + the resize handle. */ +} +div#pager .ui-resizable-handle::after { + content: ''; + top: 2px; + left: 50%; + height: 3px; + width: 30px; + margin-left: -15px; + position: absolute; + border-top: 1px solid #cfcfcf; +} +.quickhelp { + /* Old browsers */ + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: stretch; + display: -moz-box; + -moz-box-orient: horizontal; + -moz-box-align: stretch; + display: box; + box-orient: horizontal; + box-align: stretch; + /* Modern browsers */ + display: flex; + flex-direction: row; + align-items: stretch; + line-height: 1.8em; +} +.shortcut_key { + display: inline-block; + width: 21ex; + text-align: right; + font-family: monospace; +} +.shortcut_descr { + display: inline-block; + /* Old browsers */ + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; + /* Modern browsers */ + flex: 1; +} +span.save_widget { + margin-top: 6px; +} +span.save_widget span.filename { + height: 1em; + line-height: 1em; + padding: 3px; + margin-left: 16px; + border: none; + font-size: 146.5%; + border-radius: 2px; +} +span.save_widget span.filename:hover { + background-color: #e6e6e6; +} +span.checkpoint_status, +span.autosave_status { + font-size: small; +} +@media (max-width: 767px) { + span.save_widget { + font-size: small; + } + span.checkpoint_status, + span.autosave_status { + display: none; + } +} +@media (min-width: 768px) and (max-width: 991px) { + span.checkpoint_status { + display: none; + } + span.autosave_status { + font-size: x-small; + } +} +.toolbar { + padding: 0px; + margin-left: -5px; + margin-top: 2px; + margin-bottom: 5px; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} +.toolbar select, +.toolbar label { + width: auto; + vertical-align: middle; + margin-right: 2px; + margin-bottom: 0px; + display: inline; + font-size: 92%; + margin-left: 0.3em; + margin-right: 0.3em; + padding: 0px; + padding-top: 3px; +} +.toolbar .btn { + padding: 2px 8px; +} +.toolbar .btn-group { + margin-top: 0px; + margin-left: 5px; +} +#maintoolbar { + margin-bottom: -3px; + margin-top: -8px; + border: 0px; + min-height: 27px; + margin-left: 0px; + padding-top: 11px; + padding-bottom: 3px; +} +#maintoolbar .navbar-text { + float: none; + vertical-align: middle; + text-align: right; + margin-left: 5px; + margin-right: 0px; + margin-top: 0px; +} +.select-xs { + height: 24px; +} +.pulse, +.dropdown-menu > li > a.pulse, +li.pulse > a.dropdown-toggle, +li.pulse.open > a.dropdown-toggle { + background-color: #F37626; + color: white; +} +/** + * Primary styles + * + * Author: Jupyter Development Team + */ +/** WARNING IF YOU ARE EDITTING THIS FILE, if this is a .css file, It has a lot + * of chance of beeing generated from the ../less/[samename].less file, you can + * try to get back the less file by reverting somme commit in history + **/ +/* + * We'll try to get something pretty, so we + * have some strange css to have the scroll bar on + * the left with fix button on the top right of the tooltip + */ +@-moz-keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} +@-webkit-keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} +@-moz-keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} +@-webkit-keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} +/*properties of tooltip after "expand"*/ +.bigtooltip { + overflow: auto; + height: 200px; + -webkit-transition-property: height; + -webkit-transition-duration: 500ms; + -moz-transition-property: height; + -moz-transition-duration: 500ms; + transition-property: height; + transition-duration: 500ms; +} +/*properties of tooltip before "expand"*/ +.smalltooltip { + -webkit-transition-property: height; + -webkit-transition-duration: 500ms; + -moz-transition-property: height; + -moz-transition-duration: 500ms; + transition-property: height; + transition-duration: 500ms; + text-overflow: ellipsis; + overflow: hidden; + height: 80px; +} +.tooltipbuttons { + position: absolute; + padding-right: 15px; + top: 0px; + right: 0px; +} +.tooltiptext { + /*avoid the button to overlap on some docstring*/ + padding-right: 30px; +} +.ipython_tooltip { + max-width: 700px; + /*fade-in animation when inserted*/ + -webkit-animation: fadeOut 400ms; + -moz-animation: fadeOut 400ms; + animation: fadeOut 400ms; + -webkit-animation: fadeIn 400ms; + -moz-animation: fadeIn 400ms; + animation: fadeIn 400ms; + vertical-align: middle; + background-color: #f7f7f7; + overflow: visible; + border: #ababab 1px solid; + outline: none; + padding: 3px; + margin: 0px; + padding-left: 7px; + font-family: monospace; + min-height: 50px; + -moz-box-shadow: 0px 6px 10px -1px #adadad; + -webkit-box-shadow: 0px 6px 10px -1px #adadad; + box-shadow: 0px 6px 10px -1px #adadad; + border-radius: 2px; + position: absolute; + z-index: 1000; +} +.ipython_tooltip a { + float: right; +} +.ipython_tooltip .tooltiptext pre { + border: 0; + border-radius: 0; + font-size: 100%; + background-color: #f7f7f7; +} +.pretooltiparrow { + left: 0px; + margin: 0px; + top: -16px; + width: 40px; + height: 16px; + overflow: hidden; + position: absolute; +} +.pretooltiparrow:before { + background-color: #f7f7f7; + border: 1px #ababab solid; + z-index: 11; + content: ""; + position: absolute; + left: 15px; + top: 10px; + width: 25px; + height: 25px; + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + -o-transform: rotate(45deg); +} +ul.typeahead-list i { + margin-left: -10px; + width: 18px; +} +ul.typeahead-list { + max-height: 80vh; + overflow: auto; +} +ul.typeahead-list > li > a { + /** Firefox bug **/ + /* see https://github.com/jupyter/notebook/issues/559 */ + white-space: normal; +} +.cmd-palette .modal-body { + padding: 7px; +} +.cmd-palette form { + background: white; +} +.cmd-palette input { + outline: none; +} +.no-shortcut { + display: none; +} +.command-shortcut:before { + content: "(command)"; + padding-right: 3px; + color: #777777; +} +.edit-shortcut:before { + content: "(edit)"; + padding-right: 3px; + color: #777777; +} +#find-and-replace #replace-preview .match, +#find-and-replace #replace-preview .insert { + background-color: #BBDEFB; + border-color: #90CAF9; + border-style: solid; + border-width: 1px; + border-radius: 0px; +} +#find-and-replace #replace-preview .replace .match { + background-color: #FFCDD2; + border-color: #EF9A9A; + border-radius: 0px; +} +#find-and-replace #replace-preview .replace .insert { + background-color: #C8E6C9; + border-color: #A5D6A7; + border-radius: 0px; +} +#find-and-replace #replace-preview { + max-height: 60vh; + overflow: auto; +} +#find-and-replace #replace-preview pre { + padding: 5px 10px; +} +.terminal-app { + background: #EEE; +} +.terminal-app #header { + background: #fff; + -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); + box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); +} +.terminal-app .terminal { + width: 100%; + float: left; + font-family: monospace; + color: white; + background: black; + padding: 0.4em; + border-radius: 2px; + -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.4); + box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.4); +} +.terminal-app .terminal, +.terminal-app .terminal dummy-screen { + line-height: 1em; + font-size: 14px; +} +.terminal-app .terminal .xterm-rows { + padding: 10px; +} +.terminal-app .terminal-cursor { + color: black; + background: white; +} +.terminal-app #terminado-container { + margin-top: 20px; +} +/*# sourceMappingURL=style.min.css.map */ + +/*! +* +* Pygments "default" style with ".highlight" css_class +* +*/ +.highlight .hll { background-color: #ffffcc } +.highlight .c { color: #408080; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #BC7A00 } /* Comment.Preproc */ +.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #7D9029 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #A0A000 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #BB6688 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/relate/static/css/ipynb.style.min.css b/relate/static/css/ipynb.style.min.css new file mode 100644 index 0000000000000000000000000000000000000000..4638dd726ce2f3b9c3a6b0c615167fad5403ec26 --- /dev/null +++ b/relate/static/css/ipynb.style.min.css @@ -0,0 +1 @@ +div.cell,div.inner_cell{-webkit-box-align:stretch;display:flex}.CodeMirror,.prompt,div.input_area,div.output_text{line-height:1.21429em}.cm-header-5,.cm-header-6,.highlight-comment,.rendered_html em,.rendered_html h5,.rendered_html h6{font-style:italic}.ansibold{font-weight:700}.ansiblack{color:#000}.ansired{color:#8b0000}.ansigreen{color:#006400}.ansiyellow{color:#c4a000}.ansiblue{color:#00008b}.ansipurple{color:#9400d3}.ansicyan{color:#4682b4}.ansigray{color:gray}.ansibgblack{background-color:#000}.ansibgred{background-color:red}.ansibggreen{background-color:green}.ansibgyellow{background-color:#ff0}.ansibgblue{background-color:#00f}.ansibgpurple{background-color:#ff00ff}.ansibgcyan{background-color:#0ff}.ansibggray{background-color:gray}div.cell{-webkit-box-orient:vertical;-moz-box-orient:vertical;-moz-box-align:stretch;box-orient:vertical;box-align:stretch;flex-direction:column;align-items:stretch;border-radius:2px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;border-width:1px;border-style:solid;border-color:transparent;width:100%;padding:5px;margin:0;outline:0;background:linear-gradient(to right,transparent -40px,transparent 1px,transparent 1px,transparent 100%)}div.inner_cell,div.output_wrapper{-webkit-box-orient:vertical;-moz-box-orient:vertical}div.cell.jupyter-soft-selected{border-left-color:#E3F2FD;border-left-width:1px;padding-left:5px;border-right-color:#E3F2FD;border-right-width:1px;background:#E3F2FD}@media print{div.cell.jupyter-soft-selected{border-color:transparent}}div.cell.selected{border-color:#ababab;border-left-width:0;padding-left:6px;background:linear-gradient(to right,#42A5F5 -40px,#42A5F5 5px,transparent 5px,transparent 100%)}@media print{div.cell.selected{border-color:transparent}}div.cell.selected.jupyter-soft-selected{border-left-width:0;padding-left:6px;background:linear-gradient(to right,#42A5F5 -40px,#42A5F5 7px,#E3F2FD 7px,#E3F2FD 100%)}.edit_mode div.cell.selected{border-color:#66BB6A;border-left-width:0;padding-left:6px;background:linear-gradient(to right,#66BB6A -40px,#66BB6A 5px,transparent 5px,transparent 100%)}@media print{.edit_mode div.cell.selected{border-color:transparent}div.code_cell{page-break-inside:avoid}}.prompt{min-width:14ex;padding:.4em;margin:0;font-family:monospace;text-align:right;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}div.inner_cell{min-width:0;-moz-box-align:stretch;box-orient:vertical;box-align:stretch;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}div.input_area{border:1px solid #cfcfcf;border-radius:2px;background:#f7f7f7}div.prompt:empty{padding-top:0;padding-bottom:0}div.unrecognized_cell{padding:5px 5px 5px 0;-webkit-box-orient:horizontal;-webkit-box-align:stretch;-moz-box-orient:horizontal;-moz-box-align:stretch;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.unrecognized_cell .inner_cell{border-radius:2px;padding:5px;font-weight:700;color:red;border:1px solid #cfcfcf;background:#eaeaea}div.unrecognized_cell .inner_cell a,div.unrecognized_cell .inner_cell a:hover{color:inherit;text-decoration:none}@media (max-width:540px){.prompt{text-align:left}div.unrecognized_cell>div.prompt{display:none}}div.input,div.output_wrapper{-webkit-box-align:stretch;display:flex}div.input{page-break-inside:avoid;-webkit-box-orient:horizontal;-moz-box-orient:horizontal;-moz-box-align:stretch;box-orient:horizontal;box-align:stretch;flex-direction:row;align-items:stretch}@media (max-width:540px){div.input{-webkit-box-orient:vertical;-webkit-box-align:stretch;-moz-box-orient:vertical;-moz-box-align:stretch;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}}div.input_prompt{color:#303F9F;border-top:1px solid transparent}div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent}div.input_area>div.highlight>pre{margin:0;border:none;padding:0;background-color:transparent}.CodeMirror{font-size:14px;height:auto;background:0 0}.CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}.CodeMirror-lines{padding:.4em}.CodeMirror-linenumber{padding:0 8px 0 4px}.CodeMirror-gutters{border-bottom-left-radius:2px;border-top-left-radius:2px}.CodeMirror pre{padding:0;border:0;border-radius:0}.highlight-base,.highlight-variable{color:#000}.highlight-variable-2{color:#1a1a1a}.highlight-variable-3{color:#333}.highlight-string{color:#BA2121}.highlight-comment{color:#408080}.highlight-number{color:#080}.highlight-atom{color:#88F}.highlight-keyword{color:green;font-weight:700}.highlight-builtin{color:green}.highlight-error{color:red}.highlight-operator{color:#A2F;font-weight:700}.highlight-meta{color:#A2F}.highlight-def{color:#00f}.highlight-string-2{color:#f50}.highlight-qualifier{color:#555}.highlight-bracket{color:#997}.highlight-tag{color:#170}.highlight-attribute{color:#00c}.highlight-header{color:#00f}.highlight-quote{color:#090}.highlight-link{color:#00c}.cm-s-ipython span.cm-keyword{color:green;font-weight:700}.cm-s-ipython span.cm-atom{color:#88F}.cm-s-ipython span.cm-number{color:#080}.cm-s-ipython span.cm-def{color:#00f}.cm-s-ipython span.cm-variable{color:#000}.cm-s-ipython span.cm-operator{color:#A2F;font-weight:700}.cm-s-ipython span.cm-variable-2{color:#1a1a1a}.cm-s-ipython span.cm-variable-3{color:#333}.cm-s-ipython span.cm-comment{color:#408080;font-style:italic}.cm-s-ipython span.cm-string{color:#BA2121}.cm-s-ipython span.cm-string-2{color:#f50}.cm-s-ipython span.cm-meta{color:#A2F}.cm-s-ipython span.cm-qualifier{color:#555}.cm-s-ipython span.cm-builtin{color:green}.cm-s-ipython span.cm-bracket{color:#997}.cm-s-ipython span.cm-tag{color:#170}.cm-s-ipython span.cm-attribute{color:#00c}.cm-s-ipython span.cm-header{color:#00f}.cm-s-ipython span.cm-quote{color:#090}.cm-s-ipython span.cm-link{color:#00c}.cm-s-ipython span.cm-error{color:red}.cm-s-ipython span.cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=) right no-repeat}div.output_wrapper{position:relative;-moz-box-align:stretch;box-orient:vertical;box-align:stretch;flex-direction:column;align-items:stretch;z-index:1}div.output_area,div.output_collapsed{-webkit-box-align:stretch;display:flex}div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:2px;-webkit-box-shadow:inset 0 2px 8px rgba(0,0,0,.8);box-shadow:inset 0 2px 8px rgba(0,0,0,.8);display:block}div.output_collapsed{margin:0;padding:0;-webkit-box-orient:vertical;-moz-box-orient:vertical;-moz-box-align:stretch;box-orient:vertical;box-align:stretch;flex-direction:column;align-items:stretch}div.output_area,div.text_cell{-webkit-box-orient:horizontal}div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:2px}div.out_prompt_overlay:hover{-webkit-box-shadow:inset 0 0 1px #000;box-shadow:inset 0 0 1px #000;background:rgba(240,240,240,.5)}div.output_prompt{color:#D84315}div.output_area{padding:0;page-break-inside:avoid;-moz-box-orient:horizontal;-moz-box-align:stretch;box-orient:horizontal;box-align:stretch;flex-direction:row;align-items:stretch}.output,div.text_cell{-webkit-box-align:stretch}div.output_area .MathJax_Display{text-align:left!important}.rendered_html p,div.output_latex,div.output_text{text-align:left}div.output_area .rendered_html img,div.output_area .rendered_html table{margin-left:0;margin-right:0}div.output_area img,div.output_area svg{max-width:100%;height:auto}div.output_area img.unconfined,div.output_area svg.unconfined{max-width:none}.output{-webkit-box-orient:vertical;-moz-box-orient:vertical;-moz-box-align:stretch;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}@media (max-width:540px){div.output_area{-webkit-box-orient:vertical;-webkit-box-align:stretch;-moz-box-orient:vertical;-moz-box-align:stretch;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}}.celltoolbar,div.text_cell{-moz-box-orient:horizontal}div.output_area pre{margin:0;padding:0;border:0;vertical-align:baseline;color:#000;background-color:transparent;border-radius:0}div.output_subarea{overflow-x:auto;padding:.4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1;max-width:calc(100% - 14ex)}div.output_scroll div.output_subarea{overflow-x:visible}.text_cell.rendered .rendered_html,div#notebook{overflow-y:hidden;overflow-x:auto}div.output_text{color:#000}div.output_stderr{background:#fdd}div.output_javascript:empty{padding:0}.js-error{color:#8b0000}div.raw_input_container{line-height:1.21429em;padding-top:5px}input.raw_input{font-family:monospace;font-size:inherit;color:inherit;width:auto;vertical-align:baseline;padding:0 .25em;margin:0 .25em}input.raw_input:focus{box-shadow:none}p.p-space{margin-bottom:10px}div.output_unrecognized{padding:5px;font-weight:700;color:red}div.output_unrecognized a,div.output_unrecognized a:hover{color:inherit;text-decoration:none}.rendered_html{color:#000}.rendered_html strong{font-weight:700}.rendered_html :link,.rendered_html :visited,.rendered_html u{text-decoration:underline}.rendered_html h1{font-size:185.7%;margin:1.08em 0 0;font-weight:700;line-height:1}.rendered_html h2{font-size:157.1%;margin:1.27em 0 0;font-weight:700;line-height:1}.rendered_html h3{font-size:128.6%;margin:1.55em 0 0;font-weight:700;line-height:1}.rendered_html h4,.rendered_html h5,.rendered_html h6{margin:2em 0 0;line-height:1;font-size:100%;font-weight:700}.rendered_html h1:first-child{margin-top:.538em}.rendered_html h2:first-child{margin-top:.636em}.rendered_html h3:first-child{margin-top:.777em}.rendered_html h4:first-child,.rendered_html h5:first-child,.rendered_html h6:first-child{margin-top:1em}.rendered_html ul{list-style:disc;margin:0 2em;padding-left:0}.rendered_html ul ul{list-style:square;margin:0 2em}.rendered_html ul ul ul{list-style:circle;margin:0 2em}.rendered_html ol{list-style:decimal;margin:0 2em;padding-left:0}.rendered_html ol ol{list-style:upper-alpha;margin:0 2em}.rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}.rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}.rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}.rendered_html *+ol,.rendered_html *+ul{margin-top:1em}.rendered_html blockquote,.rendered_html pre{margin:1em 2em}.rendered_html hr{color:#000;background-color:#000}.rendered_html code,.rendered_html pre{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}.rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}.rendered_html td,.rendered_html th,.rendered_html tr{border:1px solid #000;border-collapse:collapse;margin:1em 2em}.rendered_html *+img,.rendered_html *+p,.rendered_html *+table{margin-top:1em}.rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}.rendered_html th{font-weight:700}.rendered_html img{display:block;margin-left:auto;margin-right:auto}.rendered_html img,.rendered_html svg{max-width:100%;height:auto}.rendered_html img.unconfined,.rendered_html svg.unconfined{max-width:none}div.text_cell{-moz-box-align:stretch;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.text_cell.rendered .input_area,.text_cell.unrendered .text_cell_render{display:none}@media (max-width:540px){div.text_cell>div.prompt{display:none}}div.text_cell_render{outline:0;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible}.cm-header-1,.cm-header-2,.cm-header-3,.cm-header-4,.cm-header-5,.cm-header-6{font-weight:700;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}#fonttest,.completions select{font-family:monospace}.cm-header-1{font-size:185.7%}.cm-header-2{font-size:157.1%}.cm-header-3{font-size:128.6%}.cm-header-4{font-size:110%}.cm-header-5,.cm-header-6{font-size:100%}@media (max-width:767px){.notebook_app{padding-left:0;padding-right:0}}#ipython-main-app{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;height:100%}div#notebook_panel{margin:0;padding:0;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;height:100%}div#notebook{font-size:14px;line-height:20px;width:100%;padding-top:20px;margin:0;outline:0;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;min-height:100%}@media not print{#notebook-container{padding:15px;background-color:#fff;min-height:0;-webkit-box-shadow:0 0 12px 1px rgba(87,87,87,.2);box-shadow:0 0 12px 1px rgba(87,87,87,.2)}}.notebook_app>#header,div#pager{-webkit-box-shadow:0 0 12px 1px rgba(87,87,87,.2)}div.ui-widget-content{border:1px solid #ababab;outline:0}pre.dialog{background-color:#f7f7f7;border:1px solid #ddd;border-radius:2px;padding:.4em .4em .4em 2em}p.dialog{padding:.2em}code,kbd,pre,samp{white-space:pre-wrap}p{margin-bottom:0}.end_space{min-height:100px;transition:height .2s ease}.notebook_app>#header{box-shadow:0 0 12px 1px rgba(87,87,87,.2)}@media not print{.notebook_app{background-color:#EEE}}kbd{border-style:solid;border-width:1px;box-shadow:none;margin:2px;padding:1px 2px}.celltoolbar{border:thin solid #CFCFCF;border-bottom:none;background:#EEE;border-radius:2px 2px 0 0;width:100%;height:29px;padding-right:4px;-webkit-box-orient:horizontal;-webkit-box-align:stretch;-moz-box-align:stretch;box-orient:horizontal;box-align:stretch;flex-direction:row;align-items:stretch;-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end;display:-webkit-flex;font-size:87%;padding-top:3px}@media print{#notebook-container{width:100%}.celltoolbar{display:none}}.ctb_hideshow{display:none;vertical-align:bottom}.ctb_global_show .ctb_show.ctb_hideshow{display:block}.ctb_global_show .ctb_show+.input_area,.ctb_global_show .ctb_show+div.text_cell_input,.ctb_global_show .ctb_show~div.text_cell_render{border-top-right-radius:0;border-top-left-radius:0}.ctb_global_show .ctb_show~div.text_cell_render{border:1px solid #cfcfcf}.celltoolbar select{color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;line-height:1.5;border-radius:1px;width:inherit;font-size:inherit;height:22px;padding:0;display:inline-block}.celltoolbar select:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.celltoolbar select::-moz-placeholder{color:#999;opacity:1}.celltoolbar select:-ms-input-placeholder{color:#999}.celltoolbar select::-webkit-input-placeholder{color:#999}.celltoolbar select::-ms-expand{border:0;background-color:transparent}.celltoolbar select[disabled],.celltoolbar select[readonly],fieldset[disabled] .celltoolbar select{background-color:#eee;opacity:1}.celltoolbar select[disabled],fieldset[disabled] .celltoolbar select{cursor:not-allowed}textarea.celltoolbar select{height:auto}select.celltoolbar select{height:30px;line-height:30px}select[multiple].celltoolbar select,textarea.celltoolbar select{height:auto}.celltoolbar label{margin-left:5px;margin-right:5px}.completions{position:absolute;z-index:110;overflow:hidden;border:1px solid #ababab;border-radius:2px;-webkit-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad;line-height:1}.completions select{background:#fff;outline:0;border:none;padding:0;margin:0;overflow:auto;font-size:110%;color:#000;width:auto}.dropdown-submenu>a:after,.edit_mode .modal_indicator:before{font:normal normal normal 14px/1 FontAwesome;text-rendering:auto;-moz-osx-font-smoothing:grayscale}.completions select option.context{color:#286090}#kernel_logo_widget{float:right!important;float:right}#kernel_logo_widget .current_kernel_logo{display:none;margin-top:-1px;margin-bottom:-1px;width:32px;height:32px}#menubar{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;margin-top:1px}#menubar .navbar{border-top:1px;border-radius:0 0 2px 2px;margin-bottom:0}#menubar .navbar-toggle{float:left;padding-top:7px;padding-bottom:7px;border:none}#menubar .navbar-collapse{clear:left}.nav-wrapper{border-bottom:1px solid #e7e7e7}i.menu-icon{padding-top:4px}ul#help_menu li a{overflow:hidden;padding-right:2.2em}ul#help_menu li a i{margin-right:-1.2em}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropdown-submenu>a:after{font-size:inherit;-webkit-font-smoothing:antialiased;display:block;content:"\f0da";float:right;color:#333;margin-top:2px;margin-right:-10px}.dropdown-submenu>a:after.pull-left{margin-right:.3em}.dropdown-submenu>a:after.pull-right{margin-left:.3em}.dropdown-submenu:hover>a:after{color:#262626}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px}#kernel_indicator,#modal_indicator,.indicator_area{margin-left:5px;margin-right:5px}#notification_area{float:right!important;float:right;z-index:10}.indicator_area{float:right!important;float:right;color:#777;z-index:10;text-align:center;width:auto}#kernel_indicator,#modal_indicator,#readonly-indicator{float:right!important;color:#777;width:auto;text-align:center;z-index:10}#kernel_indicator{float:right;border-left:1px solid}#kernel_indicator .kernel_indicator_name{padding-left:5px;padding-right:5px}#modal_indicator{float:right}#readonly-indicator{float:right;display:none;margin:2px 0 0}.command_mode .modal_indicator:before.pull-left,.edit_mode .modal_indicator:before.pull-left,.kernel_busy_icon:before.pull-left,.kernel_dead_icon:before.pull-left,.kernel_disconnected_icon:before.pull-left,.kernel_idle_icon:before.pull-left{margin-right:.3em}.command_mode .modal_indicator:before.pull-right,.edit_mode .modal_indicator:before.pull-right,.kernel_busy_icon:before.pull-right,.kernel_dead_icon:before.pull-right,.kernel_disconnected_icon:before.pull-right,.kernel_idle_icon:before.pull-right{margin-left:.3em}.modal_indicator:before{width:1.28571429em;text-align:center}.edit_mode .modal_indicator:before{display:inline-block;font-size:inherit;-webkit-font-smoothing:antialiased;content:"\f040"}.command_mode .modal_indicator:before,.kernel_idle_icon:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;text-rendering:auto}.command_mode .modal_indicator:before{font-size:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:' '}.kernel_idle_icon:before{font-size:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f10c"}.kernel_busy_icon:before,.kernel_dead_icon:before{font:normal normal normal 14px/1 FontAwesome;display:inline-block;text-rendering:auto;-moz-osx-font-smoothing:grayscale}.kernel_busy_icon:before{font-size:inherit;-webkit-font-smoothing:antialiased;content:"\f111"}.kernel_dead_icon:before{font-size:inherit;-webkit-font-smoothing:antialiased;content:"\f1e2"}.kernel_disconnected_icon:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f127"}.notification_widget{z-index:10;background:rgba(240,240,240,.5);margin-right:4px;color:#333;background-color:#fff;border-color:#ccc}.notification_widget.active,.notification_widget.danger.active,.notification_widget.danger:active,.notification_widget.info.active,.notification_widget.info:active,.notification_widget.success.active,.notification_widget.success:active,.notification_widget.warning.active,.notification_widget.warning:active,.notification_widget:active,.open>.dropdown-toggle.notification_widget,.open>.dropdown-toggle.notification_widget.danger,.open>.dropdown-toggle.notification_widget.info,.open>.dropdown-toggle.notification_widget.success,.open>.dropdown-toggle.notification_widget.warning{background-image:none}.notification_widget.focus,.notification_widget:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.notification_widget.active,.notification_widget:active,.notification_widget:hover,.open>.dropdown-toggle.notification_widget{color:#333;background-color:#e6e6e6;border-color:#adadad}.notification_widget.active.focus,.notification_widget.active:focus,.notification_widget.active:hover,.notification_widget:active.focus,.notification_widget:active:focus,.notification_widget:active:hover,.open>.dropdown-toggle.notification_widget.focus,.open>.dropdown-toggle.notification_widget:focus,.open>.dropdown-toggle.notification_widget:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.notification_widget.disabled.focus,.notification_widget.disabled:focus,.notification_widget.disabled:hover,.notification_widget[disabled].focus,.notification_widget[disabled]:focus,.notification_widget[disabled]:hover,fieldset[disabled] .notification_widget.focus,fieldset[disabled] .notification_widget:focus,fieldset[disabled] .notification_widget:hover{background-color:#fff;border-color:#ccc}.notification_widget .badge{color:#fff;background-color:#333}.notification_widget.warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.notification_widget.warning.focus,.notification_widget.warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.notification_widget.warning.active,.notification_widget.warning:active,.notification_widget.warning:hover,.open>.dropdown-toggle.notification_widget.warning{color:#fff;background-color:#ec971f;border-color:#d58512}.notification_widget.warning.active.focus,.notification_widget.warning.active:focus,.notification_widget.warning.active:hover,.notification_widget.warning:active.focus,.notification_widget.warning:active:focus,.notification_widget.warning:active:hover,.open>.dropdown-toggle.notification_widget.warning.focus,.open>.dropdown-toggle.notification_widget.warning:focus,.open>.dropdown-toggle.notification_widget.warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.notification_widget.warning.disabled.focus,.notification_widget.warning.disabled:focus,.notification_widget.warning.disabled:hover,.notification_widget.warning[disabled].focus,.notification_widget.warning[disabled]:focus,.notification_widget.warning[disabled]:hover,fieldset[disabled] .notification_widget.warning.focus,fieldset[disabled] .notification_widget.warning:focus,fieldset[disabled] .notification_widget.warning:hover{background-color:#f0ad4e;border-color:#eea236}.notification_widget.warning .badge{color:#f0ad4e;background-color:#fff}.notification_widget.success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.notification_widget.success.focus,.notification_widget.success:focus{color:#fff;background-color:#449d44;border-color:#255625}.notification_widget.success.active,.notification_widget.success:active,.notification_widget.success:hover,.open>.dropdown-toggle.notification_widget.success{color:#fff;background-color:#449d44;border-color:#398439}.notification_widget.success.active.focus,.notification_widget.success.active:focus,.notification_widget.success.active:hover,.notification_widget.success:active.focus,.notification_widget.success:active:focus,.notification_widget.success:active:hover,.open>.dropdown-toggle.notification_widget.success.focus,.open>.dropdown-toggle.notification_widget.success:focus,.open>.dropdown-toggle.notification_widget.success:hover{color:#fff;background-color:#398439;border-color:#255625}.notification_widget.success.disabled.focus,.notification_widget.success.disabled:focus,.notification_widget.success.disabled:hover,.notification_widget.success[disabled].focus,.notification_widget.success[disabled]:focus,.notification_widget.success[disabled]:hover,fieldset[disabled] .notification_widget.success.focus,fieldset[disabled] .notification_widget.success:focus,fieldset[disabled] .notification_widget.success:hover{background-color:#5cb85c;border-color:#4cae4c}.notification_widget.success .badge{color:#5cb85c;background-color:#fff}.notification_widget.info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.notification_widget.info.focus,.notification_widget.info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.notification_widget.info.active,.notification_widget.info:active,.notification_widget.info:hover,.open>.dropdown-toggle.notification_widget.info{color:#fff;background-color:#31b0d5;border-color:#269abc}.notification_widget.info.active.focus,.notification_widget.info.active:focus,.notification_widget.info.active:hover,.notification_widget.info:active.focus,.notification_widget.info:active:focus,.notification_widget.info:active:hover,.open>.dropdown-toggle.notification_widget.info.focus,.open>.dropdown-toggle.notification_widget.info:focus,.open>.dropdown-toggle.notification_widget.info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.notification_widget.info.disabled.focus,.notification_widget.info.disabled:focus,.notification_widget.info.disabled:hover,.notification_widget.info[disabled].focus,.notification_widget.info[disabled]:focus,.notification_widget.info[disabled]:hover,fieldset[disabled] .notification_widget.info.focus,fieldset[disabled] .notification_widget.info:focus,fieldset[disabled] .notification_widget.info:hover{background-color:#5bc0de;border-color:#46b8da}.notification_widget.info .badge{color:#5bc0de;background-color:#fff}.notification_widget.danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.notification_widget.danger.focus,.notification_widget.danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.notification_widget.danger.active,.notification_widget.danger:active,.notification_widget.danger:hover,.open>.dropdown-toggle.notification_widget.danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.notification_widget.danger.active.focus,.notification_widget.danger.active:focus,.notification_widget.danger.active:hover,.notification_widget.danger:active.focus,.notification_widget.danger:active:focus,.notification_widget.danger:active:hover,.open>.dropdown-toggle.notification_widget.danger.focus,.open>.dropdown-toggle.notification_widget.danger:focus,.open>.dropdown-toggle.notification_widget.danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.notification_widget.danger.disabled.focus,.notification_widget.danger.disabled:focus,.notification_widget.danger.disabled:hover,.notification_widget.danger[disabled].focus,.notification_widget.danger[disabled]:focus,.notification_widget.danger[disabled]:hover,fieldset[disabled] .notification_widget.danger.focus,fieldset[disabled] .notification_widget.danger:focus,fieldset[disabled] .notification_widget.danger:hover{background-color:#d9534f;border-color:#d43f3a}.notification_widget.danger .badge{color:#d9534f;background-color:#fff}div#pager{background-color:#fff;font-size:14px;line-height:20px;overflow:hidden;display:none;position:fixed;bottom:0;width:100%;max-height:50%;padding-top:8px;box-shadow:0 0 12px 1px rgba(87,87,87,.2);z-index:100;top:auto!important}div#pager pre{line-height:1.21429em;color:#000;background-color:#f7f7f7;padding:.4em}div#pager #pager-button-area{position:absolute;top:8px;right:20px}div#pager #pager-contents{position:relative;overflow:auto;width:100%;height:100%}div#pager #pager-contents #pager-container{position:relative;padding:15px 0;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}div#pager .ui-resizable-handle{top:0;height:8px;background:#f7f7f7;border-top:1px solid #cfcfcf;border-bottom:1px solid #cfcfcf}div#pager .ui-resizable-handle::after{content:'';top:2px;left:50%;height:3px;width:30px;margin-left:-15px;position:absolute;border-top:1px solid #cfcfcf}.quickhelp{-webkit-box-orient:horizontal;-webkit-box-align:stretch;-moz-box-orient:horizontal;-moz-box-align:stretch;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;line-height:1.8em}.shortcut_key{display:inline-block;width:21ex;text-align:right;font-family:monospace}.shortcut_descr{display:inline-block;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}span.save_widget{margin-top:6px}span.save_widget span.filename{height:1em;line-height:1em;padding:3px;margin-left:16px;border:none;font-size:146.5%;border-radius:2px}span.save_widget span.filename:hover{background-color:#e6e6e6}span.autosave_status,span.checkpoint_status{font-size:small}@media (max-width:767px){span.save_widget{font-size:small}span.autosave_status,span.checkpoint_status{display:none}}@media (min-width:768px) and (max-width:991px){span.checkpoint_status{display:none}span.autosave_status{font-size:x-small}}.toolbar{padding:0;margin-left:-5px;margin-top:2px;margin-bottom:5px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}.toolbar label,.toolbar select{width:auto;vertical-align:middle;margin-bottom:0;display:inline;font-size:92%;margin-left:.3em;margin-right:.3em;padding:3px 0 0}.toolbar .btn{padding:2px 8px}.toolbar .btn-group{margin-top:0;margin-left:5px}#maintoolbar{margin-bottom:-3px;margin-top:-8px;border:0;min-height:27px;margin-left:0;padding-top:11px;padding-bottom:3px}#maintoolbar .navbar-text{float:none;vertical-align:middle;text-align:right;margin-left:5px;margin-right:0;margin-top:0}.select-xs{height:24px}.dropdown-menu>li>a.pulse,.pulse,li.pulse.open>a.dropdown-toggle,li.pulse>a.dropdown-toggle{background-color:#F37626;color:#fff}@-moz-keyframes fadeOut{from{opacity:1}to{opacity:0}}@-webkit-keyframes fadeOut{from{opacity:1}to{opacity:0}}@-moz-keyframes fadeIn{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadeIn{from{opacity:0}to{opacity:1}}.bigtooltip{overflow:auto;height:200px;-webkit-transition-property:height;-webkit-transition-duration:.5s;-moz-transition-property:height;-moz-transition-duration:.5s;transition-property:height;transition-duration:.5s}.smalltooltip{-webkit-transition-property:height;-webkit-transition-duration:.5s;-moz-transition-property:height;-moz-transition-duration:.5s;transition-property:height;transition-duration:.5s;text-overflow:ellipsis;overflow:hidden;height:80px}.tooltipbuttons{position:absolute;padding-right:15px;top:0;right:0}.tooltiptext{padding-right:30px}.ipython_tooltip{max-width:700px;-webkit-animation:fadeIn .4s;-moz-animation:fadeIn .4s;animation:fadeIn .4s;vertical-align:middle;background-color:#f7f7f7;overflow:visible;border:1px solid #ababab;outline:0;padding:3px 3px 3px 7px;margin:0;font-family:monospace;min-height:50px;-moz-box-shadow:0 6px 10px -1px #adadad;-webkit-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad;border-radius:2px;position:absolute;z-index:1000}.ipython_tooltip a{float:right}.ipython_tooltip .tooltiptext pre{border:0;border-radius:0;font-size:100%;background-color:#f7f7f7}.pretooltiparrow{left:0;margin:0;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute}.pretooltiparrow:before{background-color:#f7f7f7;border:1px solid #ababab;z-index:11;content:"";position:absolute;left:15px;top:10px;width:25px;height:25px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg)}ul.typeahead-list i{margin-left:-10px;width:18px}ul.typeahead-list{max-height:80vh;overflow:auto}ul.typeahead-list>li>a{white-space:normal}.cmd-palette .modal-body{padding:7px}.cmd-palette form{background:#fff}.cmd-palette input{outline:0}.no-shortcut{display:none}.command-shortcut:before{content:"(command)";padding-right:3px;color:#777}.edit-shortcut:before{content:"(edit)";padding-right:3px;color:#777}#find-and-replace #replace-preview .insert,#find-and-replace #replace-preview .match{background-color:#BBDEFB;border-color:#90CAF9;border-style:solid;border-width:1px;border-radius:0}#find-and-replace #replace-preview .replace .match{background-color:#FFCDD2;border-color:#EF9A9A;border-radius:0}#find-and-replace #replace-preview .replace .insert{background-color:#C8E6C9;border-color:#A5D6A7;border-radius:0}#find-and-replace #replace-preview{max-height:60vh;overflow:auto}#find-and-replace #replace-preview pre{padding:5px 10px}.terminal-app{background:#EEE}.terminal-app #header{background:#fff;-webkit-box-shadow:0 0 12px 1px rgba(87,87,87,.2);box-shadow:0 0 12px 1px rgba(87,87,87,.2)}.terminal-app .terminal{width:100%;float:left;font-family:monospace;color:#fff;background:#000;padding:.4em;border-radius:2px;-webkit-box-shadow:0 0 12px 1px rgba(87,87,87,.4);box-shadow:0 0 12px 1px rgba(87,87,87,.4)}.terminal-app .terminal,.terminal-app .terminal dummy-screen{line-height:1em;font-size:14px}.terminal-app .terminal .xterm-rows{padding:10px}.terminal-app .terminal-cursor{color:#000;background:#fff}.terminal-app #terminado-container{margin-top:20px}.highlight .hll{background-color:#ffc}.highlight .c{color:#408080;font-style:italic}.highlight .err{border:1px solid red}.highlight .k{color:green;font-weight:700}.highlight .o{color:#666}.highlight .ch,.highlight .cm{color:#408080;font-style:italic}.highlight .cp{color:#BC7A00}.highlight .c1,.highlight .cpf,.highlight .cs{color:#408080;font-style:italic}.highlight .gd{color:#A00000}.highlight .ge{font-style:italic}.highlight .gr{color:red}.highlight .gh{color:navy;font-weight:700}.highlight .gi{color:#00A000}.highlight .go{color:#888}.highlight .gp{color:navy;font-weight:700}.highlight .gs{font-weight:700}.highlight .gu{color:purple;font-weight:700}.highlight .gt{color:#04D}.highlight .kc,.highlight .kd,.highlight .kn{color:green;font-weight:700}.highlight .kp{color:green}.highlight .kr{color:green;font-weight:700}.highlight .kt{color:#B00040}.highlight .m{color:#666}.highlight .s{color:#BA2121}.highlight .na{color:#7D9029}.highlight .nb{color:green}.highlight .nc{color:#00F;font-weight:700}.highlight .no{color:#800}.highlight .nd{color:#A2F}.highlight .ni{color:#999;font-weight:700}.highlight .ne{color:#D2413A;font-weight:700}.highlight .nf{color:#00F}.highlight .nl{color:#A0A000}.highlight .nn{color:#00F;font-weight:700}.highlight .nt{color:green;font-weight:700}.highlight .nv{color:#19177C}.highlight .ow{color:#A2F;font-weight:700}.highlight .w{color:#bbb}.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:#666}.highlight .s2,.highlight .sb,.highlight .sc{color:#BA2121}.highlight .sd{color:#BA2121;font-style:italic}.highlight .se{color:#B62;font-weight:700}.highlight .sh{color:#BA2121}.highlight .si{color:#B68;font-weight:700}.highlight .sx{color:green}.highlight .sr{color:#B68}.highlight .s1{color:#BA2121}.highlight .ss{color:#19177C}.highlight .bp{color:green}.highlight .vc,.highlight .vg,.highlight .vi{color:#19177C}.highlight .il{color:#666} \ No newline at end of file diff --git a/relate/static/css/style.css b/relate/static/css/style.css index d6e523a1883f6d0ffa795e97ababd6399800e18d..d5165d141743b39684b0b237ac23646f4a4c644f 100644 --- a/relate/static/css/style.css +++ b/relate/static/css/style.css @@ -333,4 +333,19 @@ a .sensitive { text-decoration: none; } +/* if not using "markdown.extensions.codehilite" extension */ +div.cell.border-box-sizing.code_cell.rendered > div.input > div.inner_cell > div.input_area > pre { + margin: 0; +} + +div.rendered_html div.highlight { + border: 1px solid #cfcfcf; + border-radius: 2px; + background: #f7f7f7; +} + +div.rendered_html div.highlight > pre{ + margin: 0.4em; + background-color: transparent; +} /* vim: set foldmethod=marker: */ diff --git a/relate/templates/base.html b/relate/templates/base.html index 2b29df1419147c6a7b4eea7279486e5ae48ab6f1..79ecaca0c0941fea465ec25793cf71206bb6e8e0 100644 --- a/relate/templates/base.html +++ b/relate/templates/base.html @@ -28,7 +28,8 @@ {% endblock %} {% block head_assets_local %} - + + {% endblock %} {% block head_assets_form_media %} diff --git a/requirements.txt b/requirements.txt index ee8118169d8608af598fa1b756a3b7827e5784cd..3dc2f8e9ad884e797326ec402c9b7d914898130c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -113,4 +113,11 @@ typing # For unittest by mock (only required for Py2) # mock +# For rendering ipython notebook +nbconvert>=5.2.1 +IPython + +# For parsing and edit html +lxml + # vim: foldmethod=marker diff --git a/tests/test_checks.py b/tests/test_checks.py index 1ba2cbb450194a26f72ad4e2e329ad155e43c97d..64b39aae33938c644c3aeccbd0bf36ebae1f2b2a 100644 --- a/tests/test_checks.py +++ b/tests/test_checks.py @@ -675,3 +675,39 @@ class CheckRelateTemplatesDirs(CheckRelateSettingsBase): self.assertCheckMessages( ["relate_override_templates_dirs.W001", "relate_override_templates_dirs.W001"]) + + +class CheckRelateDisableCodehiliteMarkdownExtensions(CheckRelateSettingsBase): + VALID_CONF = None + VALID_CONF_NO_WARNING = True + + WARNING_CONF_NOT_BOOL1 = "some string" + WARNING_CONF_NOT_BOOL2 = ["markdown.extensions.codehilite"] + WARNING_CONF_FALSE = False + + @override_settings(RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION=VALID_CONF) + def test_valid_conf(self): + self.assertEqual(self.func(None), []) + + @override_settings( + RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION=VALID_CONF_NO_WARNING) + def test_valid_conf_no_warning(self): + self.assertEqual(self.func(None), []) + + @override_settings( + RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION=WARNING_CONF_NOT_BOOL1) + def test_warning_conf_not_bool1(self): + self.assertEqual([r.id for r in self.func(None)], + ["relate_disable_codehilite_markdown_extension.W001"]) + + @override_settings( + RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION=WARNING_CONF_NOT_BOOL2) + def test_warning_conf_not_bool2(self): + self.assertEqual([r.id for r in self.func(None)], + ["relate_disable_codehilite_markdown_extension.W001"]) + + @override_settings( + RELATE_DISABLE_CODEHILITE_MARKDOWN_EXTENSION=WARNING_CONF_FALSE) + def test_warning_conf_false(self): + self.assertEqual([r.id for r in self.func(None)], + ["relate_disable_codehilite_markdown_extension.W002"]) diff --git a/tests/test_content.py b/tests/test_content.py index 907af4764920990128c32cb2de2c8b560922efca..589e9f3c87f3b3b5f296704f53dbe22e62617693 100644 --- a/tests/test_content.py +++ b/tests/test_content.py @@ -22,6 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ +import json from django.test import TestCase from tests.base_test_mixins import ( improperly_configured_cache_patch, SingleCoursePageTestMixin) @@ -66,6 +67,323 @@ class SingleCoursePageCacheTest(SingleCoursePageTestMixin, TestCase): self.assertEqual(resp.status_code, 200) +# {{{ Test Nbconvert for rendering ipynb notebook + +QUESTION_MARKUP_FULL = """ +type: Page +id: ipynb +content: | + + # Ipython notebook Examples + + {{ render_notebook_cells("test.ipynb") }} +""" + +QUESTION_MARKUP_SLICED1 = """ +type: Page +id: ipynb +content: | + + # Ipython notebook Examples + + {{ render_notebook_cells("test.ipynb", indices=[0, 1, 2]) }} +""" + +QUESTION_MARKUP_SLICED2 = """ +type: Page +id: ipynb +content: | + + # Ipython notebook Examples + + {{ render_notebook_cells("test.ipynb", indices=[1, 2]) }} +""" + +QUESTION_MARKUP_CLEAR_MARKDOWN = """ +type: Page +id: ipynb +content: | + + # Ipython notebook Examples + + {{ render_notebook_cells("test.ipynb", clear_markdown=True) }} +""" + +QUESTION_MARKUP_CLEAR_OUTPUT = """ +type: Page +id: ipynb +content: | + + # Ipython notebook Examples + + {{ render_notebook_cells("test.ipynb", clear_output=True) }} +""" + +QUESTION_MARKUP_CLEAR_ALL = """ +type: Page +id: ipynb +content: | + + # Ipython notebook Examples + + {{ render_notebook_cells("test.ipynb", clear_markdown=True, clear_output=True) }} +""" + +MARKDOWN_PLACEHOLDER = "wzxhzdk" + +TEST_IPYNB_BYTES = json.dumps({ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# First Title of Test NoteBook" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "scrolled": True + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is function1\n" + ] + } + ], + "source": [ + "def function1():\n", + " print(\"This is function1\")\n", + "\n", + "function1()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Second Title of Test NoteBook" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": True + }, + "outputs": [], + "source": [ + "def function2():\n", + " print(\"This is function2\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is function2\n" + ] + } + ], + "source": [ + "function2()" + ] + }, + { + "cell_type": "code", + "execution_count": None, + "metadata": { + "collapsed": True + }, + "outputs": [], + "source": [ + "print(`5**18`)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}).encode() + +FIRST_TITLE_TEXT = "First Title of Test NoteBook" +SECOND_TITLE_TEXT = "Second Title of Test NoteBook" +TEXT_CELL_HTML_CLASS = "text_cell_render" +CODE_CELL_HTML_CLASS = "code_cell" +CODE_CELL_IN_STR_PATTERN = '
In[%s]:
' +CODE_CELL_PRINT_STR1 = "This is function1" +CODE_CELL_PRINT_STR2 = "This is function2" + + +def strip_nbsp(s): + """ + Returns the given HTML with ' ' (introduced by nbconvert) stripped + """ + from django.utils.encoding import force_text + return force_text(s).replace(' ', '').replace(u'\xa0', '') + + +def get_nb_html_from_response(response): + from django.utils.safestring import mark_safe + return strip_nbsp(mark_safe(response.context["body"])) + + +class NbconvertRenderTestMixin(SingleCoursePageSandboxTestBaseMixin): + def assertIsValidNbConversion(self, response): # noqa + self.assertNotContains(response, MARKDOWN_PLACEHOLDER) + self.assertNotContains(response, "```") + self.assertNotContains(response, "# First Title of Test NoteBook") + self.assertNotContains(response, "# Second Title of Test NoteBook") + + def setUp(self): + super(NbconvertRenderTestMixin, self).setUp() + patcher = mock.patch("course.content.get_repo_blob_data_cached") + self.mock_func = patcher.start() + self.mock_func.return_value = TEST_IPYNB_BYTES + self.addCleanup(patcher.stop) + + +class NbconvertRenderTest(NbconvertRenderTestMixin, TestCase): + + @classmethod + def setUpTestData(cls): # noqa + super(NbconvertRenderTest, cls).setUpTestData() + cls.c.force_login(cls.instructor_participation.user) + + def test_full_notebook_render(self): + resp = self.get_page_sandbox_preview_response(QUESTION_MARKUP_FULL) + + self.assertIsValidNbConversion(resp) + self.assertContains(resp, TEXT_CELL_HTML_CLASS, count=2) + self.assertContains(resp, CODE_CELL_HTML_CLASS, count=4) + self.assertContains(resp, FIRST_TITLE_TEXT, count=1) + self.assertContains(resp, SECOND_TITLE_TEXT, count=1) + self.assertContains(resp, CODE_CELL_PRINT_STR1, count=2) + self.assertContains(resp, CODE_CELL_PRINT_STR2, count=2) + + # backtick is properly rendered with highlight + # for "`5**18`". though this syntax is not allowed in PY3 + self.assertContains( + resp, + '`5') + + nb_html = get_nb_html_from_response(resp) + for i in range(1, 4): + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % i, nb_html) + + def test_notebook_sliced1(self): + resp = self.get_page_sandbox_preview_response(QUESTION_MARKUP_SLICED1) + self.assertIsValidNbConversion(resp) + self.assertContains(resp, TEXT_CELL_HTML_CLASS, count=2) + self.assertContains(resp, CODE_CELL_HTML_CLASS, count=1) + self.assertContains(resp, FIRST_TITLE_TEXT, count=1) + self.assertContains(resp, SECOND_TITLE_TEXT, count=1) + self.assertContains(resp, CODE_CELL_PRINT_STR1, count=2) + self.assertNotContains(resp, CODE_CELL_PRINT_STR2) + + nb_html = get_nb_html_from_response(resp) + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % 1, nb_html, count=1) + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % 2, nb_html, count=0) + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % 3, nb_html, count=0) + + def test_notebook_sliced2(self): + resp = self.get_page_sandbox_preview_response(QUESTION_MARKUP_SLICED2) + self.assertIsValidNbConversion(resp) + self.assertContains(resp, TEXT_CELL_HTML_CLASS, count=1) + self.assertContains(resp, CODE_CELL_HTML_CLASS, count=1) + self.assertNotContains(resp, FIRST_TITLE_TEXT) + self.assertContains(resp, SECOND_TITLE_TEXT, count=1) + self.assertContains(resp, CODE_CELL_PRINT_STR1, count=2) + self.assertNotContains(resp, CODE_CELL_PRINT_STR2) + + # code highlight functions (in terms of rendered ipynb notebook cells only) + import six + if six.PY3: + self.assertRegex(resp.context["body"], 'class="\w*\s*highlight[^\w]') + self.assertContains(resp, " highlight hl-ipython3") + self.assertContains(resp, + 'print' + '(', + count=1) + + nb_html = get_nb_html_from_response(resp) + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % 1, nb_html, count=1) + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % 2, nb_html, count=0) + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % 3, nb_html, count=0) + + def test_notebook_clear_markdown(self): + resp = self.get_page_sandbox_preview_response(QUESTION_MARKUP_CLEAR_MARKDOWN) + self.assertIsValidNbConversion(resp) + self.assertNotContains(resp, TEXT_CELL_HTML_CLASS) + self.assertContains(resp, CODE_CELL_HTML_CLASS, count=4) + self.assertNotContains(resp, FIRST_TITLE_TEXT) + self.assertNotContains(resp, SECOND_TITLE_TEXT) + + nb_html = get_nb_html_from_response(resp) + for i in range(1, 4): + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % i, nb_html, count=1) + + def test_notebook_clear_output(self): + resp = self.get_page_sandbox_preview_response(QUESTION_MARKUP_CLEAR_OUTPUT) + self.assertIsValidNbConversion(resp) + self.assertContains(resp, TEXT_CELL_HTML_CLASS, count=2) + self.assertContains(resp, CODE_CELL_HTML_CLASS, count=4) + self.assertContains(resp, FIRST_TITLE_TEXT, count=1) + self.assertContains(resp, SECOND_TITLE_TEXT, count=1) + self.assertContains(resp, CODE_CELL_PRINT_STR1, count=1) + self.assertContains(resp, CODE_CELL_PRINT_STR2, count=1) + + nb_html = get_nb_html_from_response(resp) + for i in range(1, 4): + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % i, nb_html, count=0) + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % "", nb_html, count=4) + + def test_notebook_clear_markdown_and_output(self): + resp = self.get_page_sandbox_preview_response(QUESTION_MARKUP_CLEAR_ALL) + self.assertIsValidNbConversion(resp) + self.assertNotContains(resp, TEXT_CELL_HTML_CLASS) + self.assertContains(resp, CODE_CELL_HTML_CLASS, count=4) + self.assertNotContains(resp, FIRST_TITLE_TEXT) + self.assertNotContains(resp, SECOND_TITLE_TEXT) + self.assertContains(resp, CODE_CELL_PRINT_STR1, count=1) + self.assertContains(resp, CODE_CELL_PRINT_STR2, count=1) + + nb_html = get_nb_html_from_response(resp) + for i in range(1, 4): + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % i, nb_html, count=0) + self.assertInHTML(CODE_CELL_IN_STR_PATTERN % "", nb_html, count=4) + + +# }}} + + TEST_SANDBOX_MARK_DOWN_PATTERN = r""" type: Page id: test_endraw