diff --git a/.gitignore b/.gitignore
index 72818e9..1d59fdc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -135,3 +135,6 @@ _contents/
# Jupyterlite
_output/
book/.jupyterlite.doit.db
+
+# TeachBooks
+**.teachbooks/
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
index 208f06a..f76fc05 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,15 +7,9 @@
[submodule "book/external/deploy-book-workflow"]
path = book/external/deploy-book-workflow
url = https://github.com/TeachBooks/deploy-book-workflow.git
-[submodule "book/external/latex-to-markdown-conversion"]
- path = book/external/latex-to-markdown-conversion
- url = https://gitlab.tudelft.nl/opentextbooks/latex-to-markdown-conversion.git
[submodule "book/external/Useful_python_code"]
path = book/external/Useful_python_code
url = https://github.com/TeachBooks/Useful_python_code.git
-[submodule "book/external/TeachBooks"]
- path = book/external/TeachBooks
- url = https://github.com/TeachBooks/TeachBooks.git
[submodule "book/external/Sphinx-Image-Inverter"]
path = book/external/Sphinx-Image-Inverter
url = https://github.com/TeachBooks/Sphinx-Image-Inverter.git
diff --git a/LICENSE b/LICENSE
index 4ea99c2..0131ab3 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
-Attribution 4.0 International
+The license of this manual itself is CC BY 4.0. The same license is used for [](external/Nested-Books) and [](external/template). The license of other included materials are provided below.:
-=======================================================================
+Attribution 4.0 International
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
@@ -52,8 +52,6 @@ exhaustive, and do not form part of our licenses.
for the public:
wiki.creativecommons.org/Considerations_for_licensees
-=======================================================================
-
Creative Commons Attribution 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree
@@ -373,8 +371,6 @@ Section 8 -- Interpretation.
processes of any jurisdiction or authority.
-=======================================================================
-
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
@@ -393,3 +389,62 @@ the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.
+
+=======================================================================
+
+[](external/annotater), [](external/deploy-book-workflow), [](external/Download-Link-Replacer), [](external/JupyterBook-Patches), [](external/Sphinx-Image-Inverter) and [](external/Useful_python_code) are licensed under BSD 3-Clause license:
+
+BSD 3-Clause License
+
+Copyright (c) 2024, TeachBooks
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=======================================================================
+
+[](external/Sphinx-Grasple-public), [](external/Sphinx-TUDelft-theme) and [](external/teachbooks-sphinx-tippy) are licensed under MIT license:
+
+MIT License
+
+Copyright (c) 2024, TeachBooks
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index c92464c..92cb94d 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# TeachBooks Manual
+[](https://github.com/TeachBooks/manual/actions/workflows/call-deploy-book.yml)
+
This manual assists you in creating and collaborating on [JupyterBooks](https://jupyterbook.org/) for educational purposes. Some parts are specifically aimed for teachers at Delft University of Technology, although all material and tools are openly available. This manual aims at providing an easy start and advanced usages for new and existing users with or without skills on this topic. it is part of TeachBooks, for more information visit [https://teachbooks.io/](https://teachbooks.io/).
## Contact
@@ -16,4 +18,4 @@ The released book can be found on on https://teachbooks.io/manual. This page sho
Some parts of this book are taken from other sources in the form of submodules (linked in the folder [book/external](book/external)). To contribute to those pages, contribute to the source repository directly with a fork and merge/pull request. If you intent to clone this boko including its submodules, clone using: `git clone --recurse-submodules git@github.com:TeachBooks/manual.git`
-Happy book building!
\ No newline at end of file
+Happy book building!
diff --git a/book/_config.yml b/book/_config.yml
index d16b980..8c6fa4e 100644
--- a/book/_config.yml
+++ b/book/_config.yml
@@ -1,8 +1,6 @@
title: TeachBooks Manual
author: TeachBooks Team, built with TeachBooks and Jupyter Book, CC BY 4.0
-logo: images/Logo_without_background.png
-
execute:
execute_notebooks: 'off'
@@ -20,6 +18,7 @@ sphinx:
- jupyterbook_patches
- teachbooks_sphinx_grasple
- sphinx_image_inverter
+ - sphinx_exercise
config:
html_js_files:
- https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js
@@ -27,6 +26,10 @@ sphinx:
use_thebe_lite: true
exclude_patterns: ["**/_*.yml", "**/*.md", "**/*.ipynb","**/*.gif","**/*.txt","**/*.json",]
html_theme_options:
+ logo:
+ text: Manual
+ image_light: TeachBooks_logo.svg
+ image_dark: TeachBooks_logo_inverted.svg
repository_url: "https://github.com/TeachBooks/manual/"
path_to_docs: "book"
repository_branch: "release"
@@ -37,3 +40,13 @@ sphinx:
thebe: true
html_show_copyright: false
html_last_updated_fmt: '%B %-d, %Y'
+ html_static_path: ["images"]
+ bibtex_default_style: myapastyle
+ bibtex_reference_style: author_year_round
+ local_extensions:
+ apastyle: _ext/
+ bracket_citation_style: _ext/
+
+
+bibtex_bibfiles:
+ - references.bib
diff --git a/book/_ext/apastyle.py b/book/_ext/apastyle.py
new file mode 100644
index 0000000..16828fe
--- /dev/null
+++ b/book/_ext/apastyle.py
@@ -0,0 +1,17 @@
+
+# from pybtex.style.formatting.unsrt import Style
+from pybtexapastyle.formatting.apa import APAStyle
+from pybtexapastyle.labels.apa import LabelStyle as APALabelStyle
+from pybtex.plugin import register_plugin
+# from pybtex.style.template import names, sentence
+
+class MyAPALabelStyle(APALabelStyle):
+ def format_label(self, entry):
+ return APALabelStyle.format_label(self, entry)
+
+class MyAPAStyle(APAStyle):
+ default_label_style = 'myapa'
+
+def setup(app):
+ register_plugin('pybtex.style.labels', 'myapa', MyAPALabelStyle)
+ register_plugin('pybtex.style.formatting', 'myapastyle', MyAPAStyle)
\ No newline at end of file
diff --git a/book/_ext/bracket_citation_style.py b/book/_ext/bracket_citation_style.py
new file mode 100644
index 0000000..cab10f3
--- /dev/null
+++ b/book/_ext/bracket_citation_style.py
@@ -0,0 +1,27 @@
+from dataclasses import dataclass, field
+import sphinxcontrib.bibtex.plugin
+
+from sphinxcontrib.bibtex.style.referencing import BracketStyle
+from sphinxcontrib.bibtex.style.referencing.author_year import AuthorYearReferenceStyle
+
+
+def bracket_style() -> BracketStyle:
+ return BracketStyle(
+ left='(',
+ right=')',
+ )
+
+
+@dataclass
+class MyReferenceStyle(AuthorYearReferenceStyle):
+ bracket_parenthetical: BracketStyle = field(default_factory=bracket_style)
+ bracket_textual: BracketStyle = field(default_factory=bracket_style)
+ bracket_author: BracketStyle = field(default_factory=bracket_style)
+ bracket_label: BracketStyle = field(default_factory=bracket_style)
+ bracket_year: BracketStyle = field(default_factory=bracket_style)
+
+
+def setup(app):
+ sphinxcontrib.bibtex.plugin.register_plugin(
+ 'sphinxcontrib.bibtex.style.referencing',
+ 'author_year_round', MyReferenceStyle)
\ No newline at end of file
diff --git a/book/_ext/pybtexapastyle/LICENSE b/book/_ext/pybtexapastyle/LICENSE
new file mode 100644
index 0000000..579d367
--- /dev/null
+++ b/book/_ext/pybtexapastyle/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Naeka
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/book/_ext/pybtexapastyle/formatting/__init__.py b/book/_ext/pybtexapastyle/formatting/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/book/_ext/pybtexapastyle/formatting/apa.py b/book/_ext/pybtexapastyle/formatting/apa.py
new file mode 100644
index 0000000..dfa5a58
--- /dev/null
+++ b/book/_ext/pybtexapastyle/formatting/apa.py
@@ -0,0 +1,486 @@
+# -*- coding:Utf-8 -*-
+from __future__ import unicode_literals
+
+import re
+import six
+
+from pybtex.plugin import find_plugin
+from pybtex.style.formatting import BaseStyle, toplevel
+from pybtex.style.template import (
+ field, first_of, href, join, optional, optional_field, sentence, tag,
+ together, words, node, FieldIsMissing
+)
+
+from pybtex.richtext import Text, Symbol
+
+
+firstlast = find_plugin('pybtex.style.names', 'lastfirst')()
+
+if six.PY2:
+ def format_pages(text):
+ dash_re = re.compile(r'-+')
+ pages = Text(Symbol('ndash')).join(
+ re.split(dash_re, six.text_type(text)))
+ if re.search('[-‒–—―]', six.text_type(text)):
+ return Text("pp.", Symbol('nbsp'), pages)
+ return Text("p.", Symbol('nbsp'), pages)
+else:
+ def format_pages(text):
+ dash_re = re.compile(r'-+')
+ pages = Text(Symbol('ndash')).join(text.split(dash_re))
+ if re.search('[-‒–—―]', str(text)):
+ return Text("pp.", Symbol('nbsp'), pages)
+ return Text("p.", Symbol('nbsp'), pages)
+
+
+pages = field('pages', apply_func=format_pages)
+date = words[field('year'), optional[", ", field('month')]]
+
+
+@node
+def apa_names(children, context, role, **kwargs):
+ """
+ Returns formatted names as an APA compliant reference list citation.
+ """
+ assert not children
+
+ try:
+ persons = context['entry'].persons[role]
+ except KeyError:
+ raise FieldIsMissing(role, context['entry'])
+
+ style = context['style']
+
+ if len(persons) > 7:
+ persons = persons[:6] + persons[-1:]
+ formatted_names = [style.format_name(
+ person, style.abbreviate_names) for person in persons]
+ return join(sep=', ', last_sep=', … ')[
+ formatted_names].format_data(context)
+ else:
+ formatted_names = [style.format_name(
+ person, style.abbreviate_names) for person in persons]
+ return join(sep=', ', sep2=', & ', last_sep=', & ')[
+ formatted_names].format_data(context)
+
+
+@node
+def editor_names(children, context, with_suffix=True, **kwargs):
+ """
+ Returns formatted editor names for inbook.
+ """
+ assert not children
+
+ try:
+ editors = context['entry'].persons['editor']
+ except KeyError:
+ raise FieldIsMissing('editor', context['entry'])
+
+ formatted_names = [
+ firstlast.format(editor, True) for editor in editors]
+
+ if with_suffix:
+ return words[
+ join(sep=', ', sep2=', & ', last_sep=', & ')[formatted_names],
+ "(Eds.)" if len(editors) > 1 else "(Ed.)"
+ ].format_data(context)
+
+ return join(sep=', ', sep2=', & ', last_sep=', & ')[
+ formatted_names
+ ].format_data(context)
+
+
+class APAStyle(BaseStyle):
+ name = 'apa'
+ default_name_style = 'lastfirst'
+ default_sorting_style = 'author_year_title'
+ default_label_style = 'apa'
+
+ def __init__(self, *args, **kwargs):
+ super(APAStyle, self).__init__(*args, **kwargs)
+ self.abbreviate_names = True
+
+ def format_names(self, role, as_sentence=True):
+ formatted_names = apa_names(role)
+ if as_sentence:
+ return sentence(capfirst=False)[formatted_names]
+ else:
+ return formatted_names
+
+ def format_author_or_editor_and_date(self, e):
+ if 'author' in e.persons and 'editor' in e.persons:
+ return sentence(sep=' ')[
+ self.format_names('author'), join["(", date, ")."],
+ self.format_editor(e, as_sentence=False)]
+ elif 'author' in e.persons:
+ return sentence(sep=' ')[
+ self.format_names('author'), join["(", date, ")"]]
+ else:
+ return sentence(sep=' ')[
+ self.format_editor(e, as_sentence=False),
+ join["(", date, ")"]]
+
+ def format_editor(self, e, as_sentence=True):
+ editors = self.format_names('editor', as_sentence=False)
+ if 'editor' not in e.persons:
+ # when parsing the template, a FieldIsMissing exception
+ # will be thrown anyway; no need to do anything now,
+ # just return the template that will throw the exception
+ return editors
+ if len(e.persons['editor']) > 1:
+ word = '(Eds.)'
+ else:
+ word = '(Ed.)'
+ result = join(sep=' ')[editors, word]
+ if as_sentence:
+ return sentence[result]
+ else:
+ return result
+
+ def format_volume(self, e, for_article=False):
+ prefix = "Vol."
+ if for_article:
+ return join[
+ tag('em')[field('volume')],
+ optional['(', field('number'), ')'],
+ ]
+ else:
+ return optional[together[prefix, field('volume')]]
+
+ def format_title(self, e, which_field, as_sentence=True):
+ formatted_title = field(
+ which_field, apply_func=lambda text: text.capitalize()
+ )
+ if as_sentence:
+ return sentence[formatted_title]
+ else:
+ return formatted_title
+
+ def format_btitle(self, e, which_field, as_sentence=True):
+ formatted_title = tag('em')[field(which_field)]
+ if as_sentence:
+ return sentence[formatted_title]
+ else:
+ return formatted_title
+
+ def format_web_refs(self, e):
+ # Based on urlbst output.web.refs
+ return sentence(add_period=False)[
+ optional[self.format_url(e)],
+ optional[self.format_eprint(e)],
+ optional[self.format_pubmed(e)],
+ optional[self.format_doi(e)],
+ ]
+
+ def format_url(self, e):
+ # Based on urlbst format.url
+ return words[
+ 'URL:',
+ href[
+ field('url', raw=True),
+ field('url', raw=True)
+ ]
+ ]
+
+ def format_pubmed(self, e):
+ # Based on urlbst format.pubmed
+ return href[
+ join[
+ 'https://www.ncbi.nlm.nih.gov/pubmed/',
+ field('pubmed', raw=True)
+ ],
+ join[
+ 'PMID:',
+ field('pubmed', raw=True)
+ ]
+ ]
+
+ def format_doi(self, e):
+ # Based on urlbst format.doi
+ return href[
+ join[
+ 'https://doi.org/',
+ field('doi', raw=True)
+ ],
+ join[
+ 'doi:',
+ field('doi', raw=True)
+ ]
+ ]
+
+ def format_eprint(self, e):
+ # Based on urlbst format.eprint
+ return href[
+ join[
+ 'https://arxiv.org/abs/',
+ field('eprint', raw=True)
+ ],
+ join[
+ 'arXiv:',
+ field('eprint', raw=True)
+ ]
+ ]
+
+ def get_article_template(self, e):
+ # Required fields: author, title, journal, year
+ # Optional fields: volume, number, pages, month, note, key
+ volume_and_pages = first_of[
+ # Volume and pages, with optional issue number
+ optional[
+ join[
+ self.format_volume(e, for_article=True),
+ optional[', ', field('pages')]
+ ],
+ ],
+ # Pages only
+ pages,
+ ]
+ template = toplevel[
+ self.format_names('author'),
+ sentence[
+ join["(", date, ")"]
+ ],
+ self.format_title(e, 'title'),
+ sentence[
+ tag('em')[field('journal')],
+ optional[volume_and_pages],
+ ],
+ sentence[optional_field('note')],
+ self.format_web_refs(e),
+ ]
+ return template
+
+ def get_book_template(self, e):
+ # Required fields: author/editor, title, publisher, year
+ # Optional fields: volume, series, address, edition, month, note, key,
+ # isbn
+ return toplevel[
+ self.format_author_or_editor_and_date(e),
+ sentence(sep=' ')[
+ self.format_btitle(e, 'title'),
+ optional[
+ sentence[
+ optional[field('edition'), ' ed.'],
+ self.format_volume(e),
+ ]
+ ]
+ ],
+ sentence(sep=': ')[
+ optional_field('address'),
+ field('publisher'),
+ ],
+ sentence[optional_field('note')],
+ ]
+
+ def get_booklet_template(self, e):
+ # Required fields: title
+ # Optional fields: author, howpublished, address, month, year, note,
+ # key
+ return toplevel[
+ sentence(sep=' ')[
+ first_of[
+ optional[self.format_names(
+ 'author', as_sentence=False)],
+ "None to claim their bones"
+ ],
+ join["(", first_of[optional[date], "n.d."], ")"]
+ ],
+ self.format_title(e, 'title'),
+ sentence[optional_field('address')],
+ sentence[optional_field('note')],
+ ]
+
+ def get_inbook_template(self, e):
+ # Required fields: author/editor, title, chapter/pages, publisher, year
+ # Optional fields: volume, series, address, edition, month, note, key
+ return toplevel[
+ sentence(sep=' ')[
+ self.format_names('author'),
+ join["(", date, ")"]
+ ],
+ self.format_title(e, 'title'),
+ sentence(sep=' ')[
+ optional[
+ "In ",
+ editor_names(),
+ ","
+ ],
+ self.format_btitle(e, 'booktitle', as_sentence=False),
+ optional[
+ join[
+ "(",
+ sentence(add_period=False)[
+ optional[field('edition'), ' ed.'],
+ self.format_volume(e),
+ pages,
+ ],
+ ")"
+ ]
+ ]
+ ],
+ sentence(sep=': ')[
+ optional_field('address'),
+ field('publisher'),
+ ],
+ sentence[optional_field('note')],
+ ]
+
+ def get_incollection_template(self, e):
+ # Required fields: author, title, booktitle, year
+ # Optional fields: editor, pages, organization, publisher, address,
+ # month, note, key
+ return toplevel[
+ self.format_author_or_editor_and_date(e),
+ self.format_title(e, 'title'),
+ sentence(sep=' ')[
+ self.format_btitle(e, 'booktitle', as_sentence=False),
+ optional["(", pages, ")"]
+ ],
+ sentence(sep=': ')[
+ optional_field('address'),
+ optional_field('publisher'),
+ ],
+ sentence[optional_field('note')],
+ ]
+
+ def get_inproceedings_template(self, e):
+ # Required fields: author, title, booktitle, year
+ # Optional fields: editor, pages, organization, publisher, address,
+ # month, note, key
+ return toplevel[
+ self.format_author_or_editor_and_date(e),
+ self.format_title(e, 'title'),
+ sentence(sep=' ')[
+ self.format_btitle(e, 'booktitle', as_sentence=False),
+ optional["(", pages, ")"]
+ ],
+ sentence(sep=': ')[
+ optional_field('address'),
+ optional_field('publisher'),
+ ],
+ sentence[optional_field('note')],
+ self.format_web_refs(e)
+ ]
+
+ def get_manual_template(self, e):
+ # Required fields: title
+ # Optional fields: author, organization, address, edition, month, year,
+ # note, key
+ return toplevel[
+ sentence(sep=' ')[
+ first_of[
+ optional[self.format_names('author', as_sentence=False)],
+ optional_field('organization'),
+ "None to claim their bones"
+ ],
+ join["(", first_of[optional[date], "n.d."], ")"]
+ ],
+ self.format_btitle(e, 'title'),
+ sentence[optional_field('address')],
+ sentence[optional_field('note')],
+ self.format_web_refs(e)
+ ]
+
+ def get_mastersthesis_template(self, e):
+ # Required fields: author, title, school, year
+ # Optional fields: address, month, note, key
+ return toplevel[
+ sentence(sep=' ')[
+ self.format_names('author'),
+ join["(", date, ")"]
+ ],
+ sentence(sep=' ')[
+ self.format_btitle(e, 'title', as_sentence=False),
+ "(Master's thesis)"
+ ],
+ sentence[
+ field('school'),
+ optional_field('address'),
+ ],
+ sentence[optional_field('note')],
+ ]
+
+ def get_misc_template(self, e):
+ # Required fields: aucun
+ # Optional fields: author, title, howpublished, month, year, note, key,
+ # type
+ template = toplevel[
+ sentence(sep=' ')[
+ first_of[
+ optional[self.format_names('author', as_sentence=False)],
+ optional_field('publisher'),
+ "None to claim their bones"
+ ],
+ join["(", first_of[optional[date], "n.d."], ")"]
+ ],
+ optional[self.format_title(e, 'title')],
+ sentence[optional_field('note')],
+ self.format_web_refs(e)
+ ]
+ return template
+
+ def get_phdthesis_template(self, e):
+ # Required fields: author, title, school, year
+ # Optional fields: address, month, note, key
+ return toplevel[
+ sentence(sep=' ')[
+ self.format_names('author'),
+ join["(", date, ")"]
+ ],
+ sentence(sep=' ')[
+ self.format_btitle(e, 'title', as_sentence=False),
+ "(Doctoral dissertation)"
+ ],
+ sentence[
+ field('school'),
+ optional_field('address'),
+ ],
+ sentence[optional_field('note')],
+ ]
+
+ def get_proceedings_template(self, e):
+ # Required fields: title, year
+ # Optional fields: editor, publisher, organization, address, month,
+ # note, key
+ return toplevel[
+ sentence(sep=' ')[
+ first_of[
+ optional[self.format_editor(e, as_sentence=False)],
+ optional_field('organization'),
+ "None to claim their bones"
+ ],
+ join["(", first_of[optional[date], "n.d."], ")"]
+ ],
+ self.format_btitle(e, 'title'),
+ sentence(sep=': ')[
+ optional_field('address'),
+ optional_field('publisher'),
+ ],
+ sentence[optional_field('note')],
+ ]
+
+ def get_techreport_template(self, e):
+ # Required fields: author, title, institution, year
+ # Optional fields: type, number, address, month, note, key
+ return toplevel[
+ sentence(sep=' ')[
+ self.format_names('author', as_sentence=False),
+ join["(", date, ")"]
+ ],
+ self.format_btitle(e, 'title'),
+ sentence[field('institution')],
+ sentence[optional_field('note')],
+ ]
+
+ def get_unpublished_template(self, e):
+ # Required fields: author, title, note
+ # Optional fields: month, year, key
+ template = toplevel[
+ sentence(sep=' ')[
+ self.format_names('author', as_sentence=False),
+ join["(", first_of[optional[date], "n.d."], ")"]
+ ],
+ self.format_btitle(e, 'title'),
+ sentence[field('note')],
+ ]
+ return template
diff --git a/book/_ext/pybtexapastyle/formatting/pybtex/style/formatting/__init__.py b/book/_ext/pybtexapastyle/formatting/pybtex/style/formatting/__init__.py
new file mode 100644
index 0000000..5ac42b8
--- /dev/null
+++ b/book/_ext/pybtexapastyle/formatting/pybtex/style/formatting/__init__.py
@@ -0,0 +1,69 @@
+from __future__ import unicode_literals
+
+from pybtex.style import FormattedEntry, FormattedBibliography
+from pybtex.style.template import node, join
+from pybtex.richtext import Symbol
+from pybtex.plugin import Plugin, find_plugin
+
+
+@node
+def toplevel(children, data):
+ return join(sep=Symbol('newblock')) [children].format_data(data)
+
+
+class BaseStyle(Plugin):
+ """
+ The base class for pythonic formatting styles.
+ """
+
+ default_name_style = None
+ default_label_style = None
+ default_sorting_style = None
+
+ def __init__(self, label_style=None, name_style=None, sorting_style=None, abbreviate_names=False, min_crossrefs=2, **kwargs):
+ self.name_style = find_plugin('pybtex.style.names', name_style or self.default_name_style)()
+ self.label_style = find_plugin('pybtex.style.labels', label_style or self.default_label_style)()
+ self.sorting_style = find_plugin('pybtex.style.sorting', sorting_style or self.default_sorting_style)()
+ self.format_name = self.name_style.format
+ self.format_labels = self.label_style.format_labels
+ self.sort = self.sorting_style.sort
+ self.abbreviate_names = abbreviate_names
+ self.min_crossrefs = min_crossrefs
+
+ def format_entries(self, entries, bib_data=None):
+ sorted_entries = self.sort(entries)
+ labels = self.format_labels(sorted_entries)
+ for label, entry in zip(labels, sorted_entries):
+ yield self.format_entry(label, entry, bib_data=bib_data)
+
+ def format_entry(self, label, entry, bib_data=None):
+ context = {
+ 'entry': entry,
+ 'style': self,
+ 'bib_data': bib_data,
+ }
+ try:
+ get_template = getattr(self, 'get_{}_template'.format(entry.type))
+ except AttributeError:
+ format_method = getattr(self, "format_" + entry.type)
+ text = format_method(context)
+ else:
+ text = get_template(entry).format_data(context)
+ return FormattedEntry(entry.key, text, label)
+
+ def format_bibliography(self, bib_data, citations=None):
+ """
+ Format bibliography entries with the given keys and return a
+ ``FormattedBibliography`` object.
+
+ :param bib_data: A :py:class:`pybtex.database.BibliographyData` object.
+ :param citations: A list of citation keys.
+ """
+
+ if citations is None:
+ citations = list(bib_data.entries.keys())
+ citations = bib_data.add_extra_citations(citations, self.min_crossrefs)
+ entries = [bib_data.entries[key] for key in citations]
+ formatted_entries = self.format_entries(entries)
+ formatted_bibliography = FormattedBibliography(formatted_entries, style=self, preamble=bib_data.preamble)
+ return formatted_bibliography
diff --git a/book/_ext/pybtexapastyle/formatting/pybtex/style/sorting/__init__.py b/book/_ext/pybtexapastyle/formatting/pybtex/style/sorting/__init__.py
new file mode 100644
index 0000000..3430087
--- /dev/null
+++ b/book/_ext/pybtexapastyle/formatting/pybtex/style/sorting/__init__.py
@@ -0,0 +1,12 @@
+from __future__ import unicode_literals
+
+
+from pybtex.plugin import Plugin
+
+
+class BaseSortingStyle(Plugin):
+ def sorting_key(self, entry):
+ raise NotImplementedError
+
+ def sort(self, entries):
+ return sorted(entries, key=self.sorting_key)
\ No newline at end of file
diff --git a/book/_ext/pybtexapastyle/formatting/pybtex/style/sorting/author_year_title.py b/book/_ext/pybtexapastyle/formatting/pybtex/style/sorting/author_year_title.py
new file mode 100644
index 0000000..c315c0c
--- /dev/null
+++ b/book/_ext/pybtexapastyle/formatting/pybtex/style/sorting/author_year_title.py
@@ -0,0 +1,39 @@
+from __future__ import unicode_literals
+
+from pybtex.style.sorting import BaseSortingStyle
+
+class SortingStyle(BaseSortingStyle):
+
+ def sorting_key(self, entry):
+ if entry.type in ('book', 'inbook'):
+ author_key = self.author_editor_key(entry)
+ elif 'author' in entry.persons:
+ author_key = self.persons_key(entry.persons['author'])
+ else:
+ author_key = ''
+ return (author_key, entry.fields.get('year', ''), entry.fields.get('title', ''))
+
+ def persons_key(self, persons):
+ return ' '.join(self.person_key(person) for person in persons)
+
+ def person_key(self, person):
+ if person.prelast_names[0] != '{' and person.last_names[0] != '{' and person.first_names[0] != '{':
+ return ' '.join((
+ ' '.join(person.prelast_names + person.last_names),
+ ' '.join(person.first_names + person.middle_names),
+ ' '.join(person.lineage_names),
+ )).lower()
+ else:
+ return ' '.join((
+ ' '.join(person.first_names + person.middle_names),
+ ' '.join(person.prelast_names + person.last_names),
+ ' '.join(person.lineage_names),
+ )).lower()
+
+ def author_editor_key(self, entry):
+ if entry.persons.get('author'):
+ return self.persons_key(entry.persons['author'])
+ elif entry.persons.get('editor'):
+ return self.persons_key(entry.persons['editor'])
+ else:
+ return ''
diff --git a/book/_ext/pybtexapastyle/labels/__init__.py b/book/_ext/pybtexapastyle/labels/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/book/_ext/pybtexapastyle/labels/apa.py b/book/_ext/pybtexapastyle/labels/apa.py
new file mode 100644
index 0000000..3632dc6
--- /dev/null
+++ b/book/_ext/pybtexapastyle/labels/apa.py
@@ -0,0 +1,67 @@
+# -*- coding:Utf-8 -*-
+from __future__ import unicode_literals
+
+from collections import Counter
+import re
+import unicodedata
+
+from pybtex.style.labels import BaseLabelStyle
+
+
+_nonalnum_pattern = re.compile('[^A-Za-z0-9 \-]+', re.UNICODE)
+
+
+def _strip_accents(s):
+ return "".join(
+ (c for c in unicodedata.normalize('NFD', s)
+ if not unicodedata.combining(c)))
+
+
+def _strip_nonalnum(parts):
+ """Strip all non-alphanumerical characters from a list of strings.
+
+ >>> print(_strip_nonalnum([u"ÅA. B. Testing 12+}[.@~_", u" 3%"]))
+ AABTesting123
+ """
+ s = "".join(parts)
+ return _nonalnum_pattern.sub("", _strip_accents(s))
+
+
+class LabelStyle(BaseLabelStyle):
+ def format_labels(self, sorted_entries):
+ labels = [self.format_label(entry) for entry in sorted_entries]
+ count = Counter(labels)
+ counted = Counter()
+ for label in labels:
+ if count[label] == 1:
+ yield label
+ else:
+ yield label # + chr(ord('a') + counted[label])
+ # counted.update([label])
+
+ def format_label(self, entry):
+ label = "Anonymous"
+ if 'author' in entry.persons:
+ label = self.format_author_or_editor_names(entry.persons['author'])
+ elif 'editor' in entry.persons:
+ label = self.format_author_or_editor_names(entry.persons['editor'])
+ elif 'organization' in entry.fields:
+ label = entry.fields['organization']
+ if label.startswith("The "):
+ label = label[4:]
+ return ''
+ # if 'year' in entry.fields:
+ # return "{}, {}".format(label, entry.fields['year'])
+ # else:
+ # return "{}, n.d.".format(label)
+
+ def format_author_or_editor_names(self, persons):
+ if len(persons)==1:
+ return _strip_nonalnum(persons[0].last_names)
+ elif len(persons)==2:
+ return "{} & {}".format(
+ _strip_nonalnum(persons[0].last_names),
+ _strip_nonalnum(persons[1].last_names))
+ else:
+ return "{} et al.".format(
+ _strip_nonalnum(persons[0].last_names))
diff --git a/book/_ext/pybtexapastyle/names/__init__.py b/book/_ext/pybtexapastyle/names/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/book/_ext/pybtexapastyle/names/firstlast.py b/book/_ext/pybtexapastyle/names/firstlast.py
new file mode 100644
index 0000000..8f23263
--- /dev/null
+++ b/book/_ext/pybtexapastyle/names/firstlast.py
@@ -0,0 +1,39 @@
+# -*- coding:Utf-8 -*-
+from __future__ import unicode_literals
+
+from pybtex.style.names import BaseNameStyle, name_part
+from pybtex.style.template import join
+
+
+class NameStyle(BaseNameStyle):
+
+ def format(self, person, abbr=False):
+ r"""
+ Format names similarly to {vv~}{ll}{, jj}{, f.} in BibTeX.
+
+ >>> from pybtex.database import Person
+ >>> name = Person(string=r"Charles Louis Xavier Joseph de la Vall{\'e}e Poussin")
+ >>> firstlast = NameStyle().format
+
+ >>> print(firstlast(name).format().render_as('latex'))
+ Charles Louis Xavier~Joseph de~la Vall{é}e~Poussin
+ >>> print(firstlast(name).format().render_as('html'))
+ Charles Louis Xavier Joseph de la Vallée Poussin
+
+ >>> print(firstlast(name, abbr=True).format().render_as('latex'))
+ C.~L. X.~J. de~la Vall{é}e~Poussin
+ >>> print(firstlast(name, abbr=True).format().render_as('html'))
+ C. L. X. J. de la Vallée Poussin
+
+ >>> name = Person(first='First', last='Last', middle='Middle')
+ >>> print(firstlast(name).format().render_as('latex'))
+ First~Middle Last
+ >>> print(firstlast(name, abbr=True).format().render_as('latex'))
+ F.~M. Last
+
+ """
+ return join[
+ name_part(abbr=abbr)[person.rich_first_names + person.rich_middle_names],
+ name_part(before=' ')[person.rich_prelast_names],
+ name_part(before=' ')[person.rich_last_names],
+ ]
diff --git a/book/_ext/pybtexapastyle/setup.py b/book/_ext/pybtexapastyle/setup.py
new file mode 100644
index 0000000..a62d122
--- /dev/null
+++ b/book/_ext/pybtexapastyle/setup.py
@@ -0,0 +1,27 @@
+import setuptools
+
+
+setuptools.setup(
+ name='pybtex-apa-style',
+ version='1.3',
+ author='Naeka',
+ author_email='contact@naeka.fr',
+ description='Pybtex APA-like style',
+ url='https://github.com/naeka/pybtex-apa-style',
+ py_modules=['formatting.apa', 'labels.apa', 'names.firstlast'],
+ entry_points={
+ 'pybtex.style.formatting': 'apa = formatting.apa:APAStyle',
+ 'pybtex.style.labels': 'apa = labels.apa:LabelStyle',
+ 'pybtex.style.names': 'firstlast = names.firstlast:NameStyle',
+ },
+ classifiers=(
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'License :: OSI Approved :: MIT License',
+ 'Operating System :: OS Independent',
+ 'Topic :: Text Processing :: Markup',
+ 'Topic :: Utilities',
+ ),
+)
diff --git a/book/_toc.yml b/book/_toc.yml
index b3ea6ca..9b7acae 100644
--- a/book/_toc.yml
+++ b/book/_toc.yml
@@ -2,7 +2,13 @@ format: jb-book
root: intro
parts:
- - caption: Getting started!
+ - caption: Your First TeachBook!
+ chapters:
+ - file: intro/book.md
+ - file: intro/workflow.md
+ - file: intro/template.md
+ - file: intro/next.md
+ - caption: Getting Going!
chapters:
- file: installation-and-setup/user_types.md
- file: installation-and-setup/git.md
@@ -13,7 +19,6 @@ parts:
- file: installation-and-setup/anaconda.md
- file: installation-and-setup/git_bash_conda_vs-code.md
- file: installation-and-setup/jupyter-book-setup.md
- - file: external/template/README.md
- file: workflows/collaboration.md
sections:
- file: workflows/milestones_issues.md
@@ -23,7 +28,11 @@ parts:
- file: workflows/merge_request.md
- file: installation-and-setup/collab
- file: installation-and-setup/tools
- - file: installation-and-setup/creating_content.md
+ - file: installation-and-setup/copyright.md
+ sections:
+ - file: installation-and-setup/copyright/considerations
+ - file: installation-and-setup/copyright/licenses
+ - file: installation-and-setup/copyright/recommendations
- caption: Features
chapters:
- file: features/overview.md
@@ -45,13 +54,16 @@ parts:
- file: basic-features/utterances.md
- file: features/easy-editing.md
sections:
- - file: external/TeachBooks/README.md
+ - file: external/template/README.md
+ - file: features/teachbooks
- file: external/deploy-book-workflow/README.md
+ - file: features/local_server
- file: external/Nested-Books/README.md
- file: features/sphinx_extensions.md
sections:
- file: external/Download-Link-Replacer/README.md
- - file: features/custom-launch-button.md
+ - file: features/custom-launch-button.md
+ - file: basic-features/utterances.md
- file: features/interactive_element.ipynb
sections:
- file: external/Sphinx-Grasple-public/README.md
@@ -70,9 +82,11 @@ parts:
- file: external/JupyterBook-Patches/README.md
- file: external/Sphinx-TUDelft-theme/README.md
- file: external/teachbooks-sphinx-tippy/README.md
+ - file: features/apa
- file: features/students
sections:
- file: external/annotater/README.md
+ - file: basic-features/hypothesis.md
- caption: Examples
chapters:
@@ -86,13 +100,18 @@ parts:
- file: examples/coding_theory_widgets.ipynb
- file: examples/parametric_questions.ipynb
- - caption: Editing tools
+ - caption: Editing Tools
chapters:
- file: tools/figmaker
- file: helper_code/intro.md
sections:
- - file: external/latex-to-markdown-conversion/README.md
+ - file: helper_code/converter.md
- file: external/Useful_python_code/snippit.ipynb
- file: external/Useful_python_code/extensionfildownloadreturn.ipynb
- file: external/Useful_python_code/figshrinker.ipynb
-
\ No newline at end of file
+
+ - caption: Miscallaneous
+ chapters:
+ - file: references.md
+ - file: credits
+ - file: contact
\ No newline at end of file
diff --git a/book/basic-features/external-features.md b/book/basic-features/external-features.md
deleted file mode 100644
index d574b30..0000000
--- a/book/basic-features/external-features.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# Externally Developed Features
-
-```{admonition} User types
-:class: tip
-This section is useful for user type 1-5.
-```
-
-This chapter includes features useful for books in the educational context, developed by various parties.
\ No newline at end of file
diff --git a/book/basic-features/hypothesis.md b/book/basic-features/hypothesis.md
index 1d490ce..0f42e79 100644
--- a/book/basic-features/hypothesis.md
+++ b/book/basic-features/hypothesis.md
@@ -1,5 +1,10 @@
# Making comments on the website: Hypothesis
+```{admonition} User types
+:class: tip
+This section is useful for user type 1-5.
+```
+
{bdg-warning}`Javascript overlay` {bdg-success}`Chrome Extension`
Hypothesis is a third-party application that allows anyone to make publicly visible comments on a website (once you create a free account). This section explains how to use and install the extension. As this tool requires an account with a third-party, we advise to use our [local-annotator](../external/annotater/README.md) with similar capabilities but which store annotations locally. By default Hypothesis stores annotations publicly, which might confuse other students.
diff --git a/book/basic-features/utterances.md b/book/basic-features/utterances.md
index 5bd350b..f82a44f 100644
--- a/book/basic-features/utterances.md
+++ b/book/basic-features/utterances.md
@@ -1,13 +1,22 @@
# Discussions in your book: Utterances
+```{admonition} User types
+:class: tip
+This section is useful for user type 3-5.
+```
+
{bdg-white}`GitHub app and Javascript script`
[Utterances 🔮](https://utteranc.es/) is a lightweight open-source widget which allows you, your colleages and your students to discuss stuff in a blog post in your book. It is build on GitHub issues, so requires a GitHub repository, although the book can be hosted anywhere (so also on GitLab).
-The [utterances website](https://utteranc.es/) clearly explains the required steps. One thing to take care of is how you want to do the issue-mapping with respect to multiple deployed versions (draft version, student version, archived versions):
-
- - `Issue title contains page pathname`/`Issue title contains page URL` is useful if you want to isolate the comments on each of the branches.
- - `Issue title contains page title` is useful if you want to show the all comments on all different branches.
+The [utterances website](https://utteranc.es/) clearly explains the required steps. Three things to take care of are:
+1. With the current setup of the [deploy book workflow on GitHub](../external/deploy-book-workflow/README.md), this widget only works on the primary branch.
+2. The baseurl is the root url of your book (the part of the url that doesn't change when opening different pages of the book). It needs to be defined in the `_config.yml` so that utteranc.es knows where to redirect users while interacting with the widget:
+```
+html:
+ baseurl : "https://.github.io/" #Replace this with your own URL
+```
+3. It's advised to use `Issue title contains page pathname` as an option on utteranc.es, because that url is most stable.
The given script can be added anywhere in your book, just copy the html-script into your `.md`-file or a markdown cell in your `.ipynb`-file. The blogpost is not visible when you do a local build of the book, build it online or use a local python server as shown in {ref}`setup-local-server`.
@@ -24,4 +33,4 @@ Below you see an example of this feature!
theme="github-light"
crossorigin="anonymous"
async>
-
\ No newline at end of file
+
diff --git a/book/contact.md b/book/contact.md
new file mode 100644
index 0000000..cf77ec0
--- /dev/null
+++ b/book/contact.md
@@ -0,0 +1,15 @@
+# Contact
+
+## Contact
+If you encounter any issues report it by clicking {octicon}`mark-github` on the top right corner of this page.
+
+If you have questions, contact the editors at TeachBooks@tudelft.nl. TU Delft account holder can also contact us in the [MS Teams Open Interactive Textbooks Community](https://teams.microsoft.com/l/team/19%3Ah9-uRcP_yYauh-VuoPFozJVUvHVOB4a0mz1ZWvh4q4Q1%40thread.tacv2/conversations?groupId=3e88c1f3-4a4f-483a-a366-7e617de9ba99&tenantId=096e524d-6929-4030-8cd3-8ab42de0887b)
+
+## Contribute
+This book will continue to develop, so feel free to contribute https://github.com/TeachBooks/manual! You can do so directly by forking this repository and creating a pull request.
+
+The released book can be found on on https://teachbooks.io/manual. This page shows the built book of the `release` branch. All branches will also be visible online, as pointed to in the actions summaries: https://github.com/TeachBooks/mirror_teachbook_manual/actions
+
+Some parts of this book are taken from other sources in the form of submodules (linked in the folder [book/external](https://github.com/TeachBooks/manual/tree/release/book/external)). To contribute to those pages, contribute to the source repository directly with a fork and merge/pull request. If you intent to clone this book including its submodules, clone using: `git clone --recurse-submodules git@github.com:TeachBooks/manual.git`
+
+
diff --git a/book/credits.md b/book/credits.md
new file mode 100644
index 0000000..443e088
--- /dev/null
+++ b/book/credits.md
@@ -0,0 +1,63 @@
+(credits)=
+# Credits and License
+
+You can refer to this book in its entirety as:
+
+> van Woudenberg, T. and Lanzafame, R. (2024), _TeachBooks Manual_. https://github.com/TeachBooks/manual. Retreived [Month, Year]. CC BY 4.0.
+
+The introduction, structure and decisions on content is done under direction of Tom van Woudenberg and Robert Lanzafame. The content is written by many contributors, of which there are many.
+
+We anticipate that the content of this book will change continuously. Therefore, if you'd like to refer to a specific chapter, we recommend using the source code directly with the citation that refers to the GitHub repository and lists the date and name of the file. Although content will be added over time, chapter titles and URL's in this book are expected to remain relatively static after Spring 2025. You can refer to individual chapters or pages within this book as:
+
+> `` (2024), ``. In _TeachBooks Manual_. https://github.com/TeachBooks/manual (chapter `./book/intro/`, retrieved [``]).
+
+Better yet, include a link to the specific commit! _If you know what this means, we assume you know how to do it._
+
+## Acknowledgements
+
+This book has many contributors, many of whom are also key members of the TeachBooks Team:
+
+- Tom van Woudenberg
+- Robert Lanzafame
+- Freek Pols
+- Julie Kirsch
+- Caspar Jungbacker
+
+All from Delft University of Technology.
+
+This doesn't include small contributions from various people from within and outside Delft University of Technology.
+
+A better way to see the contributions is to check the [Contributors Page](https://github.com/TeachBooks/manual/graphs/contributors) of the GitHub repository.
+
+A big "thank you" is also due to the various colleagues and teaching assistants that have worked as part of the [TeachBooks](https://teachbooks.io/) Team for developing tools and providing support to improve this book, as well as the faculty of Civil Engineering and Geosciences and the Library at Delft University of Technology for significant financial support. The faculties of of Applied Sciences and Electrical Engineering, Mathematics and Computer Science have also provided support in the form of contributions from employees and student assistants..
+
+## License
+This manual is [CC BY 4.0 licensed](https://creativecommons.org/licenses/by/4.0/) allowing you to share and adapt the material, as long as the source is named. External resources that are reused in this manual are listed below.
+
+(external_resources)=
+### External resources
+
+Parts of this book are taken from other external resources and reused in various ways. If an author is not listed on a particular page, it is by the Authors, except as follows:
+
+The following pages are included directly from an external resource and is not edited by the TeachBooks Team:
+
+- page [](./external/annotater/README.md). Original content licensed under BSD 3-Clause license.
+- Page [](./external/deploy-book-workflow/README.md). Original content licensed under BSD 3-Clause license.
+- Page [](./external/Download-Link-Replacer/README.md). Original content licensed under BSD 3-Clause license.
+- Page [](./external/JupyterBook-Patches/README.md). Original content licensed under BSD 3-Clause license.
+- Page [](./external/Nested-Books/README.md). Original content licensed under CC BY 4.0 license.
+- Page [](./external/Sphinx-Grasple-public/README.md). Original content licensed under MIT license.
+- Page [](./external/Sphinx-Image-Inverter/README.md). Original content licensed under BSD 3-Clause license.
+- Page [](./external/Sphinx-TUDelft-theme/README.md). Original content licensed under MIT license.
+- Page [](./external/teachbooks-sphinx-tippy/README.md). Original content licensed under MIT license.
+- Page [](./external/template/README.md). Original content licensed under CC BY 4.0 license.
+- Pages [](./external/Useful_python_code/extensionfildownloadreturn.ipynb), [](./external/Useful_python_code/figshrinker.ipynb) and [](./external/Useful_python_code/snippit.ipynb). Original content licensed under BSD 3-Clause license.
+
+The following pages contain content written by others, part of has been reused and/or modified by the TeachBooks Team:
+- Pages {ref}`copyright` and {ref}`copyright_considerations` include text from {cite:t}`tud_cip_24` that is used in the copyright checklist items. Original content licensed under CC BY.
+- Page {ref}`copyright_licenses`: {numref}`Figure %s` is included unmodified, along with paraphrased and quoted text (including hyperlinks) from {cite:t}`hall21`. Work is licensed under CC BY.
+- Page {ref}`copyright_licenses`: {numref}`Figure %s` is included unmodified. Work is provided by Kennisland under a CC0 license. Accessed at [](https://wiki.creativecommons.org/wiki/File:CC_License_Compatibility_Chart.png) on December 17, 2024.
+
+
+
+
diff --git a/book/external/Download-Link-Replacer b/book/external/Download-Link-Replacer
index 66952b5..f69e970 160000
--- a/book/external/Download-Link-Replacer
+++ b/book/external/Download-Link-Replacer
@@ -1 +1 @@
-Subproject commit 66952b5f23af2f0106eb24e56f186d729b5a1ca8
+Subproject commit f69e970a8da7d85e5473c7e5f58299a2ee3cf331
diff --git a/book/external/JupyterBook-Patches b/book/external/JupyterBook-Patches
index 5c129f2..f4d9638 160000
--- a/book/external/JupyterBook-Patches
+++ b/book/external/JupyterBook-Patches
@@ -1 +1 @@
-Subproject commit 5c129f2447bb4b30100c136d94b5bee9e51e2921
+Subproject commit f4d9638b197ad992d4e179295aa648b641925c6d
diff --git a/book/external/Nested-Books b/book/external/Nested-Books
index ced5cde..3cf6152 160000
--- a/book/external/Nested-Books
+++ b/book/external/Nested-Books
@@ -1 +1 @@
-Subproject commit ced5cdefa1b1b6c4fdba3fc42a94e812db4892f0
+Subproject commit 3cf61525f3985916805a59361935764d78e460df
diff --git a/book/external/Sphinx-Grasple-public b/book/external/Sphinx-Grasple-public
index c29b4a0..f4eff8d 160000
--- a/book/external/Sphinx-Grasple-public
+++ b/book/external/Sphinx-Grasple-public
@@ -1 +1 @@
-Subproject commit c29b4a03351c88fa5cdd09475f99a1b486a0e247
+Subproject commit f4eff8d1565eaf127898f2fe216cf5208684fb27
diff --git a/book/external/Sphinx-Image-Inverter b/book/external/Sphinx-Image-Inverter
index c9c9d2f..c497add 160000
--- a/book/external/Sphinx-Image-Inverter
+++ b/book/external/Sphinx-Image-Inverter
@@ -1 +1 @@
-Subproject commit c9c9d2f6953b5a57ff4763976840ec3bb281dbcf
+Subproject commit c497add7fea53bacdd24f1c7fa5ec7a850e5f9d0
diff --git a/book/external/Sphinx-TUDelft-theme b/book/external/Sphinx-TUDelft-theme
index 0f47585..35ecbdd 160000
--- a/book/external/Sphinx-TUDelft-theme
+++ b/book/external/Sphinx-TUDelft-theme
@@ -1 +1 @@
-Subproject commit 0f4758586bebb1db4da0738b66d02d883ff7b54d
+Subproject commit 35ecbddad78b567a0b2d1d4bdb513d8b95181348
diff --git a/book/external/TeachBooks b/book/external/TeachBooks
deleted file mode 160000
index eb5f90c..0000000
--- a/book/external/TeachBooks
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit eb5f90c86e6f9dd368c513b2d958f77fb941cae0
diff --git a/book/external/Useful_python_code b/book/external/Useful_python_code
index e522976..7fbdbbf 160000
--- a/book/external/Useful_python_code
+++ b/book/external/Useful_python_code
@@ -1 +1 @@
-Subproject commit e522976583a6c8cbc910531e972320a45f942737
+Subproject commit 7fbdbbf720c27112fb58bcf7826225197e39357b
diff --git a/book/external/annotater b/book/external/annotater
index 7cd38db..0da75c3 160000
--- a/book/external/annotater
+++ b/book/external/annotater
@@ -1 +1 @@
-Subproject commit 7cd38dbba9ab50eebc5dbba6c61b9cb4f46d3cf0
+Subproject commit 0da75c3592d2ddafbcec61fc7248cfb0e3c8cc1b
diff --git a/book/external/deploy-book-workflow b/book/external/deploy-book-workflow
index 71dd5f2..ed2cdc8 160000
--- a/book/external/deploy-book-workflow
+++ b/book/external/deploy-book-workflow
@@ -1 +1 @@
-Subproject commit 71dd5f2f56c8540fa45ce713adf44cab9d85c36e
+Subproject commit ed2cdc81be5036deb8da244814a946d17ece7708
diff --git a/book/external/latex-to-markdown-conversion b/book/external/latex-to-markdown-conversion
deleted file mode 160000
index f71092b..0000000
--- a/book/external/latex-to-markdown-conversion
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit f71092bfdb2e3d5d2f580bac5e31ff695806e7d3
diff --git a/book/external/teachbooks-sphinx-tippy b/book/external/teachbooks-sphinx-tippy
index 5aec30e..a80e764 160000
--- a/book/external/teachbooks-sphinx-tippy
+++ b/book/external/teachbooks-sphinx-tippy
@@ -1 +1 @@
-Subproject commit 5aec30ed8df7c6259faf7ac6cd178a0cf2887c17
+Subproject commit a80e7645bc5a377b3c75befdf29eb67934bb9ab7
diff --git a/book/external/template b/book/external/template
index 5aadbc5..1ea38ab 160000
--- a/book/external/template
+++ b/book/external/template
@@ -1 +1 @@
-Subproject commit 5aadbc527ee1251a60cbd4877d109b0558e03aad
+Subproject commit 1ea38abf8b30e9076fe315d258655ecf679e4bf2
diff --git a/book/features/_ext.zip b/book/features/_ext.zip
new file mode 100644
index 0000000..34e2f8f
Binary files /dev/null and b/book/features/_ext.zip differ
diff --git a/book/features/adding_HTML_elements.md b/book/features/adding_HTML_elements.md
index b241964..78a6cf0 100644
--- a/book/features/adding_HTML_elements.md
+++ b/book/features/adding_HTML_elements.md
@@ -32,7 +32,7 @@ Let's take a closer look at the source. Since this project uses a local file str
- Finally, the string `"element_render_box.html"` selects the HTML file we want to embed. We are now in `book/_static/element_render_box.html`.
## Viewing result at local build
-To view the final result locally, it's required to setup a [local python webserver](setup-local-server).
+To view the final result locally, it's required to setup a {ref}`local Python webserver `.
## HTML code for the 3D render element
@@ -196,4 +196,4 @@ To conclude, I provide the HTML/JavaScript code for the 3D render element above.