From 1515247112c6876e40b718ca1dcd58fd61d85905 Mon Sep 17 00:00:00 2001
From: Robert Lanzafame <R.C.Lanzafame@tudelft.nl>
Date: Tue, 17 Dec 2024 03:31:52 +0100
Subject: [PATCH 1/6] add _ext

---
 _ext/apastyle.py                              |  17 +
 _ext/bracket_citation_style.py                |  27 +
 _ext/pybtexapastyle/LICENSE                   |  21 +
 _ext/pybtexapastyle/formatting/__init__.py    |   0
 _ext/pybtexapastyle/formatting/apa.py         | 486 ++++++++++++++++++
 .../pybtex/style/formatting/__init__.py       |  69 +++
 .../pybtex/style/sorting/__init__.py          |  12 +
 .../pybtex/style/sorting/author_year_title.py |  39 ++
 _ext/pybtexapastyle/labels/__init__.py        |   0
 _ext/pybtexapastyle/labels/apa.py             |  67 +++
 _ext/pybtexapastyle/names/__init__.py         |   0
 _ext/pybtexapastyle/names/firstlast.py        |  39 ++
 _ext/pybtexapastyle/setup.py                  |  27 +
 13 files changed, 804 insertions(+)
 create mode 100644 _ext/apastyle.py
 create mode 100644 _ext/bracket_citation_style.py
 create mode 100644 _ext/pybtexapastyle/LICENSE
 create mode 100644 _ext/pybtexapastyle/formatting/__init__.py
 create mode 100644 _ext/pybtexapastyle/formatting/apa.py
 create mode 100644 _ext/pybtexapastyle/formatting/pybtex/style/formatting/__init__.py
 create mode 100644 _ext/pybtexapastyle/formatting/pybtex/style/sorting/__init__.py
 create mode 100644 _ext/pybtexapastyle/formatting/pybtex/style/sorting/author_year_title.py
 create mode 100644 _ext/pybtexapastyle/labels/__init__.py
 create mode 100644 _ext/pybtexapastyle/labels/apa.py
 create mode 100644 _ext/pybtexapastyle/names/__init__.py
 create mode 100644 _ext/pybtexapastyle/names/firstlast.py
 create mode 100644 _ext/pybtexapastyle/setup.py

diff --git a/_ext/apastyle.py b/_ext/apastyle.py
new file mode 100644
index 00000000..16828fed
--- /dev/null
+++ b/_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/_ext/bracket_citation_style.py b/_ext/bracket_citation_style.py
new file mode 100644
index 00000000..cab10f3c
--- /dev/null
+++ b/_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/_ext/pybtexapastyle/LICENSE b/_ext/pybtexapastyle/LICENSE
new file mode 100644
index 00000000..579d367a
--- /dev/null
+++ b/_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/_ext/pybtexapastyle/formatting/__init__.py b/_ext/pybtexapastyle/formatting/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/_ext/pybtexapastyle/formatting/apa.py b/_ext/pybtexapastyle/formatting/apa.py
new file mode 100644
index 00000000..dfa5a588
--- /dev/null
+++ b/_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/_ext/pybtexapastyle/formatting/pybtex/style/formatting/__init__.py b/_ext/pybtexapastyle/formatting/pybtex/style/formatting/__init__.py
new file mode 100644
index 00000000..5ac42b86
--- /dev/null
+++ b/_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/_ext/pybtexapastyle/formatting/pybtex/style/sorting/__init__.py b/_ext/pybtexapastyle/formatting/pybtex/style/sorting/__init__.py
new file mode 100644
index 00000000..3430087c
--- /dev/null
+++ b/_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/_ext/pybtexapastyle/formatting/pybtex/style/sorting/author_year_title.py b/_ext/pybtexapastyle/formatting/pybtex/style/sorting/author_year_title.py
new file mode 100644
index 00000000..c315c0c3
--- /dev/null
+++ b/_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/_ext/pybtexapastyle/labels/__init__.py b/_ext/pybtexapastyle/labels/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/_ext/pybtexapastyle/labels/apa.py b/_ext/pybtexapastyle/labels/apa.py
new file mode 100644
index 00000000..3632dc62
--- /dev/null
+++ b/_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/_ext/pybtexapastyle/names/__init__.py b/_ext/pybtexapastyle/names/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/_ext/pybtexapastyle/names/firstlast.py b/_ext/pybtexapastyle/names/firstlast.py
new file mode 100644
index 00000000..8f23263e
--- /dev/null
+++ b/_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&nbsp;Joseph de&nbsp;la Vall<span class="bibtex-protected">é</span>e&nbsp;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.&nbsp;L. X.&nbsp;J. de&nbsp;la Vall<span class="bibtex-protected">é</span>e&nbsp;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/_ext/pybtexapastyle/setup.py b/_ext/pybtexapastyle/setup.py
new file mode 100644
index 00000000..a62d1225
--- /dev/null
+++ b/_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',
+    ),
+)
-- 
GitLab


From a82c9ad59d1dab577d4d96fe5ef0d4489c9043eb Mon Sep 17 00:00:00 2001
From: Robert Lanzafame <R.C.Lanzafame@tudelft.nl>
Date: Tue, 17 Dec 2024 03:34:12 +0100
Subject: [PATCH 2/6] config

---
 book/_config.yml | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/book/_config.yml b/book/_config.yml
index 93a0a23e..1053d2d4 100644
--- a/book/_config.yml
+++ b/book/_config.yml
@@ -10,8 +10,6 @@ only_build_toc_files: true
 
 sphinx:
   config:
-    # Bibliography style
-    bibtex_reference_style: author_year
     patch_config:
       disabled-patches: []
     html_show_copyright: false
@@ -30,6 +28,11 @@ sphinx:
       # END REMOVE-FROM-PUBLISH
       launch_buttons:
         thebe: true
+    bibtex_default_style: myapastyle
+    bibtex_reference_style: author_year_round
+  local_extensions:
+    apastyle: _ext/
+    bracket_citation_style: _ext/
   extra_extensions:
     - sphinx_inline_tabs
     - sphinx_grasple
-- 
GitLab


From 5c78d815966c30b07629138900a2db75b9edd4e6 Mon Sep 17 00:00:00 2001
From: Robert Lanzafame <R.C.Lanzafame@tudelft.nl>
Date: Tue, 17 Dec 2024 04:03:50 +0100
Subject: [PATCH 3/6] put _ext in book/book not book/

---
 {_ext => book/_ext}/apastyle.py                                   | 0
 {_ext => book/_ext}/bracket_citation_style.py                     | 0
 {_ext => book/_ext}/pybtexapastyle/LICENSE                        | 0
 {_ext => book/_ext}/pybtexapastyle/formatting/__init__.py         | 0
 {_ext => book/_ext}/pybtexapastyle/formatting/apa.py              | 0
 .../pybtexapastyle/formatting/pybtex/style/formatting/__init__.py | 0
 .../pybtexapastyle/formatting/pybtex/style/sorting/__init__.py    | 0
 .../formatting/pybtex/style/sorting/author_year_title.py          | 0
 {_ext => book/_ext}/pybtexapastyle/labels/__init__.py             | 0
 {_ext => book/_ext}/pybtexapastyle/labels/apa.py                  | 0
 {_ext => book/_ext}/pybtexapastyle/names/__init__.py              | 0
 {_ext => book/_ext}/pybtexapastyle/names/firstlast.py             | 0
 {_ext => book/_ext}/pybtexapastyle/setup.py                       | 0
 13 files changed, 0 insertions(+), 0 deletions(-)
 rename {_ext => book/_ext}/apastyle.py (100%)
 rename {_ext => book/_ext}/bracket_citation_style.py (100%)
 rename {_ext => book/_ext}/pybtexapastyle/LICENSE (100%)
 rename {_ext => book/_ext}/pybtexapastyle/formatting/__init__.py (100%)
 rename {_ext => book/_ext}/pybtexapastyle/formatting/apa.py (100%)
 rename {_ext => book/_ext}/pybtexapastyle/formatting/pybtex/style/formatting/__init__.py (100%)
 rename {_ext => book/_ext}/pybtexapastyle/formatting/pybtex/style/sorting/__init__.py (100%)
 rename {_ext => book/_ext}/pybtexapastyle/formatting/pybtex/style/sorting/author_year_title.py (100%)
 rename {_ext => book/_ext}/pybtexapastyle/labels/__init__.py (100%)
 rename {_ext => book/_ext}/pybtexapastyle/labels/apa.py (100%)
 rename {_ext => book/_ext}/pybtexapastyle/names/__init__.py (100%)
 rename {_ext => book/_ext}/pybtexapastyle/names/firstlast.py (100%)
 rename {_ext => book/_ext}/pybtexapastyle/setup.py (100%)

diff --git a/_ext/apastyle.py b/book/_ext/apastyle.py
similarity index 100%
rename from _ext/apastyle.py
rename to book/_ext/apastyle.py
diff --git a/_ext/bracket_citation_style.py b/book/_ext/bracket_citation_style.py
similarity index 100%
rename from _ext/bracket_citation_style.py
rename to book/_ext/bracket_citation_style.py
diff --git a/_ext/pybtexapastyle/LICENSE b/book/_ext/pybtexapastyle/LICENSE
similarity index 100%
rename from _ext/pybtexapastyle/LICENSE
rename to book/_ext/pybtexapastyle/LICENSE
diff --git a/_ext/pybtexapastyle/formatting/__init__.py b/book/_ext/pybtexapastyle/formatting/__init__.py
similarity index 100%
rename from _ext/pybtexapastyle/formatting/__init__.py
rename to book/_ext/pybtexapastyle/formatting/__init__.py
diff --git a/_ext/pybtexapastyle/formatting/apa.py b/book/_ext/pybtexapastyle/formatting/apa.py
similarity index 100%
rename from _ext/pybtexapastyle/formatting/apa.py
rename to book/_ext/pybtexapastyle/formatting/apa.py
diff --git a/_ext/pybtexapastyle/formatting/pybtex/style/formatting/__init__.py b/book/_ext/pybtexapastyle/formatting/pybtex/style/formatting/__init__.py
similarity index 100%
rename from _ext/pybtexapastyle/formatting/pybtex/style/formatting/__init__.py
rename to book/_ext/pybtexapastyle/formatting/pybtex/style/formatting/__init__.py
diff --git a/_ext/pybtexapastyle/formatting/pybtex/style/sorting/__init__.py b/book/_ext/pybtexapastyle/formatting/pybtex/style/sorting/__init__.py
similarity index 100%
rename from _ext/pybtexapastyle/formatting/pybtex/style/sorting/__init__.py
rename to book/_ext/pybtexapastyle/formatting/pybtex/style/sorting/__init__.py
diff --git a/_ext/pybtexapastyle/formatting/pybtex/style/sorting/author_year_title.py b/book/_ext/pybtexapastyle/formatting/pybtex/style/sorting/author_year_title.py
similarity index 100%
rename from _ext/pybtexapastyle/formatting/pybtex/style/sorting/author_year_title.py
rename to book/_ext/pybtexapastyle/formatting/pybtex/style/sorting/author_year_title.py
diff --git a/_ext/pybtexapastyle/labels/__init__.py b/book/_ext/pybtexapastyle/labels/__init__.py
similarity index 100%
rename from _ext/pybtexapastyle/labels/__init__.py
rename to book/_ext/pybtexapastyle/labels/__init__.py
diff --git a/_ext/pybtexapastyle/labels/apa.py b/book/_ext/pybtexapastyle/labels/apa.py
similarity index 100%
rename from _ext/pybtexapastyle/labels/apa.py
rename to book/_ext/pybtexapastyle/labels/apa.py
diff --git a/_ext/pybtexapastyle/names/__init__.py b/book/_ext/pybtexapastyle/names/__init__.py
similarity index 100%
rename from _ext/pybtexapastyle/names/__init__.py
rename to book/_ext/pybtexapastyle/names/__init__.py
diff --git a/_ext/pybtexapastyle/names/firstlast.py b/book/_ext/pybtexapastyle/names/firstlast.py
similarity index 100%
rename from _ext/pybtexapastyle/names/firstlast.py
rename to book/_ext/pybtexapastyle/names/firstlast.py
diff --git a/_ext/pybtexapastyle/setup.py b/book/_ext/pybtexapastyle/setup.py
similarity index 100%
rename from _ext/pybtexapastyle/setup.py
rename to book/_ext/pybtexapastyle/setup.py
-- 
GitLab


From 3394770c53b5a04722832001d7e126b1f694671c Mon Sep 17 00:00:00 2001
From: Robert Lanzafame <R.C.Lanzafame@tudelft.nl>
Date: Tue, 17 Dec 2024 04:21:37 +0100
Subject: [PATCH 4/6] missing booktitle

---
 book/_bibliography/references.bib | 1 +
 1 file changed, 1 insertion(+)

diff --git a/book/_bibliography/references.bib b/book/_bibliography/references.bib
index 22a6a042..d598f923 100644
--- a/book/_bibliography/references.bib
+++ b/book/_bibliography/references.bib
@@ -301,6 +301,7 @@ author = {Jeuken, A. and Kind, J. and Slootjes, N. and Gauderis, J. and Vos, R.}
 year = {2013},
 month = {01},
 pages = {},
+booktitle = {Proceedings of ICFM5At: Rotterdam, Netherlands, Taylor & Francis Group, London, ISBN 978-0-415-62144-1},
 title = {Cost-benefit Analysis of Flood Risk Management Strategies for the Rhine-Meuse Delta},
 }
 
-- 
GitLab


From 2ce80d0e8572b3316408f30724848a0f08f81dbc Mon Sep 17 00:00:00 2001
From: Robert Lanzafame <R.C.Lanzafame@tudelft.nl>
Date: Tue, 17 Dec 2024 04:23:51 +0100
Subject: [PATCH 5/6] fix ugly CUR reference

---
 book/_bibliography/references.bib | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/book/_bibliography/references.bib b/book/_bibliography/references.bib
index d598f923..c54efd69 100644
--- a/book/_bibliography/references.bib
+++ b/book/_bibliography/references.bib
@@ -198,8 +198,8 @@ author = {Faber, M.H. and Stewart, M.G.},
 
 @misc{CUR1997,
   title={Kansen in de Civiele Techniek, Deel 1: Probabilistisch ontwerpen in theorie},
-  author={(Civieltechnisch Centrum Uitvoering research en Regelgeving), CUR},
-  howpublished={CUR rapport 190},
+  author={{CUR}},
+  howpublished={CUR rapport 190; Civieltechnisch Centrum Uitvoering research en Regelgeving},
   year={1997}
 }
 
-- 
GitLab


From e7bd47f4347b7efdf97301fe1bf658786a0ec2d5 Mon Sep 17 00:00:00 2001
From: Robert Lanzafame <R.C.Lanzafame@tudelft.nl>
Date: Thu, 19 Dec 2024 14:42:51 +0100
Subject: [PATCH 6/6] publish EVA

---
 book/_toc.yml | 2 --
 1 file changed, 2 deletions(-)

diff --git a/book/_toc.yml b/book/_toc.yml
index 901a603c..b7d4a848 100644
--- a/book/_toc.yml
+++ b/book/_toc.yml
@@ -227,7 +227,6 @@ parts:
       - file: ml/nn_interactive
       - file: ml/review
 
-    # START REMOVE-FROM-PUBLISH
     - file: eva/intro.md
       title: Extreme Value Analysis
       sections:
@@ -269,7 +268,6 @@ parts:
         - file: eva/Bernoulli.md
         - file: eva/videos.md
           title: EVA videos 
-    # END REMOVE-FROM-PUBLISH
 
     # START REMOVE-FROM-PUBLISH
     - file: pd/intro.md
-- 
GitLab