commit 257d3cd19ef3238ba23d2d0fa1ffdcc7a66a5e73 Author: Raphael Date: Fri Jul 26 10:31:14 2024 +0200 first commit diff --git a/LICRcyr2utf8.xdy b/LICRcyr2utf8.xdy new file mode 100644 index 0000000..a9ca1c8 --- /dev/null +++ b/LICRcyr2utf8.xdy @@ -0,0 +1,101 @@ +;; -*- coding: utf-8; mode: Lisp; -*- +;; style file for xindy +;; filename: LICRcyr2utf8.xdy +;; description: style file for xindy which maps back LaTeX Internal +;; Character Representation of Cyrillic to utf-8 +;; usage: for use with pdflatex produced .idx files. +;; Contributed by the Sphinx team, July 2018. +(merge-rule "\IeC {\'\CYRG }" "Ѓ" :string) +(merge-rule "\IeC {\'\CYRK }" "Ќ" :string) +(merge-rule "\IeC {\'\cyrg }" "ѓ" :string) +(merge-rule "\IeC {\'\cyrk }" "ќ" :string) +(merge-rule "\IeC {\CYRA }" "А" :string) +(merge-rule "\IeC {\CYRB }" "Б" :string) +(merge-rule "\IeC {\CYRC }" "Ц" :string) +(merge-rule "\IeC {\CYRCH }" "Ч" :string) +(merge-rule "\IeC {\CYRD }" "Д" :string) +(merge-rule "\IeC {\CYRDJE }" "Ђ" :string) +(merge-rule "\IeC {\CYRDZE }" "Ѕ" :string) +(merge-rule "\IeC {\CYRDZHE }" "Џ" :string) +(merge-rule "\IeC {\CYRE }" "Е" :string) +(merge-rule "\IeC {\CYREREV }" "Э" :string) +(merge-rule "\IeC {\CYRERY }" "Ы" :string) +(merge-rule "\IeC {\CYRF }" "Ф" :string) +(merge-rule "\IeC {\CYRG }" "Г" :string) +(merge-rule "\IeC {\CYRGUP }" "Ґ" :string) +(merge-rule "\IeC {\CYRH }" "Х" :string) +(merge-rule "\IeC {\CYRHRDSN }" "Ъ" :string) +(merge-rule "\IeC {\CYRI }" "И" :string) +(merge-rule "\IeC {\CYRIE }" "Є" :string) +(merge-rule "\IeC {\CYRII }" "І" :string) +(merge-rule "\IeC {\CYRISHRT }" "Й" :string) +(merge-rule "\IeC {\CYRJE }" "Ј" :string) +(merge-rule "\IeC {\CYRK }" "К" :string) +(merge-rule "\IeC {\CYRL }" "Л" :string) +(merge-rule "\IeC {\CYRLJE }" "Љ" :string) +(merge-rule "\IeC {\CYRM }" "М" :string) +(merge-rule "\IeC {\CYRN }" "Н" :string) +(merge-rule "\IeC {\CYRNJE }" "Њ" :string) +(merge-rule "\IeC {\CYRO }" "О" :string) +(merge-rule "\IeC {\CYRP }" "П" :string) +(merge-rule "\IeC {\CYRR }" "Р" :string) +(merge-rule "\IeC {\CYRS }" "С" :string) +(merge-rule "\IeC {\CYRSFTSN }" "Ь" :string) +(merge-rule "\IeC {\CYRSH }" "Ш" :string) +(merge-rule "\IeC {\CYRSHCH }" "Щ" :string) +(merge-rule "\IeC {\CYRT }" "Т" :string) +(merge-rule "\IeC {\CYRTSHE }" "Ћ" :string) +(merge-rule "\IeC {\CYRU }" "У" :string) +(merge-rule "\IeC {\CYRUSHRT }" "Ў" :string) +(merge-rule "\IeC {\CYRV }" "В" :string) +(merge-rule "\IeC {\CYRYA }" "Я" :string) +(merge-rule "\IeC {\CYRYI }" "Ї" :string) +(merge-rule "\IeC {\CYRYO }" "Ё" :string) +(merge-rule "\IeC {\CYRYU }" "Ю" :string) +(merge-rule "\IeC {\CYRZ }" "З" :string) +(merge-rule "\IeC {\CYRZH }" "Ж" :string) +(merge-rule "\IeC {\cyra }" "а" :string) +(merge-rule "\IeC {\cyrb }" "б" :string) +(merge-rule "\IeC {\cyrc }" "ц" :string) +(merge-rule "\IeC {\cyrch }" "ч" :string) +(merge-rule "\IeC {\cyrd }" "д" :string) +(merge-rule "\IeC {\cyrdje }" "ђ" :string) +(merge-rule "\IeC {\cyrdze }" "ѕ" :string) +(merge-rule "\IeC {\cyrdzhe }" "џ" :string) +(merge-rule "\IeC {\cyre }" "е" :string) +(merge-rule "\IeC {\cyrerev }" "э" :string) +(merge-rule "\IeC {\cyrery }" "ы" :string) +(merge-rule "\IeC {\cyrf }" "ф" :string) +(merge-rule "\IeC {\cyrg }" "г" :string) +(merge-rule "\IeC {\cyrgup }" "ґ" :string) +(merge-rule "\IeC {\cyrh }" "х" :string) +(merge-rule "\IeC {\cyrhrdsn }" "ъ" :string) +(merge-rule "\IeC {\cyri }" "и" :string) +(merge-rule "\IeC {\cyrie }" "є" :string) +(merge-rule "\IeC {\cyrii }" "і" :string) +(merge-rule "\IeC {\cyrishrt }" "й" :string) +(merge-rule "\IeC {\cyrje }" "ј" :string) +(merge-rule "\IeC {\cyrk }" "к" :string) +(merge-rule "\IeC {\cyrl }" "л" :string) +(merge-rule "\IeC {\cyrlje }" "љ" :string) +(merge-rule "\IeC {\cyrm }" "м" :string) +(merge-rule "\IeC {\cyrn }" "н" :string) +(merge-rule "\IeC {\cyrnje }" "њ" :string) +(merge-rule "\IeC {\cyro }" "о" :string) +(merge-rule "\IeC {\cyrp }" "п" :string) +(merge-rule "\IeC {\cyrr }" "р" :string) +(merge-rule "\IeC {\cyrs }" "с" :string) +(merge-rule "\IeC {\cyrsftsn }" "ь" :string) +(merge-rule "\IeC {\cyrsh }" "ш" :string) +(merge-rule "\IeC {\cyrshch }" "щ" :string) +(merge-rule "\IeC {\cyrt }" "т" :string) +(merge-rule "\IeC {\cyrtshe }" "ћ" :string) +(merge-rule "\IeC {\cyru }" "у" :string) +(merge-rule "\IeC {\cyrushrt }" "ў" :string) +(merge-rule "\IeC {\cyrv }" "в" :string) +(merge-rule "\IeC {\cyrya }" "я" :string) +(merge-rule "\IeC {\cyryi }" "ї" :string) +(merge-rule "\IeC {\cyryo }" "ё" :string) +(merge-rule "\IeC {\cyryu }" "ю" :string) +(merge-rule "\IeC {\cyrz }" "з" :string) +(merge-rule "\IeC {\cyrzh }" "ж" :string) diff --git a/LICRlatin2utf8.xdy b/LICRlatin2utf8.xdy new file mode 100644 index 0000000..1d76825 --- /dev/null +++ b/LICRlatin2utf8.xdy @@ -0,0 +1,239 @@ +;; style file for xindy +;; filename: LICRlatin2utf8.xdy +;; description: style file for xindy which maps back LaTeX Internal +;; Character Representation of letters (as arising in .idx index +;; file) to UTF-8 encoding for correct sorting by xindy. +;; usage: for use with the pdflatex engine, +;; *not* for use with xelatex or lualatex. +;; +;; This is based upon xindy's distributed file tex/inputenc/utf8.xdy. +;; The modifications include: +;; +;; - Updates for compatibility with current LaTeX macro encoding. +;; +;; - Systematic usage of the \IeC {...} mark-up, because mark-up in +;; tex/inputenc/utf8.xdy was using it on seemingly random basis, and +;; Sphinx coercing of xindy usability for both Latin and Cyrillic scripts +;; with pdflatex requires its systematic presence here. +;; +;; - Support for some extra letters: Ÿ, Ŋ, ŋ, Œ, œ, IJ, ij, ȷ and ẞ. +;; +;; Indeed Sphinx needs to support for pdflatex engine all Unicode letters +;; available in TeX T1 font encoding. The above letters are found in +;; that encoding but not in the Latin1, 2, 3 charsets which are those +;; covered by original tex/inputenc/utf8.xdy. +;; +;; - There is a problem that ȷ is not supported out-of-the box by LaTeX +;; with inputenc, one must add explicitly +;; \DeclareUnicodeCharacter{0237}{\j} +;; to preamble of LaTeX document. However this character is not supported +;; by the TeX "times" font used by default by Sphinx for pdflatex engine. +;; +;; **Update**: since LaTeX 2018/12/01, the \j as well as \SS, \k{} and +;; \.{} need no extra user declaration anymore. +;; +;; - ẞ needs \DeclareUnicodeCharacter{1E9E}{\SS} (but ß needs no extra set-up). +;; +;; - U+02DB (˛) and U+02D9 (˙) are also not supported by inputenc +;; out of the box and require +;; \DeclareUnicodeCharacter{02DB}{\k{}} +;; \DeclareUnicodeCharacter{02D9}{\.{}} +;; to be added to preamble. +;; +;; - U+0127 ħ and U+0126 Ħ are absent from TeX T1+TS1 font encodings. +;; +;; - Characters Ŋ and ŋ are not supported by TeX font "times" used by +;; default by Sphinx for pdflatex engine but they are supported by +;; some TeX fonts, in particular by the default LaTeX font for T1 +;; encoding. +;; +;; - " and ~ must be escaped as ~" and resp. ~~ in xindy merge rules. +;; +;; Contributed by the Sphinx team, July 2018. +;; +;; See sphinx.xdy for superior figures, as they are escaped by LaTeX writer. +(merge-rule "\IeC {\textonesuperior }" "¹" :string) +(merge-rule "\IeC {\texttwosuperior }" "²" :string) +(merge-rule "\IeC {\textthreesuperior }" "³" :string) +(merge-rule "\IeC {\'a}" "á" :string) +(merge-rule "\IeC {\'A}" "Á" :string) +(merge-rule "\IeC {\`a}" "à" :string) +(merge-rule "\IeC {\`A}" "À" :string) +(merge-rule "\IeC {\^a}" "â" :string) +(merge-rule "\IeC {\^A}" "Â" :string) +(merge-rule "\IeC {\~"a}" "ä" :string) +(merge-rule "\IeC {\~"A}" "Ä" :string) +(merge-rule "\IeC {\~~a}" "ã" :string) +(merge-rule "\IeC {\~~A}" "Ã" :string) +(merge-rule "\IeC {\c c}" "ç" :string) +(merge-rule "\IeC {\c C}" "Ç" :string) +(merge-rule "\IeC {\'c}" "ć" :string) +(merge-rule "\IeC {\'C}" "Ć" :string) +(merge-rule "\IeC {\^c}" "ĉ" :string) +(merge-rule "\IeC {\^C}" "Ĉ" :string) +(merge-rule "\IeC {\.c}" "ċ" :string) +(merge-rule "\IeC {\.C}" "Ċ" :string) +(merge-rule "\IeC {\c s}" "ş" :string) +(merge-rule "\IeC {\c S}" "Ş" :string) +(merge-rule "\IeC {\c t}" "ţ" :string) +(merge-rule "\IeC {\c T}" "Ţ" :string) +(merge-rule "\IeC {\-}" "­" :string); soft hyphen +(merge-rule "\IeC {\textdiv }" "÷" :string) +(merge-rule "\IeC {\'e}" "é" :string) +(merge-rule "\IeC {\'E}" "É" :string) +(merge-rule "\IeC {\`e}" "è" :string) +(merge-rule "\IeC {\`E}" "È" :string) +(merge-rule "\IeC {\^e}" "ê" :string) +(merge-rule "\IeC {\^E}" "Ê" :string) +(merge-rule "\IeC {\~"e}" "ë" :string) +(merge-rule "\IeC {\~"E}" "Ë" :string) +(merge-rule "\IeC {\^g}" "ĝ" :string) +(merge-rule "\IeC {\^G}" "Ĝ" :string) +(merge-rule "\IeC {\.g}" "ġ" :string) +(merge-rule "\IeC {\.G}" "Ġ" :string) +(merge-rule "\IeC {\^h}" "ĥ" :string) +(merge-rule "\IeC {\^H}" "Ĥ" :string) +(merge-rule "\IeC {\H o}" "ő" :string) +(merge-rule "\IeC {\H O}" "Ő" :string) +(merge-rule "\IeC {\textacutedbl }" "˝" :string) +(merge-rule "\IeC {\H u}" "ű" :string) +(merge-rule "\IeC {\H U}" "Ű" :string) +(merge-rule "\IeC {\ae }" "æ" :string) +(merge-rule "\IeC {\AE }" "Æ" :string) +(merge-rule "\IeC {\textcopyright }" "©" :string) +(merge-rule "\IeC {\c \ }" "¸" :string) +(merge-rule "\IeC {\dh }" "ð" :string) +(merge-rule "\IeC {\DH }" "Ð" :string) +(merge-rule "\IeC {\dj }" "đ" :string) +(merge-rule "\IeC {\DJ }" "Đ" :string) +(merge-rule "\IeC {\guillemotleft }" "«" :string) +(merge-rule "\IeC {\guillemotright }" "»" :string) +(merge-rule "\IeC {\'\i }" "í" :string) +(merge-rule "\IeC {\`\i }" "ì" :string) +(merge-rule "\IeC {\^\i }" "î" :string) +(merge-rule "\IeC {\~"\i }" "ï" :string) +(merge-rule "\IeC {\i }" "ı" :string) +(merge-rule "\IeC {\^\j }" "ĵ" :string) +(merge-rule "\IeC {\k {}}" "˛" :string) +(merge-rule "\IeC {\l }" "ł" :string) +(merge-rule "\IeC {\L }" "Ł" :string) +(merge-rule "\IeC {\nobreakspace }" " " :string) +(merge-rule "\IeC {\o }" "ø" :string) +(merge-rule "\IeC {\O }" "Ø" :string) +(merge-rule "\IeC {\textsterling }" "£" :string) +(merge-rule "\IeC {\textparagraph }" "¶" :string) +(merge-rule "\IeC {\ss }" "ß" :string) +(merge-rule "\IeC {\textsection }" "§" :string) +(merge-rule "\IeC {\textbrokenbar }" "¦" :string) +(merge-rule "\IeC {\textcent }" "¢" :string) +(merge-rule "\IeC {\textcurrency }" "¤" :string) +(merge-rule "\IeC {\textdegree }" "°" :string) +(merge-rule "\IeC {\textexclamdown }" "¡" :string) +(merge-rule "\IeC {\texthbar }" "ħ" :string) +(merge-rule "\IeC {\textHbar }" "Ħ" :string) +(merge-rule "\IeC {\textonehalf }" "½" :string) +(merge-rule "\IeC {\textonequarter }" "¼" :string) +(merge-rule "\IeC {\textordfeminine }" "ª" :string) +(merge-rule "\IeC {\textordmasculine }" "º" :string) +(merge-rule "\IeC {\textperiodcentered }" "·" :string) +(merge-rule "\IeC {\textquestiondown }" "¿" :string) +(merge-rule "\IeC {\textregistered }" "®" :string) +(merge-rule "\IeC {\textthreequarters }" "¾" :string) +(merge-rule "\IeC {\textyen }" "¥" :string) +(merge-rule "\IeC {\th }" "þ" :string) +(merge-rule "\IeC {\TH }" "Þ" :string) +(merge-rule "\IeC {\'I}" "Í" :string) +(merge-rule "\IeC {\`I}" "Ì" :string) +(merge-rule "\IeC {\^I}" "Î" :string) +(merge-rule "\IeC {\~"I}" "Ï" :string) +(merge-rule "\IeC {\.I}" "İ" :string) +(merge-rule "\IeC {\^J}" "Ĵ" :string) +(merge-rule "\IeC {\k a}" "ą" :string) +(merge-rule "\IeC {\k A}" "Ą" :string) +(merge-rule "\IeC {\k e}" "ę" :string) +(merge-rule "\IeC {\k E}" "Ę" :string) +(merge-rule "\IeC {\'l}" "ĺ" :string) +(merge-rule "\IeC {\'L}" "Ĺ" :string) +(merge-rule "\IeC {\textlnot }" "¬" :string) +(merge-rule "\IeC {\textmu }" "µ" :string) +(merge-rule "\IeC {\'n}" "ń" :string) +(merge-rule "\IeC {\'N}" "Ń" :string) +(merge-rule "\IeC {\~~n}" "ñ" :string) +(merge-rule "\IeC {\~~N}" "Ñ" :string) +(merge-rule "\IeC {\'o}" "ó" :string) +(merge-rule "\IeC {\'O}" "Ó" :string) +(merge-rule "\IeC {\`o}" "ò" :string) +(merge-rule "\IeC {\`O}" "Ò" :string) +(merge-rule "\IeC {\^o}" "ô" :string) +(merge-rule "\IeC {\^O}" "Ô" :string) +(merge-rule "\IeC {\~"o}" "ö" :string) +(merge-rule "\IeC {\~"O}" "Ö" :string) +(merge-rule "\IeC {\~~o}" "õ" :string) +(merge-rule "\IeC {\~~O}" "Õ" :string) +(merge-rule "\IeC {\textpm }" "±" :string) +(merge-rule "\IeC {\r a}" "å" :string) +(merge-rule "\IeC {\r A}" "Å" :string) +(merge-rule "\IeC {\'r}" "ŕ" :string) +(merge-rule "\IeC {\'R}" "Ŕ" :string) +(merge-rule "\IeC {\r u}" "ů" :string) +(merge-rule "\IeC {\r U}" "Ů" :string) +(merge-rule "\IeC {\'s}" "ś" :string) +(merge-rule "\IeC {\'S}" "Ś" :string) +(merge-rule "\IeC {\^s}" "ŝ" :string) +(merge-rule "\IeC {\^S}" "Ŝ" :string) +(merge-rule "\IeC {\textasciidieresis }" "¨" :string) +(merge-rule "\IeC {\textasciimacron }" "¯" :string) +(merge-rule "\IeC {\.{}}" "˙" :string) +(merge-rule "\IeC {\textasciiacute }" "´" :string) +(merge-rule "\IeC {\texttimes }" "×" :string) +(merge-rule "\IeC {\u a}" "ă" :string) +(merge-rule "\IeC {\u A}" "Ă" :string) +(merge-rule "\IeC {\u g}" "ğ" :string) +(merge-rule "\IeC {\u G}" "Ğ" :string) +(merge-rule "\IeC {\textasciibreve }" "˘" :string) +(merge-rule "\IeC {\'u}" "ú" :string) +(merge-rule "\IeC {\'U}" "Ú" :string) +(merge-rule "\IeC {\`u}" "ù" :string) +(merge-rule "\IeC {\`U}" "Ù" :string) +(merge-rule "\IeC {\^u}" "û" :string) +(merge-rule "\IeC {\^U}" "Û" :string) +(merge-rule "\IeC {\~"u}" "ü" :string) +(merge-rule "\IeC {\~"U}" "Ü" :string) +(merge-rule "\IeC {\u u}" "ŭ" :string) +(merge-rule "\IeC {\u U}" "Ŭ" :string) +(merge-rule "\IeC {\v c}" "č" :string) +(merge-rule "\IeC {\v C}" "Č" :string) +(merge-rule "\IeC {\v d}" "ď" :string) +(merge-rule "\IeC {\v D}" "Ď" :string) +(merge-rule "\IeC {\v e}" "ě" :string) +(merge-rule "\IeC {\v E}" "Ě" :string) +(merge-rule "\IeC {\v l}" "ľ" :string) +(merge-rule "\IeC {\v L}" "Ľ" :string) +(merge-rule "\IeC {\v n}" "ň" :string) +(merge-rule "\IeC {\v N}" "Ň" :string) +(merge-rule "\IeC {\v r}" "ř" :string) +(merge-rule "\IeC {\v R}" "Ř" :string) +(merge-rule "\IeC {\v s}" "š" :string) +(merge-rule "\IeC {\v S}" "Š" :string) +(merge-rule "\IeC {\textasciicaron }" "ˇ" :string) +(merge-rule "\IeC {\v t}" "ť" :string) +(merge-rule "\IeC {\v T}" "Ť" :string) +(merge-rule "\IeC {\v z}" "ž" :string) +(merge-rule "\IeC {\v Z}" "Ž" :string) +(merge-rule "\IeC {\'y}" "ý" :string) +(merge-rule "\IeC {\'Y}" "Ý" :string) +(merge-rule "\IeC {\~"y}" "ÿ" :string) +(merge-rule "\IeC {\'z}" "ź" :string) +(merge-rule "\IeC {\'Z}" "Ź" :string) +(merge-rule "\IeC {\.z}" "ż" :string) +(merge-rule "\IeC {\.Z}" "Ż" :string) +;; letters not in Latin1, 2, 3 but available in TeX T1 font encoding +(merge-rule "\IeC {\~"Y}" "Ÿ" :string) +(merge-rule "\IeC {\NG }" "Ŋ" :string) +(merge-rule "\IeC {\ng }" "ŋ" :string) +(merge-rule "\IeC {\OE }" "Œ" :string) +(merge-rule "\IeC {\oe }" "œ" :string) +(merge-rule "\IeC {\IJ }" "IJ" :string) +(merge-rule "\IeC {\ij }" "ij" :string) +(merge-rule "\IeC {\j }" "ȷ" :string) +(merge-rule "\IeC {\SS }" "ẞ" :string) diff --git a/LatinRules.xdy b/LatinRules.xdy new file mode 100644 index 0000000..99f14a2 --- /dev/null +++ b/LatinRules.xdy @@ -0,0 +1,607 @@ +;; style file for xindy +;; filename: LatinRules.xdy +;; +;; It is based upon xindy's files lang/general/utf8.xdy and +;; lang/general/utf8-lang.xdy which implement +;; "a general sorting order for Western European languages" +;; +;; The aim for Sphinx is to be able to index in a Cyrillic document +;; also terms using the Latin alphabets, inclusive of letters +;; with diacritics. To this effect the xindy rules from lang/general +;; got manually re-coded to avoid collisions with the encoding +;; done by xindy for sorting words in Cyrillic languages, which was +;; observed not to use bytes with octal encoding 0o266 or higher. +;; +;; So here we use only 0o266 or higher bytes. +;; (Ŋ, ŋ, IJ, and ij are absent from +;; lang/general/utf8.xdy and not included here) +;; Contributed by the Sphinx team, 2018. + +(define-letter-group "A" :prefixes ("")) +(define-letter-group "B" :after "A" :prefixes ("")) +(define-letter-group "C" :after "B" :prefixes ("")) +(define-letter-group "D" :after "C" :prefixes ("")) +(define-letter-group "E" :after "D" :prefixes ("")) +(define-letter-group "F" :after "E" :prefixes ("")) +(define-letter-group "G" :after "F" :prefixes ("")) +(define-letter-group "H" :after "G" :prefixes ("")) +(define-letter-group "I" :after "H" :prefixes ("")) +(define-letter-group "J" :after "I" :prefixes ("")) +(define-letter-group "K" :after "J" :prefixes ("")) +(define-letter-group "L" :after "K" :prefixes ("")) +(define-letter-group "M" :after "L" :prefixes ("")) +(define-letter-group "N" :after "M" :prefixes ("")) +(define-letter-group "O" :after "N" :prefixes ("")) +(define-letter-group "P" :after "O" :prefixes ("")) +(define-letter-group "Q" :after "P" :prefixes ("")) +(define-letter-group "R" :after "Q" :prefixes ("")) +(define-letter-group "S" :after "R" :prefixes ("")) +(define-letter-group "T" :after "S" :prefixes ("")) +(define-letter-group "U" :after "T" :prefixes ("")) +(define-letter-group "V" :after "U" :prefixes ("")) +(define-letter-group "W" :after "V" :prefixes ("")) +(define-letter-group "X" :after "W" :prefixes ("")) +(define-letter-group "Y" :after "X" :prefixes ("")) +(define-letter-group "Z" :after "Y" :prefixes ("")) + +(define-rule-set "sphinx-xy-alphabetize" + + :rules (("À" "" :string) + ("Ă" "" :string) + ("â" "" :string) + ("Ä" "" :string) + ("à" "" :string) + ("Å" "" :string) + ("Ã" "" :string) + ("Á" "" :string) + ("á" "" :string) + ("ã" "" :string) + ("Â" "" :string) + ("ă" "" :string) + ("å" "" :string) + ("ą" "" :string) + ("ä" "" :string) + ("Ą" "" :string) + ("æ" "" :string) + ("Æ" "" :string) + ("ć" "" :string) + ("ĉ" "" :string) + ("ç" "" :string) + ("Č" "" :string) + ("č" "" :string) + ("Ĉ" "" :string) + ("Ç" "" :string) + ("Ć" "" :string) + ("ď" "" :string) + ("Đ" "" :string) + ("Ď" "" :string) + ("đ" "" :string) + ("ê" "" :string) + ("Ę" "" :string) + ("Ě" "" :string) + ("ë" "" :string) + ("ě" "" :string) + ("é" "" :string) + ("È" "" :string) + ("Ë" "" :string) + ("É" "" :string) + ("è" "" :string) + ("Ê" "" :string) + ("ę" "" :string) + ("ĝ" "" :string) + ("ğ" "" :string) + ("Ğ" "" :string) + ("Ĝ" "" :string) + ("ĥ" "" :string) + ("Ĥ" "" :string) + ("Ï" "" :string) + ("Í" "" :string) + ("ï" "" :string) + ("Î" "" :string) + ("î" "" :string) + ("ı" "" :string) + ("İ" "" :string) + ("í" "" :string) + ("Ì" "" :string) + ("ì" "" :string) + ("Ĵ" "" :string) + ("ĵ" "" :string) + ("ł" "" :string) + ("Ł" "" :string) + ("ľ" "" :string) + ("Ľ" "" :string) + ("ń" "" :string) + ("Ń" "" :string) + ("ñ" "" :string) + ("ň" "" :string) + ("Ñ" "" :string) + ("Ň" "" :string) + ("Õ" "" :string) + ("Ő" "" :string) + ("ó" "" :string) + ("ö" "" :string) + ("ô" "" :string) + ("ő" "" :string) + ("Ø" "" :string) + ("Ö" "" :string) + ("õ" "" :string) + ("Ô" "" :string) + ("ø" "" :string) + ("Ó" "" :string) + ("Ò" "" :string) + ("ò" "" :string) + ("œ" "ĺ" :string) + ("Œ" "ĺ" :string) + ("Ř" "" :string) + ("ř" "" :string) + ("Ŕ" "" :string) + ("ŕ" "" :string) + ("ŝ" "" :string) + ("Ś" "" :string) + ("ș" "" :string) + ("ş" "" :string) + ("Ŝ" "" :string) + ("ś" "" :string) + ("Ș" "" :string) + ("š" "" :string) + ("Ş" "" :string) + ("Š" "" :string) + ("ß" "" :string) + ("Ț" "" :string) + ("Ť" "" :string) + ("ț" "" :string) + ("ť" "" :string) + ("û" "" :string) + ("ŭ" "" :string) + ("ů" "" :string) + ("ű" "" :string) + ("ù" "" :string) + ("Ŭ" "" :string) + ("Ù" "" :string) + ("Ű" "" :string) + ("Ü" "" :string) + ("Ů" "" :string) + ("ú" "" :string) + ("Ú" "" :string) + ("Û" "" :string) + ("ü" "" :string) + ("ÿ" "" :string) + ("Ý" "" :string) + ("Ÿ" "" :string) + ("ý" "" :string) + ("Ż" "" :string) + ("Ž" "" :string) + ("Ź" "" :string) + ("ž" "" :string) + ("ż" "" :string) + ("ź" "" :string) + ("a" "" :string) + ("A" "" :string) + ("b" "" :string) + ("B" "" :string) + ("c" "" :string) + ("C" "" :string) + ("d" "" :string) + ("D" "" :string) + ("e" "" :string) + ("E" "" :string) + ("F" "" :string) + ("f" "" :string) + ("G" "" :string) + ("g" "" :string) + ("H" "" :string) + ("h" "" :string) + ("i" "" :string) + ("I" "" :string) + ("J" "" :string) + ("j" "" :string) + ("K" "" :string) + ("k" "" :string) + ("L" "" :string) + ("l" "" :string) + ("M" "" :string) + ("m" "" :string) + ("n" "" :string) + ("N" "" :string) + ("O" "" :string) + ("o" "" :string) + ("p" "" :string) + ("P" "" :string) + ("Q" "" :string) + ("q" "" :string) + ("r" "" :string) + ("R" "" :string) + ("S" "" :string) + ("s" "" :string) + ("t" "" :string) + ("T" "" :string) + ("u" "" :string) + ("U" "" :string) + ("v" "" :string) + ("V" "" :string) + ("W" "" :string) + ("w" "" :string) + ("x" "" :string) + ("X" "" :string) + ("Y" "" :string) + ("y" "" :string) + ("z" "" :string) + ("Z" "" :string) + )) + +(define-rule-set "sphinx-xy-resolve-diacritics" + + :rules (("Ĥ" "" :string) + ("ó" "" :string) + ("ľ" "" :string) + ("Ř" "" :string) + ("ĝ" "" :string) + ("ď" "" :string) + ("Ě" "" :string) + ("ĥ" "" :string) + ("Č" "" :string) + ("Ĵ" "" :string) + ("ě" "" :string) + ("ž" "" :string) + ("Ď" "" :string) + ("ř" "" :string) + ("Ž" "" :string) + ("ı" "" :string) + ("Ť" "" :string) + ("á" "" :string) + ("č" "" :string) + ("Á" "" :string) + ("ň" "" :string) + ("Š" "" :string) + ("Ň" "" :string) + ("ĵ" "" :string) + ("ť" "" :string) + ("Ó" "" :string) + ("ý" "" :string) + ("Ĝ" "" :string) + ("Ú" "" :string) + ("Ľ" "" :string) + ("š" "" :string) + ("Ý" "" :string) + ("ú" "" :string) + ("Ś" "" :string) + ("ć" "" :string) + ("Ł" "" :string) + ("ł" "" :string) + ("ń" "" :string) + ("À" "" :string) + ("Ź" "" :string) + ("à" "" :string) + ("Ń" "" :string) + ("Đ" "" :string) + ("ÿ" "" :string) + ("ś" "" :string) + ("Ğ" "" :string) + ("ğ" "" :string) + ("Ù" "" :string) + ("İ" "" :string) + ("đ" "" :string) + ("ù" "" :string) + ("Ț" "" :string) + ("é" "" :string) + ("ŕ" "" :string) + ("Ć" "" :string) + ("ț" "" :string) + ("ò" "" :string) + ("ź" "" :string) + ("Ò" "" :string) + ("Ÿ" "" :string) + ("Ŕ" "" :string) + ("É" "" :string) + ("ĉ" "" :string) + ("ô" "" :string) + ("Í" "" :string) + ("ŝ" "" :string) + ("Ż" "" :string) + ("Ă" "" :string) + ("Ŝ" "" :string) + ("ñ" "" :string) + ("ŭ" "" :string) + ("í" "" :string) + ("È" "" :string) + ("Ô" "" :string) + ("Ŭ" "" :string) + ("ż" "" :string) + ("Ñ" "" :string) + ("è" "" :string) + ("Ĉ" "" :string) + ("ă" "" :string) + ("â" "" :string) + ("û" "" :string) + ("ê" "" :string) + ("Õ" "" :string) + ("õ" "" :string) + ("ș" "" :string) + ("ç" "" :string) + ("Â" "" :string) + ("Ê" "" :string) + ("Û" "" :string) + ("Ç" "" :string) + ("ì" "" :string) + ("Ì" "" :string) + ("Ș" "" :string) + ("ö" "" :string) + ("Ö" "" :string) + ("ş" "" :string) + ("ů" "" :string) + ("ë" "" :string) + ("ã" "" :string) + ("î" "" :string) + ("Î" "" :string) + ("Ã" "" :string) + ("Ş" "" :string) + ("Ů" "" :string) + ("Ë" "" :string) + ("ï" "" :string) + ("Ő" "" :string) + ("Ï" "" :string) + ("Ę" "" :string) + ("ő" "" :string) + ("Ü" "" :string) + ("Å" "" :string) + ("ü" "" :string) + ("ę" "" :string) + ("å" "" :string) + ("Ä" "" :string) + ("ű" "" :string) + ("Ø" "" :string) + ("ø" "" :string) + ("Ű" "" :string) + ("ä" "" :string) + ("Ą" "" :string) + ("ą" "" :string) + ("œ" "" :string) + ("ß" "" :string) + ("Æ" "" :string) + ("Œ" "" :string) + ("æ" "" :string) + ("e" "" :string) + ("t" "" :string) + ("L" "" :string) + ("Y" "" :string) + ("J" "" :string) + ("a" "" :string) + ("p" "" :string) + ("u" "" :string) + ("j" "" :string) + ("b" "" :string) + ("G" "" :string) + ("U" "" :string) + ("F" "" :string) + ("H" "" :string) + ("i" "" :string) + ("z" "" :string) + ("c" "" :string) + ("l" "" :string) + ("A" "" :string) + ("Q" "" :string) + ("w" "" :string) + ("D" "" :string) + ("R" "" :string) + ("d" "" :string) + ("s" "" :string) + ("r" "" :string) + ("k" "" :string) + ("v" "" :string) + ("m" "" :string) + ("P" "" :string) + ("y" "" :string) + ("K" "" :string) + ("q" "" :string) + ("S" "" :string) + ("I" "" :string) + ("C" "" :string) + ("M" "" :string) + ("Z" "" :string) + ("T" "" :string) + ("W" "" :string) + ("B" "" :string) + ("h" "" :string) + ("x" "" :string) + ("X" "" :string) + ("f" "" :string) + ("E" "" :string) + ("V" "" :string) + ("N" "" :string) + ("O" "" :string) + ("o" "" :string) + ("g" "" :string) + ("n" "" :string) + )) + +(define-rule-set "sphinx-xy-resolve-case" + + :rules (("Ú" "8" :string) + ("Ÿ" "8" :string) + ("Ç" "8" :string) + ("Ĉ" "8" :string) + ("Ŕ" "8" :string) + ("Ľ" "8" :string) + ("Ů" "8" :string) + ("Ý" "8" :string) + ("É" "8" :string) + ("Ë" "8" :string) + ("Ș" "8" :string) + ("Ì" "8" :string) + ("Ê" "8" :string) + ("Ň" "8" :string) + ("Ą" "8" :string) + ("Š" "8" :string) + ("Û" "8" :string) + ("Ş" "8" :string) + ("Ć" "8" :string) + ("Ò" "8" :string) + ("Ĝ" "8" :string) + ("Ñ" "8" :string) + ("Ó" "8" :string) + ("Î" "8" :string) + ("Á" "8" :string) + ("Ã" "8" :string) + ("Ț" "8" :string) + ("Å" "8" :string) + ("Ğ" "8" :string) + ("Ü" "8" :string) + ("È" "8" :string) + ("Ô" "8" :string) + ("İ" "8" :string) + ("Ű" "8" :string) + ("Ù" "8" :string) + ("Ŭ" "8" :string) + ("Â" "8" :string) + ("Ť" "8" :string) + ("Ń" "8" :string) + ("Ď" "8" :string) + ("Ź" "8" :string) + ("Ž" "8" :string) + ("Đ" "8" :string) + ("Ŝ" "8" :string) + ("Č" "8" :string) + ("Ĵ" "8" :string) + ("Ö" "8" :string) + ("Ø" "8" :string) + ("Ż" "8" :string) + ("Ł" "8" :string) + ("Ă" "8" :string) + ("Ě" "8" :string) + ("Ő" "8" :string) + ("Õ" "8" :string) + ("Ę" "8" :string) + ("Ï" "8" :string) + ("À" "8" :string) + ("Ĥ" "8" :string) + ("Ä" "8" :string) + ("Ś" "8" :string) + ("Ř" "8" :string) + ("Í" "8" :string) + ("Œ" "89" :string) + ("Æ" "89" :string) + ("ì" "9" :string) + ("è" "9" :string) + ("ą" "9" :string) + ("š" "9" :string) + ("ú" "9" :string) + ("å" "9" :string) + ("ă" "9" :string) + ("ę" "9" :string) + ("ü" "9" :string) + ("ź" "9" :string) + ("ò" "9" :string) + ("ť" "9" :string) + ("ț" "9" :string) + ("ĵ" "9" :string) + ("ŕ" "9" :string) + ("ż" "9" :string) + ("ä" "9" :string) + ("ý" "9" :string) + ("ù" "9" :string) + ("á" "9" :string) + ("é" "9" :string) + ("č" "9" :string) + ("ň" "9" :string) + ("ś" "9" :string) + ("ø" "9" :string) + ("í" "9" :string) + ("đ" "9" :string) + ("ı" "9" :string) + ("ğ" "9" :string) + ("î" "9" :string) + ("ã" "9" :string) + ("à" "9" :string) + ("ř" "9" :string) + ("ő" "9" :string) + ("ů" "9" :string) + ("ș" "9" :string) + ("ÿ" "9" :string) + ("ë" "9" :string) + ("ŭ" "9" :string) + ("ç" "9" :string) + ("ű" "9" :string) + ("ñ" "9" :string) + ("õ" "9" :string) + ("ě" "9" :string) + ("ş" "9" :string) + ("ž" "9" :string) + ("ĝ" "9" :string) + ("ŝ" "9" :string) + ("ń" "9" :string) + ("û" "9" :string) + ("ł" "9" :string) + ("ď" "9" :string) + ("ĥ" "9" :string) + ("ê" "9" :string) + ("ô" "9" :string) + ("ĉ" "9" :string) + ("â" "9" :string) + ("ć" "9" :string) + ("ï" "9" :string) + ("ö" "9" :string) + ("ľ" "9" :string) + ("ó" "9" :string) + ("æ" "99" :string) + ("ß" "99" :string) + ("œ" "99" :string) + ("N" "8" :string) + ("V" "8" :string) + ("O" "8" :string) + ("X" "8" :string) + ("E" "8" :string) + ("P" "8" :string) + ("K" "8" :string) + ("T" "8" :string) + ("Z" "8" :string) + ("M" "8" :string) + ("C" "8" :string) + ("I" "8" :string) + ("S" "8" :string) + ("B" "8" :string) + ("W" "8" :string) + ("D" "8" :string) + ("R" "8" :string) + ("H" "8" :string) + ("F" "8" :string) + ("Q" "8" :string) + ("A" "8" :string) + ("G" "8" :string) + ("U" "8" :string) + ("J" "8" :string) + ("Y" "8" :string) + ("L" "8" :string) + ("o" "9" :string) + ("n" "9" :string) + ("g" "9" :string) + ("x" "9" :string) + ("f" "9" :string) + ("y" "9" :string) + ("q" "9" :string) + ("h" "9" :string) + ("w" "9" :string) + ("s" "9" :string) + ("d" "9" :string) + ("v" "9" :string) + ("k" "9" :string) + ("r" "9" :string) + ("m" "9" :string) + ("z" "9" :string) + ("c" "9" :string) + ("i" "9" :string) + ("l" "9" :string) + ("b" "9" :string) + ("j" "9" :string) + ("a" "9" :string) + ("p" "9" :string) + ("u" "9" :string) + ("t" "9" :string) + ("e" "9" :string) + )) + +(use-rule-set :run 0 + :rule-set ("sphinx-xy-alphabetize")) +(use-rule-set :run 1 + :rule-set ("sphinx-xy-resolve-diacritics")) +(use-rule-set :run 2 + :rule-set ("sphinx-xy-resolve-case")) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e4653f2 --- /dev/null +++ b/Makefile @@ -0,0 +1,64 @@ +# Makefile for Sphinx LaTeX output + +ALLDOCS = $(basename $(wildcard *.tex)) +ALLPDF = $(addsuffix .pdf,$(ALLDOCS)) +ALLDVI = $(addsuffix .dvi,$(ALLDOCS)) +ALLXDV = +ALLPS = $(addsuffix .ps,$(ALLDOCS)) + +# Prefix for archive names +ARCHIVEPREFIX = +# Additional LaTeX options (passed via variables in latexmkrc/latexmkjarc file) +export LATEXOPTS ?= +# Additional latexmk options +LATEXMKOPTS ?= +# format: pdf or dvi (used only by archive targets) +FMT = pdf + +LATEX = latexmk -dvi +PDFLATEX = latexmk -pdf -dvi- -ps- + + +%.dvi: %.tex FORCE_MAKE + $(LATEX) $(LATEXMKOPTS) '$<' + +%.ps: %.dvi + dvips '$<' + +%.pdf: %.tex FORCE_MAKE + $(PDFLATEX) $(LATEXMKOPTS) '$<' + +all: $(ALLPDF) + +all-dvi: $(ALLDVI) + +all-ps: $(ALLPS) + +all-pdf: $(ALLPDF) + +zip: all-$(FMT) + mkdir $(ARCHIVEPREFIX)docs-$(FMT) + cp $(ALLPDF) $(ARCHIVEPREFIX)docs-$(FMT) + zip -q -r -9 $(ARCHIVEPREFIX)docs-$(FMT).zip $(ARCHIVEPREFIX)docs-$(FMT) + rm -r $(ARCHIVEPREFIX)docs-$(FMT) + +tar: all-$(FMT) + mkdir $(ARCHIVEPREFIX)docs-$(FMT) + cp $(ALLPDF) $(ARCHIVEPREFIX)docs-$(FMT) + tar cf $(ARCHIVEPREFIX)docs-$(FMT).tar $(ARCHIVEPREFIX)docs-$(FMT) + rm -r $(ARCHIVEPREFIX)docs-$(FMT) + +gz: tar + gzip -9 < $(ARCHIVEPREFIX)docs-$(FMT).tar > $(ARCHIVEPREFIX)docs-$(FMT).tar.gz + +bz2: tar + bzip2 -9 -k $(ARCHIVEPREFIX)docs-$(FMT).tar + +xz: tar + xz -9 -k $(ARCHIVEPREFIX)docs-$(FMT).tar + +clean: + rm -f *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla *.ps *.tar *.tar.gz *.tar.bz2 *.tar.xz $(ALLPDF) $(ALLDVI) $(ALLXDV) *.fls *.fdb_latexmk + +.PHONY: all all-pdf all-dvi all-ps clean zip tar gz bz2 xz +.PHONY: FORCE_MAKE \ No newline at end of file diff --git a/Slide01.png b/Slide01.png new file mode 100644 index 0000000..a87efed Binary files /dev/null and b/Slide01.png differ diff --git a/Slide02.png b/Slide02.png new file mode 100644 index 0000000..1223327 Binary files /dev/null and b/Slide02.png differ diff --git a/Slide03.png b/Slide03.png new file mode 100644 index 0000000..b933797 Binary files /dev/null and b/Slide03.png differ diff --git a/Slide04.png b/Slide04.png new file mode 100644 index 0000000..21bea3c Binary files /dev/null and b/Slide04.png differ diff --git a/Slide05.png b/Slide05.png new file mode 100644 index 0000000..34ab5ab Binary files /dev/null and b/Slide05.png differ diff --git a/Slide06.png b/Slide06.png new file mode 100644 index 0000000..dcb3b7d Binary files /dev/null and b/Slide06.png differ diff --git a/Slide07.png b/Slide07.png new file mode 100644 index 0000000..920f571 Binary files /dev/null and b/Slide07.png differ diff --git a/Slide08.png b/Slide08.png new file mode 100644 index 0000000..8f3ca60 Binary files /dev/null and b/Slide08.png differ diff --git a/Slide09.png b/Slide09.png new file mode 100644 index 0000000..f902ec7 Binary files /dev/null and b/Slide09.png differ diff --git a/Slide10.png b/Slide10.png new file mode 100644 index 0000000..fcf1c0c Binary files /dev/null and b/Slide10.png differ diff --git a/Slide11.png b/Slide11.png new file mode 100644 index 0000000..47eabeb Binary files /dev/null and b/Slide11.png differ diff --git a/Slide12.png b/Slide12.png new file mode 100644 index 0000000..236291a Binary files /dev/null and b/Slide12.png differ diff --git a/Slide13.png b/Slide13.png new file mode 100644 index 0000000..c8fe675 Binary files /dev/null and b/Slide13.png differ diff --git a/Slide14.png b/Slide14.png new file mode 100644 index 0000000..58f2619 Binary files /dev/null and b/Slide14.png differ diff --git a/Slide15.png b/Slide15.png new file mode 100644 index 0000000..354df5b Binary files /dev/null and b/Slide15.png differ diff --git a/Slide16.png b/Slide16.png new file mode 100644 index 0000000..5c1d0c9 Binary files /dev/null and b/Slide16.png differ diff --git a/Slide18.png b/Slide18.png new file mode 100644 index 0000000..af942ec Binary files /dev/null and b/Slide18.png differ diff --git a/Slide19.png b/Slide19.png new file mode 100644 index 0000000..ba98389 Binary files /dev/null and b/Slide19.png differ diff --git a/Slide20.png b/Slide20.png new file mode 100644 index 0000000..a1d4e3f Binary files /dev/null and b/Slide20.png differ diff --git a/Slide21.png b/Slide21.png new file mode 100644 index 0000000..353e424 Binary files /dev/null and b/Slide21.png differ diff --git a/Slide22.png b/Slide22.png new file mode 100644 index 0000000..e3258e3 Binary files /dev/null and b/Slide22.png differ diff --git a/Slide23.png b/Slide23.png new file mode 100644 index 0000000..3458d33 Binary files /dev/null and b/Slide23.png differ diff --git a/Slide24.png b/Slide24.png new file mode 100644 index 0000000..b00d41d Binary files /dev/null and b/Slide24.png differ diff --git a/Slide25.png b/Slide25.png new file mode 100644 index 0000000..1e3e0dc Binary files /dev/null and b/Slide25.png differ diff --git a/Slide26.png b/Slide26.png new file mode 100644 index 0000000..889e14d Binary files /dev/null and b/Slide26.png differ diff --git a/Slide27.png b/Slide27.png new file mode 100644 index 0000000..d310ff0 Binary files /dev/null and b/Slide27.png differ diff --git a/Slide28.png b/Slide28.png new file mode 100644 index 0000000..fbe317a Binary files /dev/null and b/Slide28.png differ diff --git a/Slide29.png b/Slide29.png new file mode 100644 index 0000000..7b8d22b Binary files /dev/null and b/Slide29.png differ diff --git a/Slide30.png b/Slide30.png new file mode 100644 index 0000000..a1e556e Binary files /dev/null and b/Slide30.png differ diff --git a/Slide31.png b/Slide31.png new file mode 100644 index 0000000..b3ec3e3 Binary files /dev/null and b/Slide31.png differ diff --git a/Slide32.png b/Slide32.png new file mode 100644 index 0000000..4c8c22d Binary files /dev/null and b/Slide32.png differ diff --git a/Slide33.png b/Slide33.png new file mode 100644 index 0000000..f236409 Binary files /dev/null and b/Slide33.png differ diff --git a/Slide34.png b/Slide34.png new file mode 100644 index 0000000..1f93956 Binary files /dev/null and b/Slide34.png differ diff --git a/Slide35.png b/Slide35.png new file mode 100644 index 0000000..9c70dca Binary files /dev/null and b/Slide35.png differ diff --git a/Slide36.png b/Slide36.png new file mode 100644 index 0000000..613e4d3 Binary files /dev/null and b/Slide36.png differ diff --git a/Slide37.png b/Slide37.png new file mode 100644 index 0000000..783179b Binary files /dev/null and b/Slide37.png differ diff --git a/Slide38.png b/Slide38.png new file mode 100644 index 0000000..454abc6 Binary files /dev/null and b/Slide38.png differ diff --git a/Slide39.png b/Slide39.png new file mode 100644 index 0000000..a6257ca Binary files /dev/null and b/Slide39.png differ diff --git a/Slide40.png b/Slide40.png new file mode 100644 index 0000000..5e97b06 Binary files /dev/null and b/Slide40.png differ diff --git a/book.tex b/book.tex new file mode 100644 index 0000000..b997b93 --- /dev/null +++ b/book.tex @@ -0,0 +1,3452 @@ +%% Generated by Sphinx. +\def\sphinxdocclass{report} +\documentclass[a4paper,11pt,english]{sphinxmanual} +\ifdefined\pdfpxdimen + \let\sphinxpxdimen\pdfpxdimen\else\newdimen\sphinxpxdimen +\fi \sphinxpxdimen=.75bp\relax +\ifdefined\pdfimageresolution + \pdfimageresolution= \numexpr \dimexpr1in\relax/\sphinxpxdimen\relax +\fi +%% let collapsible pdf bookmarks panel have high depth per default +\PassOptionsToPackage{bookmarksdepth=5}{hyperref} + +\PassOptionsToPackage{warn}{textcomp} +\usepackage[utf8]{inputenc} +\ifdefined\DeclareUnicodeCharacter +% support both utf8 and utf8x syntaxes + \ifdefined\DeclareUnicodeCharacterAsOptional + \def\sphinxDUC#1{\DeclareUnicodeCharacter{"#1}} + \else + \let\sphinxDUC\DeclareUnicodeCharacter + \fi + \sphinxDUC{00A0}{\nobreakspace} + \sphinxDUC{2500}{\sphinxunichar{2500}} + \sphinxDUC{2502}{\sphinxunichar{2502}} + \sphinxDUC{2514}{\sphinxunichar{2514}} + \sphinxDUC{251C}{\sphinxunichar{251C}} + \sphinxDUC{2572}{\textbackslash} +\fi +\usepackage{cmap} +\usepackage[LGR,T1]{fontenc} +\usepackage{amsmath,amssymb,amstext} +\usepackage{babel} +\usepackage{substitutefont} + + +\usepackage{tgtermes} +\usepackage{tgheros} +\renewcommand{\ttdefault}{txtt} + + +\expandafter\ifx\csname T@LGR\endcsname\relax +\else +% LGR was declared as font encoding + \substitutefont{LGR}{\rmdefault}{cmr} + \substitutefont{LGR}{\sfdefault}{cmss} + \substitutefont{LGR}{\ttdefault}{cmtt} +\fi +\expandafter\ifx\csname T@X2\endcsname\relax + \expandafter\ifx\csname T@T2A\endcsname\relax + \else + % T2A was declared as font encoding + \substitutefont{T2A}{\rmdefault}{cmr} + \substitutefont{T2A}{\sfdefault}{cmss} + \substitutefont{T2A}{\ttdefault}{cmtt} + \fi +\else +% X2 was declared as font encoding + \substitutefont{X2}{\rmdefault}{cmr} + \substitutefont{X2}{\sfdefault}{cmss} + \substitutefont{X2}{\ttdefault}{cmtt} +\fi + +\usepackage{textalpha} +\usepackage[Bjarne]{fncychap} +\usepackage[,numfigreset=1,mathnumfig]{sphinx} + +\fvset{fontsize=auto} +\usepackage{geometry} + + +% Include hyperref last. +\usepackage{hyperref} +% Fix anchor placement for figures with captions. +\usepackage{hypcap}% it must be loaded after hyperref. +% Set up styles of URL: it should be placed after hyperref. +\urlstyle{same} + +\addto\captionsenglish{\renewcommand{\contentsname}{Table of Contents}} + +\usepackage{sphinxmessages} +\setcounter{tocdepth}{1} + + + +\title{5G Mobile Networks: A Systems Approach} +\date{Dec 09, 2022} +\release{Version 1.1\sphinxhyphen{}dev} +\author{Peterson and Sunay} +\newcommand{\sphinxlogo}{\vbox{}} +\renewcommand{\releasename}{Release} +\makeindex +\begin{document} + +\pagestyle{empty} +\sphinxmaketitle +\pagestyle{plain} +\sphinxtableofcontents +\pagestyle{normal} +\phantomsection\label{\detokenize{index::doc}} + + + +\chapter*{Preface} +\label{\detokenize{preface:preface}}\label{\detokenize{preface::doc}} +\sphinxAtStartPar +The transition to 5G is happening, and unless you’ve been actively +trying to ignore it, you’ve undoubtedly heard the hype. But if you are +like 99\% of the CS\sphinxhyphen{}trained, systems\sphinxhyphen{}oriented, cloud\sphinxhyphen{}savvy people in +the world, the cellular network is largely a mystery. You know it’s an +important technology used in the last mile to connect people to the +Internet, but you’ve otherwise abstracted it out of your +scope\sphinxhyphen{}of\sphinxhyphen{}concerns. Perhaps you’ve heard a conspiracy theory or two +about how 5G is going to cause some awful side\sphinxhyphen{}effect—a sign that the +hype around 5G might not be working as intended. + +\sphinxAtStartPar +The important thing to understand about 5G is that it implies much more +than a generational upgrade in bandwidth (although it does involve +that too). It involves transformative +changes to the access network that will make it much more like a +modern cloud. Important technology trends such as software\sphinxhyphen{}defined +networking (SDN) and open source software will lead to an +access network that is much more nimble and innovative. And +it will enable new classes of application, particularly a broad set of +IoT (Internet of Things) applications. In fact we could even see the +“Access\sphinxhyphen{}as\sphinxhyphen{}frontend\sphinxhyphen{}to\sphinxhyphen{}Internet” perspective being turned on its head, as the +access network itself becomes a collection of clouds with new services +delivered directly from “edge clouds”. + +\sphinxAtStartPar +This book is written for someone who has a working understanding of the +Internet and the cloud, but has had limited success penetrating the myriad +of acronyms that dominate cellular networking. In fairness, the Internet +has its share of acronyms, but it also comes with a sufficient set of +abstractions to help manage the complexity. It’s hard to say the same +for the cellular network, where pulling on one thread seemingly unravels +the entire space. It has also been the case that the cellular network +had been largely hidden inside proprietary devices, which has made it +impossible to figure it out for yourself. + +\sphinxAtStartPar +This book is the result of a mobile networking expert teaching a +systems person about 5G as we’ve collaborated on an open source 5G +implementation. The material has been used to train other software +developers, and we are hopeful it will be useful to anyone who wants a +deeper understanding of 5G and the opportunity for innovation it +provides. Readers who want hands\sphinxhyphen{}on experience can also access the open +source software introduced in the book. + +\sphinxAtStartPar +This book will likely be a work\sphinxhyphen{}in\sphinxhyphen{}progress for the foreseeable future. +It’s not intended to be encyclopedic—favoring perspective and end\sphinxhyphen{}to\sphinxhyphen{}end +completeness over every last bit of detail—but we do plan to flesh out +the content over time. Your suggestions (and contributions) to this end +are welcome. + + +\section*{Acknowledgements} +\label{\detokenize{preface:acknowledgements}} +\sphinxAtStartPar +The software described in this book is due to the hard work of the ONF +engineering team and the open source community that works with +them. We acknowledge their contributions. We also thank Bruce Davie, +Guru Parulkar, and Changhoon Kim for their feedback on early drafts of +the manuscript. + +\begin{DUlineblock}{0em} +\item[] Larry Peterson and Oguz Sunay +\item[] Open Networking Foundation +\item[] March 2020 +\end{DUlineblock} + + +\chapter{Chapter 1: Introduction} +\label{\detokenize{intro:chapter-1-introduction}}\label{\detokenize{intro::doc}} +\sphinxAtStartPar +Mobile networks, which have a 40\sphinxhyphen{}year history that parallels the +Internet’s, have undergone significant change. The first two +generations supported voice and then text, with 3G defining the +transition to broadband access, supporting data rates measured in +hundreds of kilobits\sphinxhyphen{}per\sphinxhyphen{}second. Today, the industry is at 4G +(supporting data rates typically measured in the few +megabits\sphinxhyphen{}per\sphinxhyphen{}second) and transitioning to 5G, with the promise of a +tenfold increase in data rates. + +\sphinxAtStartPar +But 5G is about much more than increased bandwidth. 5G represents a +fundamental rearchitecting of the access network in a way that +leverages several key technology trends and sets it on a path to enable +much greater innovation. In the same way that 3G +defined the transition from voice to broadband, 5G’s promise is primarily +about the transition from a single access service (broadband +connectivity) to a richer collection of edge services and devices. 5G +is expected to provide support for immersive user interfaces (e.g., AR/VR), +mission\sphinxhyphen{}critical applications (e.g., public safety, autonomous +vehicles), and the Internet\sphinxhyphen{}of\sphinxhyphen{}Things (IoT). Because these use cases +will include everything from home appliances to industrial robots to +self\sphinxhyphen{}driving cars, 5G won’t just support humans accessing the Internet +from their smartphones, but also swarms of autonomous devices working +together on their behalf. There is more to supporting these services +than just improving bandwidth or latency to individual users. As we will see, a fundamentally +different edge network architecture is required. + +\sphinxAtStartPar +The requirements for this architecture are ambitious, and can be +illustrated by three classes of capabilities: +\begin{itemize} +\item {} +\sphinxAtStartPar +To support \sphinxstyleemphasis{Massive Internet\sphinxhyphen{}of\sphinxhyphen{}Things}, potentially including +devices with ultra\sphinxhyphen{}low energy (10+ years of battery life), ultra\sphinxhyphen{}low +complexity (10s of bits\sphinxhyphen{}per\sphinxhyphen{}second), and ultra\sphinxhyphen{}high density (1 +million nodes per square kilometer). + +\item {} +\sphinxAtStartPar +To support \sphinxstyleemphasis{Mission\sphinxhyphen{}Critical Control}, potentially including +ultra\sphinxhyphen{}high availability (greater than 99.999\% or “five nines”), +ultra\sphinxhyphen{}low latency (as low as 1 ms), and extreme mobility (up to 100 +km/h). + +\item {} +\sphinxAtStartPar +To support \sphinxstyleemphasis{Enhanced Mobile Broadband}, potentially including extreme data rates +(multi\sphinxhyphen{}Gbps peak, 100+ Mbps sustained) and extreme +capacity (10 Tbps of aggregate throughput per square kilometer). + +\end{itemize} + +\sphinxAtStartPar +These targets will certainly not be met overnight, but that’s in keeping +with each generation of the mobile network being a decade\sphinxhyphen{}long +endeavor. + +\sphinxAtStartPar +On top of these quantitative improvements to the capabilities of the access +network, 5G is being viewed as a chance for building a platform to +support innovation. Whereas prior access networks were generally +optimized for known services (such as voice calls and SMS), the +Internet has been hugely successful in large part because it supported +a wide range of applications that were not even thought of when it was +first designed. The 5G network is very much being designed with this +same goal of enabling all sorts of future applications beyond those we +fully recognize today. + +\phantomsection\label{\detokenize{intro:reading-vision}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +For an example of the grand vision for 5G from one of the industry +leaders, see \sphinxhref{https://www.qualcomm.com/media/documents/files/whitepaper-making-5g-nr-a-reality.pdf}{Making 5G NR a Reality}. +Qualcomm Whitepaper, December 2016. +\end{sphinxadmonition} + +\sphinxAtStartPar +The 5G mobile network, because it is on an +evolutionary path and not a point solution, includes standardized +specifications, a range of implementation choices, and a long list of +aspirational goals. Because this leaves so much room for interpretation, +our approach to describing 5G is grounded in two mutually supportive +principles. The first is to apply a \sphinxstyleemphasis{systems lens}, which is to say, we +explain the sequence of design decisions that lead to a solution rather +than fall back on enumerating the overwhelming number of acronyms or +individual point technologies as a +\sphinxstyleemphasis{fait accompli}. The second is to aggressively disaggregate the system. +Building a disaggregated, virtualized, and software\sphinxhyphen{}defined 5G access +network is the direction the industry is already headed (for good +technical and business reasons), but breaking the 5G network down into +its elemental components is also the best way to explain how 5G works. +It also helps to illustrate how 5G might evolve in the future to provide +even more value. + +\begin{sphinxShadowBox} +\sphinxstylesidebartitle{Evolutionary Path} + +\sphinxAtStartPar +That 5G is on an evolutionary path is the central theme of +this book. We call attention to its importance here, and +revisit the topic throughout the book. + +\sphinxAtStartPar +We are writing this book for \sphinxstyleemphasis{system generalists}, with the +goal of helping bring a community that understands a broad +range of systems issues (but knows little or nothing about the +cellular network) up to speed so they can play a role in its +evolution. This is a community that understands both feature +velocity and best practices in building robust scalable +systems, and so has an important role to play in bringing all +of 5G’s potential to fruition. +\end{sphinxShadowBox} + +\sphinxAtStartPar +What this all means is that there is no single, comprehensive definition +of 5G, any more than there is for the Internet. It is a complex and +evolving system, constrained by a set of standards that purposely give +all the stakeholders many degrees of freedom. In the chapters that +follow, it should be clear from the context whether we are talking about +\sphinxstyleemphasis{standards} (what everyone must do to interoperate), \sphinxstyleemphasis{trends} (where +the industry seems to be headed), or \sphinxstyleemphasis{implementation choices} +(examples to make the discussion more concrete). By adopting a systems +perspective throughout, our intent is to describe 5G in a way that +helps the reader navigate this rich and rapidly evolving system. + + +\section{1.1 Standardization Landscape} +\label{\detokenize{intro:standardization-landscape}} +\sphinxAtStartPar +As of 3G, the generational designation corresponds to a standard defined +by the \sphinxstyleemphasis{3rd Generation Partnership Project (3GPP)}. Even though its name +has “3G” in it, the 3GPP continues to define the standards for 4G and 5G, +each of which corresponds to a sequence of releases of the standard. +Release 15 is considered the demarcation point between 4G and 5G, with +Release 17 scheduled for 2021. Complicating the terminology, 4G +was on a multi\sphinxhyphen{}release evolutionary path referred to as \sphinxstyleemphasis{Long Term +Evolution (LTE)}. 5G is on a similar evolutionary path, with several +expected releases over its lifetime. + +\sphinxAtStartPar +While 5G is an ambitious advance beyond 4G, it is also the case that +understanding 4G is the first step to understanding 5G, as several +aspects of the latter can be explained as bringing a new +degree\sphinxhyphen{}of\sphinxhyphen{}freedom to the former. In the chapters that follow, we often +introduce some architectural feature of 4G as a way of laying the +foundation for the corresponding 5G component. + +\sphinxAtStartPar +Like Wi\sphinxhyphen{}Fi, cellular networks transmit data at certain bandwidths in the +radio spectrum. Unlike Wi\sphinxhyphen{}Fi, which permits anyone to use a channel at +either 2.4 or 5 GHz (these are unlicensed bands), governments have +auctioned off and licensed exclusive use of various frequency bands to +service providers, who in turn sell mobile access service to their +subscribers. + +\sphinxAtStartPar +There is also a shared\sphinxhyphen{}license band at 3.5 GHz, called \sphinxstyleemphasis{Citizens +Broadband Radio Service (CBRS)}, set aside in North America for cellular +use. Similar spectrum is being set aside in other countries. The CBRS band +allows 3 tiers of users to share the spectrum: first right of use +goes to the original owners of this spectrum (naval radars and satellite +ground stations); followed by priority users who receive this right over +10MHz bands for three years via regional auctions; and finally the rest +of the population, who can access and utilize a portion of this band as +long as they first check with a central database of registered users. +CBRS, along with standardization efforts to extend cellular networks to +operate in the unlicensed bands, open the door for private cellular +networks similar to Wi\sphinxhyphen{}Fi. + +\sphinxAtStartPar +The specific frequency bands that are licensed for cellular networks +vary around the world, and are complicated by the fact that network +operators often simultaneously support both old/legacy technologies and +new/next\sphinxhyphen{}generation technologies, each of which occupies a different +frequency band. The high\sphinxhyphen{}level summary is that traditional cellular +technologies range from 700\sphinxhyphen{}2400 MHz, with new mid\sphinxhyphen{}spectrum +allocations now happening at 6 GHz, and millimeter\sphinxhyphen{}wave (mmWave) +allocations opening above 24 GHz. + +\sphinxAtStartPar +While the specific frequency band is not directly relevant to +understanding 5G from an architectural perspective, it does impact the +physical\sphinxhyphen{}layer components, which in turn has indirect ramifications on +the overall 5G system. We identify and explain these ramifications +in later chapters. Ensuring that the allocated spectrum is used +\sphinxstyleemphasis{efficiently} is also a critical design goal. + + +\section{1.2 Access Networks} +\label{\detokenize{intro:access-networks}} +\sphinxAtStartPar +The cellular network is part of the access network that implements the +Internet’s so\sphinxhyphen{}called \sphinxstyleemphasis{last mile}. Other access technologies include +\sphinxstyleemphasis{Passive Optical Networks (PON)}, colloquially known as +Fiber\sphinxhyphen{}to\sphinxhyphen{}the\sphinxhyphen{}Home. These access networks are provided by both big and +small network operators. Global network operators like AT\&T run access +networks at thousands of aggregation points\sphinxhyphen{}of\sphinxhyphen{}presence across a +country like the US, along with a national backbone that interconnects +those sites. Small regional and municipal network operators might run +an access network with one or two points\sphinxhyphen{}of\sphinxhyphen{}presence, and then connect +to the rest of the Internet through some large operator’s backbone. + +\sphinxAtStartPar +In either case, access networks are physically anchored at thousands of +aggregation points\sphinxhyphen{}of\sphinxhyphen{}presence within close proximity to end users, +each of which serves anywhere from 1,000\sphinxhyphen{}100,000 subscribers, +depending on population density. In practice, the physical deployment +of these “edge” locations vary from operator to operator, but one +possible scenario is to anchor both the cellular and wireline access +networks in Telco \sphinxstyleemphasis{Central Offices}. + +\sphinxAtStartPar +Historically, the Central Office—officially known as the \sphinxstyleemphasis{PSTN +(Public Switched Telephone Network) Central Office}—anchored wired +access (both telephony and broadband), while the cellular network +evolved independently by deploying a parallel set of \sphinxstyleemphasis{Mobile Telephone +Switching Offices (MTSO)}. Each MTSO serves as a \sphinxstyleemphasis{mobile aggregation} +point for the set of cell towers in a given geographic area. For our +purposes, the important idea is that such aggregation points exist, and +it is reasonable to think of them as defining the edge of the +operator\sphinxhyphen{}managed access network. For simplicity, we sometimes use the +term “Central Office” as a synonym for both types of edge sites. + + +\section{1.3 Edge Cloud} +\label{\detokenize{intro:edge-cloud}} +\sphinxAtStartPar +Because of their wide distribution and close proximity to end users, +Central Offices are also an ideal place to host the edge cloud. But this +raises the question: What exactly is the edge cloud? + +\sphinxAtStartPar +In a nutshell, the cloud began as a collection of warehouse\sphinxhyphen{}sized +datacenters, each of which provided a cost\sphinxhyphen{}effective way to power, cool, +and operate a scalable number of servers. Over time, this shared +infrastructure lowered the barrier to deploying scalable Internet +services, but today, there is increasing pressure to offer +low\sphinxhyphen{}latency/high\sphinxhyphen{}bandwidth cloud applications that cannot be effectively +implemented in centralized datacenters. Augmented Reality (AR), Virtual +Reality (VR), Internet\sphinxhyphen{}of\sphinxhyphen{}Things (IoT), and Autonomous Vehicles are all +examples of this kind of application. This has resulted in a trend to +move some functionality out of the datacenter and towards the edge of +the network, closer to end users. + +\sphinxAtStartPar +Where this edge is \sphinxstyleemphasis{physically} located depends on who you ask. If you +ask a network operator that already owns and operates thousands of +Central Offices, then their Central Offices are an obvious answer. +Others might claim the edge is located at the 14,000 Starbucks across +the US, and still others might point to the tens\sphinxhyphen{}of\sphinxhyphen{}thousands of cell +towers spread across the globe. + +\sphinxAtStartPar +Our approach is to be location agnostic, but it is worth pointing out +that the cloud’s migration to the edge coincides with a second trend, +which is that network operators are re\sphinxhyphen{}architecting the access network +to use the same commodity hardware and best practices in building +scalable software as the cloud providers. Such a design, which is +sometimes referred to as CORD \sphinxstyleemphasis{(Central Office Re\sphinxhyphen{}architected as a +Datacenter)}, supports both the access network and edge services +co\sphinxhyphen{}located on a shared cloud platform. This platform is then replicated +across hundreds or thousands of sites (including, but not limited to, +Central Offices). So while we shouldn’t limit ourselves to the Central +Office as the only answer to the question of where the edge cloud is +located, it is becoming a viable option. + +\phantomsection\label{\detokenize{intro:reading-cord}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +To learn about the technical origins of CORD, which was first +applied to fiber\sphinxhyphen{}based access networks (PON), see \sphinxhref{https://wiki.opencord.org/download/attachments/1278027/PETERSON\_CORD.pdf}{Central Office +Re\sphinxhyphen{}architected as a Datacenter, IEEE Communications, October 2016}. + +\sphinxAtStartPar +To understand the business case for CORD (and CORD\sphinxhyphen{}inspired +technologies), see the A.D. Little report \sphinxhref{https://www.adlittle.com/en/who-dares-wins}{Who Dares Wins! +How Access Transformation Can Fast\sphinxhyphen{}Track Evolution of +Operator Production Platforms, September 2019}. +\end{sphinxadmonition} + +\sphinxAtStartPar +When we get into the details of how 5G can be implemented in practice, +we use CORD as our exemplar. For now, the important thing to understand +is that 5G is being implemented as software running on commodity +hardware, rather than embedded in the special\sphinxhyphen{}purpose proprietary +hardware used in past generations. This has a significant impact on how +we think about 5G (and how we describe 5G), which will increasingly +become yet another software\sphinxhyphen{}based component in the cloud, as opposed to +an isolated and specialized technology attached to the periphery of the +cloud. + +\sphinxAtStartPar +Keep in mind that our use of CORD as an exemplar is not to imply that +the edge cloud is limited to Central Offices. CORD is a good exemplar +because it is designed to host both edge services and access +technologies like 5G on a common platform, where the Telco Central +Office is one possible location to deploy such a platform. + +\sphinxAtStartPar +An important takeaway from this discussion is that to understand how 5G +is being implemented, it is helpful to have a working understanding of +how clouds are built. This includes the use of \sphinxstyleemphasis{commodity hardware} +(both servers and white\sphinxhyphen{}box switches), horizontally scalable +\sphinxstyleemphasis{microservices} (also referred to as \sphinxstyleemphasis{cloud native}), and +\sphinxstyleemphasis{Software\sphinxhyphen{}Defined Networks (SDN)}. It is also helpful to have an +appreciation for how cloud software is developed, tested, deployed, and +operated, including practices like \sphinxstyleemphasis{DevOps} and \sphinxstyleemphasis{Continuous Integration +/ Continuous Deployment (CI/CD)}. + +\phantomsection\label{\detokenize{intro:reading-devops}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +If you are unfamiliar with SDN, we recommend a companion book: +\sphinxhref{https://sdn.systemsapproach.org/}{Software\sphinxhyphen{}Defined Networks: A Systems Approach}. March 2020. + +\sphinxAtStartPar +If you are unfamiliar with DevOps—or more generally, with the +operational issues cloud providers face—we recommend \sphinxhref{https://landing.google.com/sre/books/}{Site +Reliability Engineering: How Google Runs Production Systems}. +\end{sphinxadmonition} + +\sphinxAtStartPar +One final note about terminology. Anyone who has been paying +attention to the discussion surrounding 5G will have undoubtedly heard +about \sphinxstyleemphasis{Network Function Virtualization (NFV)}, which involves moving +functionality that was once embedded in hardware appliances into VMs +(or, more recently, containers) +running on commodity servers. In our experience, NFV is a stepping +stone towards the fully disaggregated and cloud native solution we +describe in this book, and so we do not dwell on it. You can think of +the NFV initiative as mostly consistent with the approach taken in +this book, but making some specific engineering choices that may +differ in detail from that described here. + +\sphinxAtStartPar +While equating NFV with an implementation choice is perfectly valid, +there is another interpretation of events that better captures the +essence of the transformation currently underway. When Telcos began +the NFV initiative, they imagined incorporating cloud technologies +into their networks, creating a so\sphinxhyphen{}called \sphinxstyleemphasis{Telco Cloud}. What is +actually happening instead, is that the Telco’s access technology is +being subsumed into the cloud, running as yet another cloud\sphinxhyphen{}hosted +workload. It would be more accurate to refer to the resulting system +now emerging as the \sphinxstyleemphasis{Cloud\sphinxhyphen{}based Telco}. One reading of this book is +as a roadmap to such an outcome. + + +\chapter{Chapter 2: Radio Transmission} +\label{\detokenize{primer:chapter-2-radio-transmission}}\label{\detokenize{primer::doc}} +\sphinxAtStartPar +For anyone familiar with wireless access technologies like Wi\sphinxhyphen{}Fi, the +cellular network is most unique due to its approach to sharing the +available radio spectrum among its many users, all the while allowing +those users to remain connected while moving. This has resulted in a +highly dynamic and adaptive approach, in which coding, modulation and +scheduling play a central role. + +\sphinxAtStartPar +As we will see in this chapter, cellular networks use a +reservation\sphinxhyphen{}based strategy, whereas Wi\sphinxhyphen{}Fi is contention\sphinxhyphen{}based. This +difference is rooted in each system’s fundamental assumption about +utilization: Wi\sphinxhyphen{}Fi assumes a lightly loaded network (and hence +optimistically transmits when the wireless link is idle and backs off if +contention is detected), while 4G and 5G cellular networks assume (and +strive for) high utilization (and hence explicitly assign different +users to different “shares” of the available radio spectrum). + +\sphinxAtStartPar +We start by giving a short primer on radio transmission as a way of +laying a foundation for understanding the rest of the 5G architecture. +The following is not a substitute for a theoretical treatment of the topic, +but is instead intended as a way of grounding the systems\sphinxhyphen{}oriented +description of 5G that follows in the reality of wireless communication. + + +\section{2.1 Coding and Modulation} +\label{\detokenize{primer:coding-and-modulation}} +\sphinxAtStartPar +The mobile channel over which digital data needs to be reliably +transmitted brings a number of impairments, including noise, +attenuation, distortion, fading, and interference. This challenge is +addressed by a combination of coding and modulation, as depicted in +\hyperref[\detokenize{primer:fig-modulation}]{Figure \ref{\detokenize{primer:fig-modulation}}}. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=500\sphinxpxdimen]{{Slide09}.png} +\caption{The role of coding and modulation in mobile communication.}\label{\detokenize{primer:id5}}\label{\detokenize{primer:fig-modulation}}\end{figure} + +\sphinxAtStartPar +At its core, coding inserts extra bits into the data to help recover +from all the environmental factors that interfere with signal +propagation. This typically implies some form of \sphinxstyleemphasis{Forward Error +Correction} (e.g., turbo codes, polar codes). Modulation then +generates signals that represent the encoded data stream, and it does +so in a way that matches the channel characteristics: It first uses a +digital modulation signal format that maximizes the number of reliably +transmitted bits every second based on the specifics of the observed +channel impairments; it next matches the transmission +bandwidth to channel bandwidth using pulse shaping; and finally, it +uses RF modulation to transmit the signal as an electromagnetic wave +over an assigned \sphinxstyleemphasis{carrier frequency.} + +\sphinxAtStartPar +For a deeper appreciation of the challenges of reliably transmitting +data by propagating radio signals through the air, consider the +scenario depicted in \hyperref[\detokenize{primer:fig-multipath}]{Figure \ref{\detokenize{primer:fig-multipath}}}, where +the signal bounces off various stationary and moving objects, +following multiple paths from the transmitter to the receiver, who may +also be moving. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide10}.png} +\caption{Signals propagate along multiple paths from +transmitter to receiver.}\label{\detokenize{primer:id6}}\label{\detokenize{primer:fig-multipath}}\end{figure} + +\sphinxAtStartPar +As a consequence of these multiple paths, the original signal arrives at +the receiver spread over time, as illustrated in +\hyperref[\detokenize{primer:fig-coherence}]{Figure \ref{\detokenize{primer:fig-coherence}}}. Empirical evidence shows that the +Multipath Spread—the time between the first and last signals of one +transmission arriving at the receiver—is 1\sphinxhyphen{}10μs in urban +environments and 10\sphinxhyphen{}30μs in suburban environments. These multipath +signals can interfere with each other constructively or destructively, +and this will vary over time. Theoretical +bounds for the time duration for which the channel may be assumed to +be invariant, known as the \sphinxstyleemphasis{Coherence Time} and denoted +\(T_c\), is given by +\begin{equation*} +\begin{split}T_c =c/v \times 1/f\end{split} +\end{equation*} +\sphinxAtStartPar +where \(c\) is the velocity of the signal, \(v\) is the +velocity of the receiver (e.g., moving car or train), and \(f\) is +the frequency of the carrier signal that is being modulated. This +says the coherence time is inversely proportional to the frequency of +the signal and the speed of movement, which makes intuitive sense: The +higher the frequency (narrower the wave) the shorter the coherence time, +and likewise, the faster the receiver is moving the shorter the coherence +time. Based on the target parameters to this model (selected according +to the target physical environment), it is possible to calculate +\(T_c\), which in turn bounds the rate at which symbols can be +transmitted without undue risk of interference. The dynamic nature of +the wireless channel is a central challenge to address in the cellular +network. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=500\sphinxpxdimen]{{Slide11}.png} +\caption{Received data spread over time due to multipath +variation.}\label{\detokenize{primer:id7}}\label{\detokenize{primer:fig-coherence}}\end{figure} + +\sphinxAtStartPar +To complicate matters further, +\hyperref[\detokenize{primer:fig-multipath}]{Figure \ref{\detokenize{primer:fig-multipath}}} and \hyperref[\detokenize{primer:fig-coherence}]{\ref{\detokenize{primer:fig-coherence}}} imply +the transmission originates from a single +antenna, but cell towers are equipped with an array of antennas, each +transmitting in a different (but overlapping) direction. This +technology, called \sphinxstyleemphasis{Multiple\sphinxhyphen{}Input\sphinxhyphen{}Multiple\sphinxhyphen{}Output (MIMO)}, opens the +door to purposely transmitting data from multiple antennas in an effort +to reach the receiver, adding even more paths to the environment\sphinxhyphen{}imposed +multipath propagation. + +\sphinxAtStartPar +One of the most important consequences of these factors is that the +transmitter must receive feedback from every receiver to judge how to +best utilize the wireless medium on their behalf. 3GPP specifies a +\sphinxstyleemphasis{Channel Quality Indicator (CQI)} for this purpose, where in practice +the receiver sends a CQI status report to the base station periodically +(e.g., every millisecond in LTE). These CQI messages report the observed +signal\sphinxhyphen{}to\sphinxhyphen{}noise ratio, which impacts the receiver’s ability to recover +the data bits. The base station then uses this information to adapt how +it allocates the available radio spectrum to the subscribers it is +serving, as well as which coding and modulation scheme to employ. +All of these decisions are made by the scheduler. + + +\section{2.2 Scheduler} +\label{\detokenize{primer:scheduler}} +\sphinxAtStartPar +How the scheduler does its job is one of the most important properties +of each generation of the cellular network, which in turn depends on +the multiplexing mechanism. For example, 2G used \sphinxstyleemphasis{Time Division +Multiple Access (TDMA)} and 3G used \sphinxstyleemphasis{Code Division Multiple Access +(CDMA)}. How data is multiplexed is also a major differentiator for 4G +and 5G, completing the transition from the cellular network being +fundamentally circuit\sphinxhyphen{}switched to fundamentally packet\sphinxhyphen{}switched. + +\sphinxAtStartPar +Both 4G and 5G are based on \sphinxstyleemphasis{Orthogonal Frequency\sphinxhyphen{}Division +Multiplexing (OFDM)}, an approach that multiplexes data over multiple +orthogonal subcarrier frequencies, each of which is modulated +independently. The value and efficiency of OFDM is in how it selects +subcarrier frequencies so as to avoid interference, that is, how it +achieves orthogonality. That topic is beyond the scope of this book. +We instead take a decidedly abstract perspective of multiplexing, +focusing on “discrete schedulable units of the radio spectrum” rather +than the signalling and modulation underpinnings that yield those +schedulable units. + +\sphinxAtStartPar +To start, we drill down on these schedulable units. We return to the +broader issue of the \sphinxstyleemphasis{air interface} that makes efficient use of the +spectrum in the concluding section. + + +\subsection{Multiplexing in 4G} +\label{\detokenize{primer:multiplexing-in-4g}} +\sphinxAtStartPar +The 4G approach to multiplexing downstream transmissions is called +\sphinxstyleemphasis{Orthogonal Frequency\sphinxhyphen{}Division Multiple Access (OFDMA)}, a specific +application of OFDM that multiplexes data over a set of 12 orthogonal +subcarrier frequencies, each of which is modulated independently.% +\begin{footnote}[1]\sphinxAtStartFootnote +4G uses a different multiplexing strategy for upstream +transmissions (from user devices to base stations), but we do +not describe it because the approach is not applicable to 5G. +% +\end{footnote} The +“Multiple Access” in OFDMA implies that data can simultaneously be +sent on behalf of multiple users, each on a different subcarrier +frequency and for a different duration of time. The subbands are +narrow (e.g., 15 kHz), but the coding of user data into OFDMA symbols +is designed to minimize the risk of data loss due to interference +between adjacent bands. + +\sphinxAtStartPar +The use of OFDMA naturally leads to conceptualizing the radio spectrum +as a 2\sphinxhyphen{}D resource, as shown in \hyperref[\detokenize{primer:fig-sched-grid}]{Figure \ref{\detokenize{primer:fig-sched-grid}}}. +The minimal schedulable unit, called a \sphinxstyleemphasis{Resource Element (RE)}, +corresponds to a 15\sphinxhyphen{}kHz band around one subcarrier frequency and the +time it takes to transmit one OFDMA symbol. The number of bits that can +be encoded in each symbol depends on the modulation rate, so for example +using \sphinxstyleemphasis{Quadrature Amplitude Modulation (QAM)}, 16\sphinxhyphen{}QAM yields 4 bits per +symbol and 64\sphinxhyphen{}QAM yields 6 bits per symbol. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide12}.png} +\caption{Spectrum abstractly represented by a 2\sphinxhyphen{}D grid of +schedulable Resource Elements.}\label{\detokenize{primer:id8}}\label{\detokenize{primer:fig-sched-grid}}\end{figure} + +\sphinxAtStartPar +A scheduler allocates some number of REs to each user that has data to +transmit during each 1 ms \sphinxstyleemphasis{Transmission Time Interval (TTI)}, where users +are depicted by different colored blocks in \hyperref[\detokenize{primer:fig-sched-grid}]{Figure \ref{\detokenize{primer:fig-sched-grid}}}. +The only constraint on the scheduler is that it must make its allocation +decisions on blocks of 7x12=84 resource elements, called a \sphinxstyleemphasis{Physical +Resource Block (PRB)}. \hyperref[\detokenize{primer:fig-sched-grid}]{Figure \ref{\detokenize{primer:fig-sched-grid}}} shows two +back\sphinxhyphen{}to\sphinxhyphen{}back PRBs. Of course time continues to flow along one axis, and +depending on the size of the available frequency band (e.g., it might be +100 MHz wide), there may be many more subcarrier slots (and hence PRBs) +available along the other axis, so the scheduler is essentially +preparing and transmitting a sequence of PRBs. + +\sphinxAtStartPar +Note that OFDMA is not a coding/modulation algorithm, but instead +provides a framework for selecting a specific coding and modulator for +each subcarrier frequency. QAM is one common example modulator. It is +the scheduler’s responsibility to select the modulation to use for each +PRB, based on the CQI feedback it has received. The scheduler also +selects the coding on a per\sphinxhyphen{}PRB basis, for example, by how it sets the +parameters to the turbo code algorithm. + +\sphinxAtStartPar +The 1\sphinxhyphen{}ms TTI corresponds to the time frame in which the scheduler +receives feedback from users about the quality of the signal they are +experiencing. This is the CQI mentioned earlier, where once every +millisecond, each user sends a set of metrics, which the scheduler uses +to make its decision as to how to allocate PRBs during the subsequent +TTI. + +\sphinxAtStartPar +Another input to the scheduling decision is the \sphinxstyleemphasis{QoS Class Identifier +(QCI)}, which indicates the quality\sphinxhyphen{}of\sphinxhyphen{}service each class of traffic is +to receive. In 4G, the QCI value assigned to each class (there are nine +such classes, in total) indicates whether the traffic has a \sphinxstyleemphasis{Guaranteed +Bit Rate (GBR)} or not \sphinxstyleemphasis{(non\sphinxhyphen{}GBR)}, plus the class’s relative priority +within those two categories. + +\sphinxAtStartPar +Finally, keep in mind that \hyperref[\detokenize{primer:fig-sched-grid}]{Figure \ref{\detokenize{primer:fig-sched-grid}}} focuses on +scheduling transmissions from a single antenna, but the MIMO technology +described above means the scheduler also has to determine which antenna +(or more generally, what subset of antennas) will most effectively reach +each receiver. But again, in the abstract, the scheduler is charged with +allocating a sequence of Resource Elements. + +\sphinxAtStartPar +This all raises the question: How does the scheduler decide which set of +users to service during a given time interval, how many resource +elements to allocate to each such user, how to select the coding and +modulation levels, and which antenna to transmit their data on? This is +an optimization problem that, fortunately, we are not trying to solve +here. Our goal is to describe an architecture that allows someone else +to design and plug in an effective scheduler. Keeping the cellular +architecture open to innovations like this is one of our goals, and as +we will see in the next section, becomes even more important in 5G where +the scheduler operates with even more degrees of freedom. + + +\subsection{Multiplexing in 5G} +\label{\detokenize{primer:multiplexing-in-5g}} +\sphinxAtStartPar +The transition from 4G to 5G introduces additional flexibility in +how the radio spectrum is scheduled, making it possible to adapt the +cellular network to a more diverse set of devices and applications +domains. + +\sphinxAtStartPar +Fundamentally, 5G defines a family of waveforms—unlike LTE, which +specified only one waveform—each optimized for a different band in the +radio spectrum.% +\begin{footnote}[2]\sphinxAtStartFootnote +A waveform is the frequency, amplitude, and phase\sphinxhyphen{}shift +independent property (shape) of a signal. A sine wave is an example +waveform. +% +\end{footnote} The bands with carrier frequencies below 1 GHz are +designed to deliver mobile broadband and massive IoT services with a +primary focus on range. Carrier frequencies between 1\sphinxhyphen{}6 GHz are +designed to offer wider bandwidths, focusing on mobile broadband and +mission\sphinxhyphen{}critical applications. Carrier frequencies above 24 GHz +(mmWaves) are designed to provide super wide bandwidths over short, +line\sphinxhyphen{}of\sphinxhyphen{}sight coverage. + +\sphinxAtStartPar +These different waveforms affect the scheduling and subcarrier intervals +(i.e., the “size” of the resource elements described in the previous +section). +\begin{itemize} +\item {} +\sphinxAtStartPar +For sub\sphinxhyphen{}1 GHz bands, 5G allows maximum 50 MHz bandwidths. In this case, +there are two waveforms: one with subcarrier spacing of 15 kHz and +another of 30 kHz. (We used 15 kHz in the example shown in +\hyperref[\detokenize{primer:fig-sched-grid}]{Figure \ref{\detokenize{primer:fig-sched-grid}}}.) +The corresponding scheduling intervals are +0.5 and 0.25 ms, respectively. (We used 0.5 ms in the example shown +in \hyperref[\detokenize{primer:fig-sched-grid}]{Figure \ref{\detokenize{primer:fig-sched-grid}}}.) + +\item {} +\sphinxAtStartPar +For 1\sphinxhyphen{}6 GHz bands, maximum bandwidths go up to 100 MHz. +Correspondingly, there are three waveforms with subcarrier spacings +of 15, 30 and 60 kHz, corresponding to scheduling intervals of +0.5, 0.25, and 0.125 ms, respectively. + +\item {} +\sphinxAtStartPar +For millimeter bands, bandwidths may go up to 400 MHz. There are two +waveforms, with subcarrier spacings of 60 kHz and 120 kHz. Both have +scheduling intervals of 0.125 ms. + +\end{itemize} + +\sphinxAtStartPar +These various configurations of subcarrier spacing and scheduling +intervals are sometimes called the \sphinxstyleemphasis{numerology} of the radio’s air +interface. + +\sphinxAtStartPar +This range of numerology is important because it adds another degree +of freedom to the scheduler. In addition to allocating radio resources +to users, it has the ability to dynamically adjust the size of the +resource by changing the wave form being used. With this additional +freedom, fixed\sphinxhyphen{}sized REs are no longer the primary unit of resource +allocation. We instead use more abstract terminology, and talk about +allocating \sphinxstyleemphasis{Resource Blocks} to subscribers, where the 5G scheduler +determines both the size and number of Resource Blocks allocated +during each time interval. + +\sphinxAtStartPar +\hyperref[\detokenize{primer:fig-scheduler}]{Figure \ref{\detokenize{primer:fig-scheduler}}} depicts the role of the scheduler +from this more abstract perspective, where just as with 4G, CQI +feedback from the receivers and the QCI quality\sphinxhyphen{}of\sphinxhyphen{}service class +selected by the subscriber are the two key pieces of input to the +scheduler. Note that the set of QCI values changes between 4G and 5G, +reflecting the increasing differentiation being supported. For 5G, +each class includes the following attributes: +\begin{itemize} +\item {} +\sphinxAtStartPar +Resource Type: Guaranteed Bit Rate (GBR), Delay\sphinxhyphen{}Critical GBR, Non\sphinxhyphen{}GBR + +\item {} +\sphinxAtStartPar +Priority Level + +\item {} +\sphinxAtStartPar +Packet Delay Budget + +\item {} +\sphinxAtStartPar +Packet Error Rate + +\item {} +\sphinxAtStartPar +Averaging Window + +\item {} +\sphinxAtStartPar +Maximum Data Burst + +\end{itemize} + +\sphinxAtStartPar +Note that while the preceding discussion could be interpreted to imply a +one\sphinxhyphen{}to\sphinxhyphen{}one relationship between subscribers and a QCI, it is more +accurate to say that each QCI is associated with a class of traffic +(often corresponding to some type of application), where a given +subscriber might be sending and receiving traffic that belongs to +multiple classes at any given time. We explore this idea in much more +depth in a later chapter. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide13}.png} +\caption{Scheduler allocates Resource Blocks to user data streams based on +CQI feedback from receivers and the QCI parameters associated with +each class of service.}\label{\detokenize{primer:id9}}\label{\detokenize{primer:fig-scheduler}}\end{figure} + + +\section{2.3 New Radio (NR)} +\label{\detokenize{primer:new-radio-nr}} +\sphinxAtStartPar +We conclude by noting that while the previous section describes 5G as +introducing additional degrees of freedom into how data is scheduled +for transmission, the end result is a qualitatively more powerful +radio. This new 5G air interface specification, which is commonly +referred to as \sphinxstyleemphasis{New Radio (NR)}, enables three new use cases that go +well beyond simply delivering increased bandwidth: +\begin{itemize} +\item {} +\sphinxAtStartPar +Extreme Mobile Broadband + +\item {} +\sphinxAtStartPar +Ultra\sphinxhyphen{}Reliable Low\sphinxhyphen{}Latency Communications + +\item {} +\sphinxAtStartPar +Massive Machine\sphinxhyphen{}Type Communications + +\end{itemize} + +\sphinxAtStartPar +All three correspond to the requirements introduced in Chapter 1, and +can be attributed to four fundamental improvements in how 5G +multiplexes data onto the radio spectrum. + +\sphinxAtStartPar +The first is the one identified in the previous section: being able to +change the waveform. This effectively introduces the ability to +dynamically change the size and number of schedulable resource units, +which opens the door to making fine\sphinxhyphen{}grain scheduling decisions that +are critical to predictable, low\sphinxhyphen{}latency communication. + +\sphinxAtStartPar +The second is related to the “Multiple Access” aspect of how distinct +traffic sources are multiplexed onto the available spectrum. In 4G, +multiplexing happens in both the frequency and time domains for +downstream traffic (as described in Section 2.2), but multiplexing +happens in only the frequency domain for upstream traffic. 5G NR +multiplexes both upstream and downstream traffic in both the time and +frequency domains. Doing so provides finer\sphinxhyphen{}grain scheduling control +needed by latency\sphinxhyphen{}sensitive applications. + +\sphinxAtStartPar +The third is related to the new spectrum available to 5G NR, with the +mmWave allocations opening above 24 GHz being especially +important. This is not only because of the abundance of capacity—which +makes it possible to set aside dedicated capacity for mission\sphinxhyphen{}critical +applications that require low\sphinxhyphen{}latency communication—but also because +the higher\sphinxhyphen{}frequency enables even finer\sphinxhyphen{}grain resource blocks (e.g., +scheduling intervals as short as 0.125 ms). Again, this improves +scheduling granularity to the benefit of applications that cannot +tolerate unpredictable latency. + +\sphinxAtStartPar +The fourth is related to delivering mobile connectivity to a massive +number of IoT devices, ranging from devices that require mobility +support and modest data rates (e.g. wearables, asset trackers) to +devices that support intermittent transmission of a few bytes of data +(e.g., sensors, meters). None of these devices are particularly +latency\sphinxhyphen{}sensitive or bandwidth\sphinxhyphen{}hungry, but the latter are especially +challenging because they require long battery lifetimes, and hence, +reduced hardware complexity that draws less power. + +\sphinxAtStartPar +Support for IoT device connectivity revolves around allocating some of +the available radio spectrum to a light\sphinxhyphen{}weight (simplified) air +interface. This approach started with Release 13 of LTE via two +complementary technologies: mMTC and NB\sphinxhyphen{}IoT (NarrowBand\sphinxhyphen{}IoT). Both +technologies build on a significantly simplified version of LTE—i.e., +limiting the numerology and flexibility needed achieve high spectrum +utilization—so as to allow for simpler IoT hardware design. mMTC +delivers up to 1 Mbps over a 1.4 MHz of bandwidth and NB\sphinxhyphen{}IoT delivers a +few tens of kbps over 200 kHz of bandwidth; hence the term +\sphinxstyleemphasis{NarrowBand}. Both technologies have been designed to support over 1 +million devices per square kilometer. With Release 16, both +technologies can be operated in\sphinxhyphen{}band with 5G, but still based on LTE +numerology. Starting with Release 17, a simpler version of 5G NR, +called \sphinxstyleemphasis{NR\sphinxhyphen{}Light}, will be introduced as the evolution of mMTC. +NR\sphinxhyphen{}Light is expected to scale the device density even further. + +\sphinxAtStartPar +As a consequence of all four improvements, 5G NR is designed to +support partitioning the available bandwidth, with different +partitions dynamically allocated to different classes of traffic +(e.g., high\sphinxhyphen{}bandwidth, low\sphinxhyphen{}latency, and low\sphinxhyphen{}complexity). This is the +essence of \sphinxstyleemphasis{slicing}, an idea we will revisit throughout this book. +Moreover, once traffic with different requirements can be served by +different slices, 5G NR’s approach to multiplexing is general enough +to support varied scheduling decisions for those slices, each tailored +for the target traffic. + + +\chapter{Chapter 3: Basic Architecture} +\label{\detokenize{arch:chapter-3-basic-architecture}}\label{\detokenize{arch::doc}} +\sphinxAtStartPar +This chapter identifies the main architectural components of cellular +access networks. It focuses on the components that are common to both 4G +and 5G and, as such, establishes a foundation for understanding the +advanced features of 5G presented in later chapters. + +\sphinxAtStartPar +This overview is partly an exercise in introducing 3GPP terminology. For +someone that is familiar with the Internet, this terminology can seem +arbitrary (e.g., “eNB” is a “base station”), but it is important to keep +in mind that this terminology came out of the 3GPP standardization +process, which has historically been concerned about telephony and +almost completely disconnected from the IETF and other Internet\sphinxhyphen{}related +efforts. To further confuse matters, the 3GPP terminology often changes +with each generation (e.g., a base station is called eNB in 4G and gNB +in 5G). We address situations like this by using generic terminology +(e.g., base station), and referencing the 3GPP\sphinxhyphen{}specific counterpart only +when the distinction is helpful. + +\phantomsection\label{\detokenize{arch:reading-terminology}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +This example is only the tip of the terminology iceberg. For a +slightly broader perspective on the complexity of terminology in +5G, see Marcin Dryjanski’s blog post: \sphinxhref{https://www.grandmetric.com/blog/2018/07/14/lte-and-5g-differences-system-complexity/}{LTE and 5G Differences: +System Complexity}. +July 2018. +\end{sphinxadmonition} + + +\section{3.1 Main Components} +\label{\detokenize{arch:main-components}} +\sphinxAtStartPar +The cellular network provides wireless connectivity to devices that are +on the move. These devices, which are known as \sphinxstyleemphasis{User Equipment (UE)}, +have traditionally corresponded to smartphones and tablets, but will +increasingly include cars, drones, industrial and agricultural machines, +robots, home appliances, medical devices, and so on. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide01}.png} +\caption{Cellular networks consists of a Radio Access Network +(RAN) and a Mobile Core.}\label{\detokenize{arch:id2}}\label{\detokenize{arch:fig-cellular}}\end{figure} + +\sphinxAtStartPar +As shown in \hyperref[\detokenize{arch:fig-cellular}]{Figure \ref{\detokenize{arch:fig-cellular}}}, the cellular network +consists of two main subsystems: the \sphinxstyleemphasis{Radio Access Network (RAN)} and +the \sphinxstyleemphasis{Mobile Core}. The RAN manages the radio spectrum, making sure it +is used efficiently and meets the quality\sphinxhyphen{}of\sphinxhyphen{}service requirements of +every user. It corresponds to a distributed collection of base +stations. As noted above, in 4G these are (somewhat cryptically) named +\sphinxstyleemphasis{eNodeB} (or \sphinxstyleemphasis{eNB}), which is short for \sphinxstyleemphasis{evolved Node B}. In 5G they +are known as \sphinxstyleemphasis{gNB}. (The g stands for “next Generation”.) + +\sphinxAtStartPar +The Mobile Core is a bundle of functionality (as opposed to a +device) that serves several purposes. +\begin{itemize} +\item {} +\sphinxAtStartPar +Provides Internet (IP) connectivity for both data and voice services. + +\item {} +\sphinxAtStartPar +Ensures this connectivity fulfills the promised QoS requirements. + +\item {} +\sphinxAtStartPar +Tracks user mobility to ensure uninterrupted service. + +\item {} +\sphinxAtStartPar +Tracks subscriber usage for billing and charging. + +\end{itemize} + +\sphinxAtStartPar +Note that Mobile Core is another example of a generic term. In 4G +this is called the \sphinxstyleemphasis{Evolved Packet Core (EPC)} and in 5G it is called +the \sphinxstyleemphasis{Next Generation Core (NG\sphinxhyphen{}Core)}. + +\sphinxAtStartPar +Even though the word “Core” is in its name, from an Internet +perspective, the Mobile Core is still part of the access network, +effectively providing a bridge between the RAN in some geographic area +and the greater IP\sphinxhyphen{}based Internet. 3GPP provides significant +flexibility in how the Mobile Core is geographically deployed, but for +our purposes, assuming each instantiation of the Mobile Core serves a +metropolitan area is a good working model. The corresponding RAN would +then span several dozens (or even hundreds) of cell towers. + +\sphinxAtStartPar +Taking a closer look at \hyperref[\detokenize{arch:fig-cellular}]{Figure \ref{\detokenize{arch:fig-cellular}}}, we see that a +\sphinxstyleemphasis{Backhaul Network} interconnects the base stations that implement the RAN with +the Mobile Core. This network is typically wired, may or may not have +the ring topology shown in the Figure, and is often constructed from +commodity components found elsewhere in the Internet. For example, the +\sphinxstyleemphasis{Passive Optical Network (PON)} that implements Fiber\sphinxhyphen{}to\sphinxhyphen{}the\sphinxhyphen{}Home is a +prime candidate for implementing the RAN backhaul. The backhaul network +is obviously a necessary part of the RAN, but it is an implementation +choice and not prescribed by the 3GPP standard. + +\sphinxAtStartPar +Although 3GPP specifies all the elements that implement the RAN and +Mobile Core in an open standard—including sub\sphinxhyphen{}layers we have not yet +introduced—network operators have historically bought proprietary +implementations of each subsystem from a single vendor. This lack of an +open source implementation contributes to the perceived “opaqueness” of +the cellular network in general, and the RAN in particular. And while it +is true that an eNodeB implementation does contain sophisticated +algorithms for scheduling transmission on the radio spectrum—algorithms +that are considered valuable intellectual property of the equipment +vendors—there is significant opportunity to open and disaggregate both +the RAN and the Mobile Core. The following two sections describe each, +in turn. + +\sphinxAtStartPar +Before getting to those details, \hyperref[\detokenize{arch:fig-cups}]{Figure \ref{\detokenize{arch:fig-cups}}} +redraws components from \hyperref[\detokenize{arch:fig-cellular}]{Figure \ref{\detokenize{arch:fig-cellular}}} to +highlight two important distinctions. The first is that a base station has an analog +component (depicted by an antenna) and a digital component (depicted +by a processor pair). The second is that the Mobile Core is +partitioned into a \sphinxstyleemphasis{Control Plane} and \sphinxstyleemphasis{User Plane}, which is similar +to the control/data plane split that someone familiar with the +Internet would recognize. (3GPP also recently introduced a +corresponding acronym—\sphinxstyleemphasis{CUPS, Control and User Plane Separation}—to +denote this idea.) The importance of these two distinctions will +become clear in the following discussion. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=400\sphinxpxdimen]{{Slide02}.png} +\caption{Mobile Core divided into a Control Plan and a User +Plane, an architectural feature known as CUPS: Control and User +Plane Separation}\label{\detokenize{arch:id3}}\label{\detokenize{arch:fig-cups}}\end{figure} + + +\section{3.2 Radio Access Network} +\label{\detokenize{arch:radio-access-network}} +\sphinxAtStartPar +We now describe the RAN by sketching the role each base station plays. +Keep in mind this is kind of like describing the Internet by explaining +how a router works—a not unreasonable place to start, but it doesn’t +fully do justice to the end\sphinxhyphen{}to\sphinxhyphen{}end story. + +\sphinxAtStartPar +First, each base station establishes the wireless channel for a +subscriber’s UE upon power\sphinxhyphen{}up or upon handover when the UE is active. +This channel is released when the UE remains idle for a predetermined +period of time. Using 3GPP terminology, this wireless channel is said to +provide a \sphinxstyleemphasis{bearer service}. The term “bearer” has historically been used in +telecommunications (including early wireline technologies like +ISDN) to denote a data channel, as opposed to a channel that +carries signaling information. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=500\sphinxpxdimen]{{Slide03}.png} +\caption{Base Station detects (and connects to) active UEs.}\label{\detokenize{arch:id4}}\label{\detokenize{arch:fig-active-ue}}\end{figure} + +\sphinxAtStartPar +Second, each base station establishes “3GPP Control Plane” +connectivity between the UE and the corresponding Mobile Core Control +Plane component, and forwards signaling traffic between the two. This +signaling traffic enables UE authentication, registration, and +mobility tracking. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=500\sphinxpxdimen]{{Slide04}.png} +\caption{Base Station establishes control plane connectivity +between each UE and the Mobile Core.}\label{\detokenize{arch:id5}}\label{\detokenize{arch:fig-control-plane}}\end{figure} + +\sphinxAtStartPar +Third, for each active UE, the base station establishes one or more +tunnels between the corresponding Mobile Core User Plane component. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=500\sphinxpxdimen]{{Slide05}.png} +\caption{Base station establishes one or more tunnels between +each UE and the Mobile Core’s User Plane.}\label{\detokenize{arch:id6}}\label{\detokenize{arch:fig-user-plane}}\end{figure} + +\sphinxAtStartPar +Fourth, the base station forwards both control and user plane packets +between the Mobile Core and the UE. These packets are tunnelled over +SCTP/IP and GTP/UDP/IP, respectively. SCTP (Stream Control Transport +Protocol) is an alternative reliable transport to TCP, tailored to carry +signaling (control) information for telephony services. GTP (a nested +acronym corresponding to (General Packet Radio Service) Tunneling +Protocol) is a 3GPP\sphinxhyphen{}specific tunneling protocol designed to run over +UDP. + +\sphinxAtStartPar +As an aside, it is noteworthy that connectivity between the RAN and the +Mobile Core is IP\sphinxhyphen{}based. This was introduced as one of the main changes +between 3G and 4G. Prior to 4G, the internals of the cellular network +were circuit\sphinxhyphen{}based, which is not surprising given its origins as a voice +network. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=500\sphinxpxdimen]{{Slide06}.png} +\caption{Base Station to Mobile Core (and Base Station to Base +Station) control plane tunneled over SCTP/IP and user plane +tunneled over GTP/UDP/IP.}\label{\detokenize{arch:id7}}\label{\detokenize{arch:fig-tunnels}}\end{figure} + +\sphinxAtStartPar +Fifth, each base station coordinates UE handovers with neighboring +base stations, using direct station\sphinxhyphen{}to\sphinxhyphen{}station links. Exactly like the +station\sphinxhyphen{}to\sphinxhyphen{}core connectivity shown in the previous figure, these links +are used to transfer both control plane (SCTP over IP) and user plane +(GTP over UDP/IP) packets. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=500\sphinxpxdimen]{{Slide07}.png} +\caption{Base Stations cooperate to implement UE hand over.}\label{\detokenize{arch:id8}}\label{\detokenize{arch:fig-handover}}\end{figure} + +\sphinxAtStartPar +Sixth, the base stations coordinate wireless multi\sphinxhyphen{}point transmission to +a UE from multiple base stations, which may or may not be part of a UE +handover from one base station to another. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=500\sphinxpxdimen]{{Slide08}.png} +\caption{Base Stations cooperate to implement multipath +transmission (link aggregation) to UEs.}\label{\detokenize{arch:id9}}\label{\detokenize{arch:fig-link-aggregation}}\end{figure} + +\sphinxAtStartPar +The main takeaway is that the base station can be viewed as a +specialized forwarder. In the Internet\sphinxhyphen{}to\sphinxhyphen{}UE direction, it fragments +outgoing IP packets into physical layer segments and schedules them +for transmission over the available radio spectrum, and in the +UE\sphinxhyphen{}to\sphinxhyphen{}Internet direction it assembles physical layer segments into IP +packets and forwards them (over a GTP/UDP/IP tunnel) to the upstream +user plane of the Mobile Core. Also, based on observations of the +wireless channel quality and per\sphinxhyphen{}subscriber policies, it decides +whether to (a) forward outgoing packets directly to the UE, (b) +indirectly forward packets to the UE via a neighboring base station, +or (c) utilize multiple paths to reach the UE. The third case has the +option of either spreading the physical payloads across multiple base +stations or across multiple carrier frequencies of a single base +station (including Wi\sphinxhyphen{}Fi). + +\sphinxAtStartPar +Note that as outlined in Chapter 2, scheduling is complex and +multi\sphinxhyphen{}faceted, even when viewed as a localized decision at a single +base station. What we now see is that there is also a global element, +whereby it’s possible to forward traffic to a different base station +(or to multiple base stations) in an effort to make efficient use of +the radio spectrum over a larger geographic area. + +\sphinxAtStartPar +In other words, the RAN as a whole (i.e., not just a single base +station) not only supports handovers (an obvious requirement for +mobility), but also \sphinxstyleemphasis{link aggregation} and \sphinxstyleemphasis{load balancing}, mechanisms +that are familiar to anyone who understands the Internet. We will +revisit how such RAN\sphinxhyphen{}wide (global) decisions can be made using SDN +techniques in a later chapter. + + +\section{3.3 Mobile Core} +\label{\detokenize{arch:mobile-core}} +\sphinxAtStartPar +The main function of the Mobile Core is to provide external packet data +network (i.e., Internet) connectivity to mobile subscribers, while +ensuring that they are authenticated and their observed service +qualities satisfy their subscription SLAs. An important aspect of the +Mobile Core is that it needs to manage all subscribers’ mobility by +keeping track of their last whereabouts at the granularity of the +serving base station. It’s the fact that the Mobile Core is keeping +track of individual subscribers—something that the Internet’s core +does not do—that creates a lot of the complexity in its architecture, +especially given that those subscribers are moving around. + +\sphinxAtStartPar +While the aggregate functionality remains largely the same as we migrate +from 4G to 5G, how that functionality is virtualized and factored into +individual components changes. The 5G Mobile Core is heavily +influenced by the cloud’s march toward a microservice\sphinxhyphen{}based (cloud +native) architecture. This shift to cloud native is deeper than it might +first appear, in part because it opens the door to customization and +specialization. Instead of supporting just voice and broadband +connectivity, the 5G Mobile Core can evolve to also support, for +example, massive IoT, which has a fundamentally different latency +requirement and usage pattern (i.e., many more devices connecting +intermittently). This stresses—if not breaks—a one\sphinxhyphen{}size\sphinxhyphen{}fits\sphinxhyphen{}all +approach to session management. + + +\subsection{4G Mobile Core} +\label{\detokenize{arch:g-mobile-core}} +\sphinxAtStartPar +The 4G Mobile Core, which 3GPP officially refers to as the \sphinxstyleemphasis{Evolved +Packet Core (EPC)}, consists of five main components, the first three of +which run in the Control Plane (CP) and the second two of which run in +the User Plane (UP). +\begin{itemize} +\item {} +\sphinxAtStartPar +MME (Mobility Management Entity): Tracks and manages the movement of +UEs throughout the RAN. This includes recording when the UE is not +active. + +\item {} +\sphinxAtStartPar +HSS (Home Subscriber Server): A database that contains all +subscriber\sphinxhyphen{}related information. + +\item {} +\sphinxAtStartPar +PCRF (Policy \& Charging Rules Function): Tracks and manages policy +rules and records billing data on subscriber traffic. + +\item {} +\sphinxAtStartPar +SGW (Serving Gateway): Forwards IP packets to and from the RAN. +Anchors the Mobile Core end of the bearer service to a (potentially +mobile) UE, and so is involved in handovers from one base station to +another. + +\item {} +\sphinxAtStartPar +PGW (Packet Gateway): Essentially an IP router, connecting the Mobile +Core to the external Internet. Supports additional access\sphinxhyphen{}related +functions, including policy enforcement, traffic shaping, and +charging. + +\end{itemize} + +\sphinxAtStartPar +Although specified as distinct components, in practice the SGW +(RAN\sphinxhyphen{}facing) and PGW (Internet\sphinxhyphen{}facing) are often combined in a single +device, commonly referred to as an S/PGW. The end result is illustrated +in \hyperref[\detokenize{arch:fig-4g-core}]{Figure \ref{\detokenize{arch:fig-4g-core}}}. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=700\sphinxpxdimen]{{Slide20}.png} +\caption{4G Mobile Core (Evolved Packet Core).}\label{\detokenize{arch:id10}}\label{\detokenize{arch:fig-4g-core}}\end{figure} + +\sphinxAtStartPar +Note that 3GPP is flexible in how the Mobile Core components are +deployed to serve a geographic area. For example, a single MME/PGW pair +might serve a metropolitan area, with SGWs deployed across \textasciitilde{}10 edge +sites spread throughout the city, each of which serves \textasciitilde{}100 base +stations. But alternative deployment configurations are allowed by the +spec. + + +\subsection{5G Mobile Core} +\label{\detokenize{arch:id1}} +\sphinxAtStartPar +The 5G Mobile Core, which 3GPP calls the \sphinxstyleemphasis{NG\sphinxhyphen{}Core}, adopts a +microservice\sphinxhyphen{}like architecture, where we say “microservice\sphinxhyphen{}like” because +while the 3GPP specification spells out this level of disaggregation, it +is really just prescribing a set of functional blocks and not an +implementation. A set of functional blocks is very +different from the collection of engineering decisions that go into +designing a microservice\sphinxhyphen{}based system. That said, viewing the collection of +components shown in \hyperref[\detokenize{arch:fig-5g-core}]{Figure \ref{\detokenize{arch:fig-5g-core}}} +as a set of microservices is a good working model. + +\sphinxAtStartPar +The following organizes the set of functional blocks into three groups. +The first group runs in the Control Plane (CP) and has a counterpart in +the EPC. +\begin{itemize} +\item {} +\sphinxAtStartPar +AMF (Core Access and Mobility Management Function): Responsible for connection +and reachability management, mobility management, access +authentication and authorization, and location services. Manages the +mobility\sphinxhyphen{}related aspects of the EPC’s MME. + +\item {} +\sphinxAtStartPar +SMF (Session Management Function): Manages each UE session, including +IP address allocation, selection of associated UP function, control +aspects of QoS, and control aspects of UP routing. Roughly +corresponds to part of the EPC’s MME and the control\sphinxhyphen{}related aspects +of the EPC’s PGW. + +\item {} +\sphinxAtStartPar +PCF (Policy Control Function): Manages the policy rules that other CP +functions then enforce. Roughly corresponds to the EPC’s PCRF. + +\item {} +\sphinxAtStartPar +UDM (Unified Data Management): Manages user identity, including the +generation of authentication credentials. Includes part of the +functionality in the EPC’s HSS. + +\item {} +\sphinxAtStartPar +AUSF (Authentication Server Function): Essentially an authentication +server. Includes part of the functionality in the EPC’s HSS. + +\end{itemize} + +\sphinxAtStartPar +The second group also runs in the Control Plane (CP) but does not have +a direct counterpart in the EPC: +\begin{itemize} +\item {} +\sphinxAtStartPar +SDSF (Structured Data Storage Network Function): A “helper” service +used to store structured data. Could be implemented by an “SQL +Database” in a microservices\sphinxhyphen{}based system. + +\item {} +\sphinxAtStartPar +UDSF (Unstructured Data Storage Network Function): A “helper” service +used to store unstructured data. Could be implemented by a “Key/Value +Store” in a microservices\sphinxhyphen{}based system. + +\item {} +\sphinxAtStartPar +NEF (Network Exposure Function): A means to expose select +capabilities to third\sphinxhyphen{}party services, including translation between +internal and external representations for data. Could be implemented +by an “API Server” in a microservices\sphinxhyphen{}based system. + +\item {} +\sphinxAtStartPar +NRF (NF Repository Function): A means to discover available services. +Could be implemented by a “Discovery Service” in a +microservices\sphinxhyphen{}based system. + +\item {} +\sphinxAtStartPar +NSSF (Network Slicing Selector Function): A means to select a Network +Slice to serve a given UE. Network slices are essentially a way to +partition network resources in order to +differentiate service given to different users. It is a key feature +of 5G that we discuss in depth in a later chapter. + +\end{itemize} + +\sphinxAtStartPar +The third group includes the one component that runs in the User Plane +(UP): +\begin{itemize} +\item {} +\sphinxAtStartPar +UPF (User Plane Function): Forwards traffic between RAN and the +Internet, corresponding to the S/PGW combination in EPC. In addition +to packet forwarding, it is responsible for policy enforcement, lawful +intercept, traffic usage reporting, and QoS policing. + +\end{itemize} + +\sphinxAtStartPar +Of these, the first and third groups are best viewed as a +straightforward refactoring of 4G’s EPC, while the second group—despite +the gratuitous introduction of new terminology—is 3GPP’s way of pointing +to a cloud native solution as the desired end\sphinxhyphen{}state for the Mobile Core. +Of particular note, introducing distinct storage services means that all +the other services can be stateless, and hence, more readily scalable. +Also note that \hyperref[\detokenize{arch:fig-5g-core}]{Figure \ref{\detokenize{arch:fig-5g-core}}} adopts an idea that’s +common in microservice\sphinxhyphen{}based systems, namely, to show a \sphinxstyleemphasis{message bus} +interconnecting all the components rather than including a full set of +pairwise connections. This also suggests a well\sphinxhyphen{}understood +implementation strategy. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=700\sphinxpxdimen]{{Slide33}.png} +\caption{5G Mobile Core (NG\sphinxhyphen{}Core).}\label{\detokenize{arch:id11}}\label{\detokenize{arch:fig-5g-core}}\end{figure} + +\sphinxAtStartPar +Stepping back from these details, and with the caveat that we are +presuming an implementation, the main takeaway is that we can +conceptualize the Mobile Core as a graph of services. You will +sometimes hear this called a \sphinxstyleemphasis{Service Graph} or \sphinxstyleemphasis{Service Chain}, the latter being more prevalent +in NFV\sphinxhyphen{}oriented documents. Another term, \sphinxstyleemphasis{Service Mesh}, has taken on +a rather specific meaning in cloud native terminology—we’ll avoid +overloading that term here. 3GPP is silent on the specific terminology +since it is considered an implementation choice rather than part of the +specification. We describe our implementation choices in later chapters. + + +\section{3.4 Security and Mobility} +\label{\detokenize{arch:security-and-mobility}} +\sphinxAtStartPar +We now take a closer look at two unique features of the cellular +network—its support for security and mobility—both of which +differentiate it from WiFi. The following also serves to fill in some +details about how each individual UE connects to the network. + +\sphinxAtStartPar +We start with the security architecture, which is grounded in two +trust assumptions. First, each Base Station trusts that it is +connected to the Mobile Core by a secure private network, over which +it establishes the tunnels introduced in \hyperref[\detokenize{arch:fig-tunnels}]{Figure \ref{\detokenize{arch:fig-tunnels}}}: a GTP/UDP/IP tunnel to the Core’s User Plane (Core\sphinxhyphen{}UP) +and a SCTP/IP tunnel to the Core’s Control Plane (Core\sphinxhyphen{}CP). Second, +each UE has an operator\sphinxhyphen{}provided SIM card, which uniquely identifies +the subscriber (i.e., phone number) and establishes the radio +parameters (e.g., frequency band) needed to communicate with that +operator’s Base Stations. The SIM card also includes a secret key that +the UE uses to authenticate itself. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide34}.png} +\caption{Sequence of steps to establish secure Control and User Plane +channels.}\label{\detokenize{arch:id12}}\label{\detokenize{arch:fig-secure}}\end{figure} + +\sphinxAtStartPar +With this starting point, \hyperref[\detokenize{arch:fig-secure}]{Figure \ref{\detokenize{arch:fig-secure}}} shows the +per\sphinxhyphen{}UE connection sequence. When a UE first becomes active, it +communicates with a nearby Base Station over a temporary +(unauthenticated) radio link (Step 1). The Base Station forwards the +request to the Core\sphinxhyphen{}CP over the existing tunnel, and the Core\sphinxhyphen{}CP +(specifically, the MME in 4G and the AMF in 5G) initiates an +authentication protocol with the UE (Step 2). 3GPP identifies a set of +options for authentication and encryption, where the actual protocols +used are an implementation choice. For example, \sphinxstyleemphasis{Advanced Encryption +Standard} (AES) is one of the options for encryption. Note that this +authentication exchange is initially in the clear since the Base +Station to UE link is not yet secure. + +\sphinxAtStartPar +Once the UE and Core\sphinxhyphen{}CP are satisfied with each other’s identity, the +Core\sphinxhyphen{}CP informs the other components of the parameters they will need +to service the UE (Step 3). This includes: (a) instructing the Core\sphinxhyphen{}UP +to initialize the user plane (e.g., assign an IP address to the UE and +set the appropriate QCI parameter); (b) instructing the Base Station +to establish an encrypted channel to the UE; and (c) giving the UE the +symmetric key it will need to use the encrypted channel with the Base +Station. The symmetric key is encrypted using the public key of the +UE (so only the UE can decrypt it, using its secret key). Once +complete, the UE can use the end\sphinxhyphen{}to\sphinxhyphen{}end user plane channel through the +Core\sphinxhyphen{}UP (Step 4). + +\sphinxAtStartPar +There are three additional details of note about this process. First, +the secure control channel between the UE and the Core\sphinxhyphen{}CP set up +during Step 2 remains available, and is used by the Core\sphinxhyphen{}CP to send +additional control instructions to the UE during the course of the +session. + +\sphinxAtStartPar +Second, the user plane channel established during Step 4 is referred +to as the \sphinxstyleemphasis{Default Bearer Service}, but additional channels can be +established between the UE and Core\sphinxhyphen{}UP, each with a potentially +different QCI value. This might be done on an +application\sphinxhyphen{}by\sphinxhyphen{}application basis, for example, under the control of +the Mobile Core doing \sphinxstyleemphasis{Deep Packet Inspection} (DPI) on the traffic, +looking for flows that require special treatment. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide35}.png} +\caption{Sequence of per\sphinxhyphen{}hop tunnels involved in an end\sphinxhyphen{}to\sphinxhyphen{}end User Plane +channel.}\label{\detokenize{arch:id13}}\label{\detokenize{arch:fig-per-hop}}\end{figure} + +\sphinxAtStartPar +Third, while the resulting user plane channels are logically +end\sphinxhyphen{}to\sphinxhyphen{}end, each is actually implemented as a sequence of per\sphinxhyphen{}hop +tunnels, as illustrated in \hyperref[\detokenize{arch:fig-per-hop}]{Figure \ref{\detokenize{arch:fig-per-hop}}}. (The +figure shows the SGW and PGW from the 4G Mobile Core to make the +example more concrete.) This means each component on the end\sphinxhyphen{}to\sphinxhyphen{}end +path terminates a downstream tunnel using one local identifier for a +given UE, and initiates an upstream tunnel using a second local +identifier for that UE. In practice, these per\sphinxhyphen{}flow tunnels are often +bundled into an single inter\sphinxhyphen{}component tunnel, which makes it +impossible to differentiate the level of service given to any +particular end\sphinxhyphen{}to\sphinxhyphen{}end UE channel. This is a limitation of 4G that 5G +has ambitions to correct. + +\sphinxAtStartPar +Support for mobility can now be understood as the process of +re\sphinxhyphen{}executing one or more of the steps shown in \hyperref[\detokenize{arch:fig-secure}]{Figure \ref{\detokenize{arch:fig-secure}}} as the UE moves throughout the RAN. The unauthenticated +link indicated by (1) allows the UE to be known to all Base Station +within range. (We refer to these as \sphinxstyleemphasis{potential links} in later +chapters.) Based on the signal’s measured CQI, the Base Stations +communicate directly with each other to make a handover decision. Once +made, the decision is then communicated to the Mobile Core, +re\sphinxhyphen{}triggering the setup functions indicated by (3), which in turn +re\sphinxhyphen{}builds the user plane tunnel between the Base Station and the SGW +shown in \hyperref[\detokenize{arch:fig-per-hop}]{Figure \ref{\detokenize{arch:fig-per-hop}}} (or correspondingly, +between the Base Station and the UPF in 5G). One of the most unique +features of the cellular network is that the Mobile Core’s user plane +(e.g., UPF in 5G) buffers data during the handover transition, +avoiding dropped packets and subsequent end\sphinxhyphen{}to\sphinxhyphen{}end retransmissions. + +\sphinxAtStartPar +In other words, the cellular network maintains the \sphinxstyleemphasis{UE session} in the +face of mobility (corresponding to the control and data channels +depicted by (2) and (4) in \hyperref[\detokenize{arch:fig-secure}]{Figure \ref{\detokenize{arch:fig-secure}}}, +respectively), but it is able to do so only when the same Mobile Core +serves the UE (i.e., only the Base Station changes). This would +typically be the case for a UE moving within a metropolitan area. +Moving between metro areas—and hence, between Mobile Cores—is +indistinguishable from power cycling a UE. The UE is assigned a new IP +address and no attempt is made to buffer and subsequently deliver +in\sphinxhyphen{}flight data. Independent of mobility, but relevant to this +discussion, any UE that becomes inactive for a period of time also +loses its session, with a new session established and a new IP address +assigned when the UE becomes active again. + +\sphinxAtStartPar +Note that this session\sphinxhyphen{}based approach can be traced to the cellular +network’s roots as a connection\sphinxhyphen{}oriented network. An interesting +thought experiment is whether the Mobile Core will continue to evolve +so as to better match the connectionless assumptions of the Internet +protocols that typically run on top of it. + + +\section{3.5 Deployment Options} +\label{\detokenize{arch:deployment-options}} +\sphinxAtStartPar +With an already deployed 4G RAN/EPC in the field and a new 5G +RAN/NG\sphinxhyphen{}Core deployment underway, we can’t ignore the issue of +transitioning from 4G to 5G (an issue the IP\sphinxhyphen{}world has been grappling +with for 20 years). 3GPP officially spells out multiple deployment +options, which can be summarized as follows. +\begin{itemize} +\item {} +\sphinxAtStartPar +Standalone 4G / Stand\sphinxhyphen{}Alone 5G + +\item {} +\sphinxAtStartPar +Non\sphinxhyphen{}Standalone (4G+5G RAN) over 4G’s EPC + +\item {} +\sphinxAtStartPar +Non\sphinxhyphen{}Standalone (4G+5G RAN) over 5G’s NG\sphinxhyphen{}Core + +\end{itemize} + +\sphinxAtStartPar +The second of the three options, which is generally referred to as +“NSA“, involves 5G base stations being deployed alongside the +existing 4G base stations in a given geography to provide a data\sphinxhyphen{}rate +and capacity boost. In NSA, control plane traffic between the user +equipment and the 4G Mobile Core utilizes (i.e., is forwarded through) +4G base stations, and the 5G base stations are used only to carry user +traffic. Eventually, it is expected that operators complete their +migration to 5G by deploying NG Core and connecting their 5G base +stations to it for Standalone (SA) operation. NSA and SA operations +are illustrated in \hyperref[\detokenize{arch:fig-nsa}]{Figure \ref{\detokenize{arch:fig-nsa}}}. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide38}.png} +\caption{NSA and SA options for 5G deployment.}\label{\detokenize{arch:id14}}\label{\detokenize{arch:fig-nsa}}\end{figure} + +\sphinxAtStartPar +One reason we call attention to the phasing issue is that we face a +similar challenge in the chapters that follow. The closer the following +discussion gets to implementation details, the more specific we have to +be about whether we are using 4G components or 5G components. As a +general rule, we use 4G components—particularly with respect to the +Mobile Core, since that’s what’s available in open source today—and trust +the reader can make the appropriate substitution without loss of +generality. Like the broader industry, the open source community is in +the process of incrementally evolving its 4G code base into its +5G\sphinxhyphen{}compliant counterpart. + +\phantomsection\label{\detokenize{arch:reading-migration}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +For more insight into 4G to 5G migration strategies, see +\sphinxhref{https://www.gsma.com/futurenetworks/wp-content/uploads/2018/04/Road-to-5G-Introduction-and-Migration\_FINAL.pdf}{Road to 5G: Introduction and Migration}. +GSMA Report, April 2018. +\end{sphinxadmonition} + + +\chapter{Chapter 4: RAN Internals} +\label{\detokenize{ran:chapter-4-ran-internals}}\label{\detokenize{ran::doc}} +\sphinxAtStartPar +The description of the RAN in the previous chapter focused on +functionality, but was mostly silent about the RAN’s internal +structure. We now focus on some of the internal details, and in +doing so, explain how the RAN is being transformed in 5G. This +involves first describing the stages in the packet processing +pipeline, and then showing how these stages can be disaggregated, +distributed and implemented. + +\sphinxAtStartPar +Our approach in this chapter is to incrementally build the RAN from +the bottom up in the first three sections. Section 4.4 then summarizes +the overall design, with a focus on how the resulting end\sphinxhyphen{}to\sphinxhyphen{}end +system is architected to evolve. + + +\section{4.1 Packet Processing Pipeline} +\label{\detokenize{ran:packet-processing-pipeline}} +\sphinxAtStartPar +\hyperref[\detokenize{ran:fig-pipeline}]{Figure \ref{\detokenize{ran:fig-pipeline}}} shows the packet processing stages +implemented by the base station. These stages are specified by the 3GPP +standard. Note that the figure depicts the base station as a pipeline +(running left\sphinxhyphen{}to\sphinxhyphen{}right for packets sent to the UE) but it is equally valid to view it as a protocol +stack (as is typically done in official 3GPP documents). Also note that +(for now) we are agnostic as to how these stages are implemented, but +since we are ultimately heading towards a cloud\sphinxhyphen{}based implementation, +you can think of each as corresponding to a microservice (if that is +helpful). + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide14}.png} +\caption{RAN processing pipeline, including both user and +control plane components.}\label{\detokenize{ran:id1}}\label{\detokenize{ran:fig-pipeline}}\end{figure} + +\sphinxAtStartPar +The key stages are as follows. +\begin{itemize} +\item {} +\sphinxAtStartPar +RRC (Radio Resource Control) \(\rightarrow\) Responsible for configuring the +coarse\sphinxhyphen{}grain and policy\sphinxhyphen{}related aspects of the pipeline. The RRC runs +in the RAN’s control plane; it does not process packets on the user +plane. + +\item {} +\sphinxAtStartPar +PDCP (Packet Data Convergence Protocol) \(\rightarrow\) Responsible for compressing +and decompressing IP headers, ciphering and integrity protection, and +making an “early” forwarding decision (i.e., whether to send the +packet down the pipeline to the UE or forward it to another base +station). + +\item {} +\sphinxAtStartPar +RLC (Radio Link Control) \(\rightarrow\) Responsible for segmentation and +reassembly, including reliably transmitting/receiving segments by +implementing a form of ARQ (automatic repeat request). + +\item {} +\sphinxAtStartPar +MAC (Media Access Control) \(\rightarrow\) Responsible for buffering, multiplexing +and demultiplexing segments, including all real\sphinxhyphen{}time scheduling +decisions about what segments are transmitted when. Also able to make +a “late” forwarding decision (i.e., to alternative carrier +frequencies, including Wi\sphinxhyphen{}Fi). + +\item {} +\sphinxAtStartPar +PHY (Physical Layer) \(\rightarrow\) Responsible for coding and modulation (as +discussed in an earlier chapter), including FEC. + +\end{itemize} + +\sphinxAtStartPar +The last two stages in \hyperref[\detokenize{ran:fig-pipeline}]{Figure \ref{\detokenize{ran:fig-pipeline}}} (D/A +conversion and the RF front\sphinxhyphen{}end) are beyond the scope of this book. + +\sphinxAtStartPar +While it is simplest to view the stages in \hyperref[\detokenize{ran:fig-pipeline}]{Figure \ref{\detokenize{ran:fig-pipeline}}} +as a pure left\sphinxhyphen{}to\sphinxhyphen{}right pipeline, in practice the Scheduler running in the +MAC stage implements the “main loop” for outbound traffic, reading data +from the upstream RLC and scheduling transmissions to the downstream +PHY. In particular, since the Scheduler determines the number of bytes +to transmit to a given UE during each time period (based on all the +factors outlined in an earlier chapter), it must request (get) a segment +of that length from the upstream queue. In practice, the size of the +segment that can be transmitted on behalf of a single UE during a single +scheduling interval can range from a few bytes to an entire IP packet. + + +\section{4.2 Split RAN} +\label{\detokenize{ran:split-ran}} +\sphinxAtStartPar +The next step is to understand how the functionality outlined above is +partitioned between physical elements, and hence, “split” across +centralized and distributed locations. The dominant option has +historically been “no split,” with the entire pipeline shown in +\hyperref[\detokenize{ran:fig-pipeline}]{Figure \ref{\detokenize{ran:fig-pipeline}}} running in the base station. Going +forward, the 3GPP standard has been extended to allow for multiple +split\sphinxhyphen{}points, with the partition shown in \hyperref[\detokenize{ran:fig-split-ran}]{Figure \ref{\detokenize{ran:fig-split-ran}}} being actively pursued by the operator\sphinxhyphen{}led O\sphinxhyphen{}RAN +(Open RAN) Alliance. It is the split we adopt throughout the rest of +this book. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide15}.png} +\caption{Split\sphinxhyphen{}RAN processing pipeline distributed across a +Central Unit (CU), Distributed Unit (DU), and Radio Unit (RU).}\label{\detokenize{ran:id2}}\label{\detokenize{ran:fig-split-ran}}\end{figure} + +\sphinxAtStartPar +This results in a RAN\sphinxhyphen{}wide configuration similar to that shown in +\hyperref[\detokenize{ran:fig-ran-hierarchy}]{Figure \ref{\detokenize{ran:fig-ran-hierarchy}}}, where a single \sphinxstyleemphasis{Central Unit (CU)} +running in the cloud serves multiple \sphinxstyleemphasis{Distributed Units (DUs)}, each of +which in turn serves multiple \sphinxstyleemphasis{Radio Units (RUs)}. Critically, the RRC +(centralized in the CU) is responsible for only near\sphinxhyphen{}real\sphinxhyphen{}time +configuration and control decision making, while the Scheduler that is +part of the MAC stage is responsible for all real\sphinxhyphen{}time scheduling +decisions. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=400\sphinxpxdimen]{{Slide16}.png} +\caption{Split\sphinxhyphen{}RAN hierarchy, with one CU serving multiple DUs, +each of which serves multiple RUs.}\label{\detokenize{ran:id3}}\label{\detokenize{ran:fig-ran-hierarchy}}\end{figure} + +\sphinxAtStartPar +Because scheduling decisions for radio transmission are made by the +MAC layer in real +time, a DU needs to be “near” (within 1ms) the RUs it manages. (You +can’t afford to make scheduling decisions based on out\sphinxhyphen{}of\sphinxhyphen{}date channel +information.) One familiar configuration is +to co\sphinxhyphen{}locate a DU and an RU in a cell tower. But when an RU corresponds +to a small cell, many of which might be spread across a modestly\sphinxhyphen{}sized +geographic area (e.g., a mall, campus, or factory), then a single DU +would likely service multiple RUs. The use of mmWave in 5G is likely to +make this later configuration all the more common. + +\sphinxAtStartPar +Also note that the split\sphinxhyphen{}RAN changes the nature of the Backhaul Network, +which in 4G connected the base stations (eNBs) back to the Mobile Core. +With the split\sphinxhyphen{}RAN there are multiple connections, which are officially +labeled as follows. +\begin{itemize} +\item {} +\sphinxAtStartPar +RU\sphinxhyphen{}DU connectivity is called the Fronthaul + +\item {} +\sphinxAtStartPar +DU\sphinxhyphen{}CU connectivity is called the Midhaul + +\item {} +\sphinxAtStartPar +CU\sphinxhyphen{}Mobile Core connectivity is called the Backhaul + +\end{itemize} + +\sphinxAtStartPar +One observation about the CU (which is relevant in the next chapter) +is that one might co\sphinxhyphen{}locate the CU and Mobile Core in the same +cluster, meaning the backhaul is implemented in the cluster switching +fabric. In such a configuration, the midhaul then effectively serves +the same purpose as the original backhaul, and the fronthaul is +constrained by the predictable/low\sphinxhyphen{}latency requirements of the MAC +stage’s real\sphinxhyphen{}time scheduler. + +\sphinxAtStartPar +A second observation about the CU shown in \hyperref[\detokenize{ran:fig-split-ran}]{Figure \ref{\detokenize{ran:fig-split-ran}}} is that it encompasses two functional blocks—the RRC +and the PDCP—which lie on the RAN’s control plane and user plane, +respectively. This separation is consistent with the idea of CUPS +introduced in Chapter 3, and plays an increasingly important role as +we dig deeper into how the RAN is implemented. For now, we note that +the two parts are typically referred to as the CU\sphinxhyphen{}C and CU\sphinxhyphen{}U, +respectively. + +\phantomsection\label{\detokenize{ran:reading-backhaul}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +For more insight into design considerations for +interconnecting the distributed components of a Split RAN, see +\sphinxhref{https://www.ngmn.org/wp-content/uploads/NGMN\_RANEV\_D4\_BH\_FH\_Evolution\_V1.01.pdf}{RAN Evolution Project: Backhaul and Fronthaul Evolution}. +NGMN Alliance Report, March 2015. +\end{sphinxadmonition} + + +\section{4.3 Software\sphinxhyphen{}Defined RAN} +\label{\detokenize{ran:software-defined-ran}} +\sphinxAtStartPar +We now describe how the RAN is implemented according to SDN +principles, resulting in an SD\sphinxhyphen{}RAN. The key architectural insight is +shown in \hyperref[\detokenize{ran:fig-rrc-split}]{Figure \ref{\detokenize{ran:fig-rrc-split}}}, where the RRC from +\hyperref[\detokenize{ran:fig-pipeline}]{Figure \ref{\detokenize{ran:fig-pipeline}}} is partitioned into two +sub\sphinxhyphen{}components: the one on the left provides a 3GPP\sphinxhyphen{}compliant way for +the RAN to interface to the Mobile Core’s control plane, while the one +on the right opens a new programmatic API for exerting software\sphinxhyphen{}based +control over the pipeline that implements the RAN user plane. + +\sphinxAtStartPar +To be more specific, the left sub\sphinxhyphen{}component simply forwards control +packets between the Mobile Core and the PDCP, providing a path over +which the Mobile Core can communicate with the UE for control +purposes, whereas the right sub\sphinxhyphen{}component implements the core of the +RRC’s control functionality. This component is commonly referred to as +the \sphinxstyleemphasis{RAN Intelligent Controller (RIC)} in O\sphinxhyphen{}RAN architecture +documents, so we adopt this terminology. The “Near\sphinxhyphen{}Real Time” +qualifier indicates the RIC is part of 10\sphinxhyphen{}100ms control loop implemented +in the CU, as opposed to the \textasciitilde{}1ms control loop required by the MAC +scheduler running in the DU. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide18}.png} +\caption{RRC disaggregated into a Mobile Core facing control +plane component and a Near\sphinxhyphen{}Real\sphinxhyphen{}Time Controller.}\label{\detokenize{ran:id4}}\label{\detokenize{ran:fig-rrc-split}}\end{figure} + +\sphinxAtStartPar +Although not shown in \hyperref[\detokenize{ran:fig-rrc-split}]{Figure \ref{\detokenize{ran:fig-rrc-split}}}, keep in mind +(from \hyperref[\detokenize{ran:fig-split-ran}]{Figure \ref{\detokenize{ran:fig-split-ran}}}) that all constituent parts of +the RRC, plus the PDCP, form the CU. + +\sphinxAtStartPar +Completing the picture, \hyperref[\detokenize{ran:fig-ran-controller}]{Figure \ref{\detokenize{ran:fig-ran-controller}}} shows +the Near\sphinxhyphen{}RT RIC implemented as an SDN Controller hosting a +set of SDN control apps. The RIC maintains a \sphinxstyleemphasis{RAN Network Information +Base (R\sphinxhyphen{}NIB)}\textendash{}a common set of information that can be consumed by numerous +control apps. The R\sphinxhyphen{}NIB includes time\sphinxhyphen{}averaged CQI values and other +per\sphinxhyphen{}session state (e.g., GTP tunnel IDs, QCI values for the type of +traffic), while the MAC (as part of the DU) maintains the +instantaneous CQI values required by the real\sphinxhyphen{}time +scheduler. Specifically, the R\sphinxhyphen{}NIB includes the following state. +\begin{itemize} +\item {} +\sphinxAtStartPar +NODES: Base Stations and Mobile Devices +\begin{itemize} +\item {} +\sphinxAtStartPar +Base Station Attributes: +\begin{itemize} +\item {} +\sphinxAtStartPar +Identifiers + +\item {} +\sphinxAtStartPar +Version + +\item {} +\sphinxAtStartPar +Config Report + +\item {} +\sphinxAtStartPar +RRM config + +\item {} +\sphinxAtStartPar +PHY resource usage + +\end{itemize} + +\item {} +\sphinxAtStartPar +Mobile Device Attributes: +\begin{itemize} +\item {} +\sphinxAtStartPar +Identifiers + +\item {} +\sphinxAtStartPar +Capability + +\item {} +\sphinxAtStartPar +Measurement Config + +\item {} +\sphinxAtStartPar +State (Active/Idle) + +\end{itemize} + +\end{itemize} + +\item {} +\sphinxAtStartPar +LINKS: \sphinxstyleemphasis{Actual} between two nodes and \sphinxstyleemphasis{Potential} between UEs and all +neighbor cells +\begin{itemize} +\item {} +\sphinxAtStartPar +Link Attributes: +\begin{itemize} +\item {} +\sphinxAtStartPar +Identifiers + +\item {} +\sphinxAtStartPar +Link Type + +\item {} +\sphinxAtStartPar +Config/Bearer Parameters + +\item {} +\sphinxAtStartPar +QCI Value + +\end{itemize} + +\end{itemize} + +\item {} +\sphinxAtStartPar +SLICES: Virtualized RAN Construct +\begin{itemize} +\item {} +\sphinxAtStartPar +Slice Attributes: +\begin{itemize} +\item {} +\sphinxAtStartPar +Links + +\item {} +\sphinxAtStartPar +Bearers/Flows + +\item {} +\sphinxAtStartPar +Validity Period + +\item {} +\sphinxAtStartPar +Desired KPIs + +\item {} +\sphinxAtStartPar +MAC RRM Configuration + +\item {} +\sphinxAtStartPar +RRM Control Configuration + +\end{itemize} + +\end{itemize} + +\end{itemize} + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=500\sphinxpxdimen]{{Slide19}.png} +\caption{Example set of control applications running on top of +Near\sphinxhyphen{}Real\sphinxhyphen{}Time RAN Controller.}\label{\detokenize{ran:id5}}\label{\detokenize{ran:fig-ran-controller}}\end{figure} + +\sphinxAtStartPar +The example Control Apps in \hyperref[\detokenize{ran:fig-ran-controller}]{Figure \ref{\detokenize{ran:fig-ran-controller}}} +include a range of possibilities, but is not intended to be an +exhaustive list. The right\sphinxhyphen{}most example, RAN Slicing, is the most +ambitious in that it introduces a new capability: Virtualizing the +RAN. It is also an idea that has been implemented, which we describe +in more detail in the next chapter. + +\sphinxAtStartPar +The next three (RF Configuration, Semi\sphinxhyphen{}Persistent Scheduling, Cipher Key +Assignment) are examples of configuration\sphinxhyphen{}oriented applications. They +provide a programmatic way to manage seldom\sphinxhyphen{}changing configuration +state, thereby enabling zero\sphinxhyphen{}touch operations. Coming up with meaningful +policies (perhaps driven by analytics) is likely to be an avenue for +innovation in the future. + +\sphinxAtStartPar +The left\sphinxhyphen{}most four example Control Applications are the sweet spot for +SDN, with its emphasis on central control over distributed +forwarding. These functions—Link Aggregation Control, Interference +Management, Load Balancing, and Handover Control—are currently +implemented by individual base stations with only local visibility, +but they have global consequences. The SDN approach is to collect the +available input data centrally, make a globally optimal decision, and +then push the respective control parameters back to the base stations +for execution. Realizing this value in the RAN is still a +work\sphinxhyphen{}in\sphinxhyphen{}progress, but products that take this approach are +emerging. Evidence using an analogous approach to optimize +wide\sphinxhyphen{}area networks over many years is compelling. + +\sphinxAtStartPar +While the above loosely categorizes the space of potential control +apps as either config\sphinxhyphen{}oriented or control\sphinxhyphen{}oriented, another possible +characterization is based on the current practice of controlling the +mobile link at two different levels. At a fine\sphinxhyphen{}grain level, per\sphinxhyphen{}node +and per\sphinxhyphen{}link control is conducted using Radio Resource Management +(RRM) functions that are distributed across the individual base +stations. RRM functions include scheduling, handover control, link +and carrier aggregation control, bearer control, and access control. +At a coarse\sphinxhyphen{}grain level, regional mobile network optimization and +configuration is conducted using \sphinxstyleemphasis{Self\sphinxhyphen{}Organizing Network (SON)} +functions. These functions oversee neighbor lists, manage load +balancing, optimize coverage and capacity, aim for network\sphinxhyphen{}wide +interference mitigation, centrally configure parameters, and so on. As +a consequence of these two levels of control, it is not uncommon to +see reference to \sphinxstyleemphasis{RRM Applications} and \sphinxstyleemphasis{SON Applications}, +respectively, in O\sphinxhyphen{}RAN documents for SD\sphinxhyphen{}RAN. + +\phantomsection\label{\detokenize{ran:reading-b4}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +For an example of how SDN principles have been successfully applied +to a production network, we recommend \sphinxhref{https://cseweb.ucsd.edu/~vahdat/papers/b4-sigcomm13.pdf}{B4: Experience with a +Globally\sphinxhyphen{}Deployed Software Defined WAN}. ACM +SIGCOMM, August 2013. +\end{sphinxadmonition} + + +\section{4.4 Architect to Evolve} +\label{\detokenize{ran:architect-to-evolve}} +\sphinxAtStartPar +We conclude this description of RAN internals by re\sphinxhyphen{}visiting the +sequence of steps involved in disaggregation, which as the previous +three sections reveal, is being pursued in multiple tiers. In doing +so, we tie up several loose ends, including the new interfaces +disaggregation exposes. These interfaces define the pivot points +around which 5G RAN is architected to evolve. + +\sphinxAtStartPar +In the first tier of disaggregation, 3GPP standards provide multiple +options of how horizontal RAN splits can take place. Horizontal +disaggregation basically splits the RAN pipeline shown in +\hyperref[\detokenize{ran:fig-pipeline}]{Figure \ref{\detokenize{ran:fig-pipeline}}} into independently operating +components. \hyperref[\detokenize{ran:fig-disagg}]{Figure \ref{\detokenize{ran:fig-disagg}} (a)} illustrates +horizontal disaggregation of the RAN from a single base station into +three distinct components: CU, DU and RU. The O\sphinxhyphen{}RAN Alliance has +selected specific disaggregation options from 3GPP and is developing +open interfaces between these components. 3GPP defines the \sphinxstylestrong{N2} and +\sphinxstylestrong{N3} interfaces between the RAN and the Mobile Core. + +\sphinxAtStartPar +The second tier of disaggregation is vertical, focusing on +control/user plane separation (CUPS) of the CU, and resulting in CU\sphinxhyphen{}U +and CU\sphinxhyphen{}C shown in \hyperref[\detokenize{ran:fig-disagg}]{Figure \ref{\detokenize{ran:fig-disagg}} (b)}. The control +plane in question is the 3GPP control plane, where the CU\sphinxhyphen{}U realizes a +pipeline for user traffic and the CU\sphinxhyphen{}C focuses on control message +signaling between Mobile Core and the disaggregated RAN components (as +well as to the UE). The O\sphinxhyphen{}RAN specified interfaces between these +disaggregated components are also shown in \hyperref[\detokenize{ran:fig-disagg}]{Figure \ref{\detokenize{ran:fig-disagg}} (b)}. + +\sphinxAtStartPar +The third tier follows the SDN paradigm by carrying vertical +disaggregation one step further. It does this by separating most of +RAN control (RRM functions) from the disaggregated RAN components, and +logically centralizing them as applications running on an SDN +Controller, which corresponds to the Near\sphinxhyphen{}RT RIC shown previously in +\hyperref[\detokenize{ran:fig-rrc-split}]{Figures \ref{\detokenize{ran:fig-rrc-split}}} and \hyperref[\detokenize{ran:fig-ran-controller}]{\ref{\detokenize{ran:fig-ran-controller}}}. This SDN\sphinxhyphen{}based vertical disaggregation is +repeated here in \hyperref[\detokenize{ran:fig-disagg}]{Figure \ref{\detokenize{ran:fig-disagg}} (c)}. The figure +also shows the additional O\sphinxhyphen{}RAN prescribed interfaces. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=450\sphinxpxdimen]{{Slide39}.png} +\caption{Three tiers of RAN disaggregation: (a) horizontal, (b) vertical +CUPS, and (c) vertical SDN.}\label{\detokenize{ran:id6}}\label{\detokenize{ran:fig-disagg}}\end{figure} + +\sphinxAtStartPar +The interface names are cryptic, and knowing their details adds little +to our conceptual understanding of the RAN, except perhaps to +re\sphinxhyphen{}enforce how challenging it is to introduce a transformative +technology like Software\sphinxhyphen{}Defined Networking into an operational +environment that is striving to achieve full backward compatibility +and universal interoperability. That said, we call out two notable +examples. + +\sphinxAtStartPar +The first is the \sphinxstylestrong{A1} interface that the mobile operator’s +management plane—typically called the \sphinxstyleemphasis{OSS/BSS (Operations Support +System / Business Support System)} in the Telco world—uses to +configure the RAN. We have not discussed the Telco OSS/BSS up to this +point, but it safe to assume such a component sits at the top of any +Telco software stack. It is the source of all configuration settings +and business logic needed to operate a network. Notice that the +Management Plane shown in \hyperref[\detokenize{ran:fig-disagg}]{Figure \ref{\detokenize{ran:fig-disagg}} (c)} +includes a \sphinxstyleemphasis{Non\sphinxhyphen{}Real\sphinxhyphen{}Time RIC} functional block, complementing the +Near\sphinxhyphen{}RT RIC that sits below the A1 interface. We return to the +relevance of these two RICs in a moment. + +\sphinxAtStartPar +The second is the \sphinxstylestrong{E2} interface that the Near\sphinxhyphen{}RT RIC uses to +control the underlying RAN elements. A requirement of the E2 interface +is that it be able to connect the Near\sphinxhyphen{}RT RIC to different types of +RAN elements. This range is reflected in the API, which revolves +around a \sphinxstyleemphasis{Service Model} abstraction. The idea is that each RAN +element advertises a Service Model, which effectively defines the set +of RAN Functions the element is able to support. The RIC then issues a +combination of the following four operations against this Service +Model. +\begin{itemize} +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Report:} RIC asks the element to report a function\sphinxhyphen{}specific value setting. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Insert:} RIC instructs the element to activate a user plane function. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Control:} RIC instructs the element to activate a control plane function. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Policy:} RIC sets a policy parameter on one of the activated functions. + +\end{itemize} + +\sphinxAtStartPar +Of course, it is the RAN element, through its published Service Model, +that defines the relevant set of functions that can be activated, the +variables that can be reported, and policies that can be set. + +\sphinxAtStartPar +Taken together, the A1 and E2 interfaces complete two of the three +major control loops of the RAN: the outer (non\sphinxhyphen{}real\sphinxhyphen{}time) loop has the +Non\sphinxhyphen{}RT RIC as its control point and the middle (near\sphinxhyphen{}real\sphinxhyphen{}time) loop has +the Near\sphinxhyphen{}RT RIC as its control point. The third (inner) control loop, +which is not shown in \hyperref[\detokenize{ran:fig-disagg}]{Figure \ref{\detokenize{ran:fig-disagg}}}, runs inside +the DU: It includes the real\sphinxhyphen{}time Scheduler embedded in the MAC stage +of the RAN pipeline. The two outer control loops have rough time +bounds of \textgreater{}\textgreater{}1sec and \textgreater{}10ms, respectively, and as we saw in Chapter 2, +the real\sphinxhyphen{}time control loop is assumed to be \textless{}1ms. + +\sphinxAtStartPar +This raises the question of how specific functionality is distributed +between the Non\sphinxhyphen{}RT RIC, Near\sphinxhyphen{}RT RIC, and DU. Starting with the second +pair (i.e., the two inner loops), it is important to recognize that +not all RRM functions can be centralized. After horizontal and +vertical CUPS disaggregation, the RRM functions are split between CU\sphinxhyphen{}C +and DU. For this reason, the SDN\sphinxhyphen{}based vertical disaggregation focuses +on centralizing CU\sphinxhyphen{}C\sphinxhyphen{}side RRM functions in the Near\sphinxhyphen{}RT RIC. In +addition to RRM control, this includes all the SON applications. + +\sphinxAtStartPar +Turning to the outer two control loops, the Near RT\sphinxhyphen{}RIC opens the +possibility of introducing policy\sphinxhyphen{}based RAN control, whereby +interrupts (exceptions) to operator\sphinxhyphen{}defined policies would signal the +need for the outer loop to become involved. For example, one can +imagine developing learning\sphinxhyphen{}based controls, where the inference +engines for these controls would run as applications on the Near +RT\sphinxhyphen{}RIC, and their non\sphinxhyphen{}real\sphinxhyphen{}time learning counterparts would run +elsewhere. The Non\sphinxhyphen{}RT RIC would then interact with the Near\sphinxhyphen{}RT RIC to +deliver relevant operator policies from the Management Plane to the +Near RT\sphinxhyphen{}RIC over the A1 interface. + +\sphinxAtStartPar +Finally, you may be wondering why there is an O\sphinxhyphen{}RAN Alliance in the +first place, given that 3GPP is already the standardization body +responsible for interoperability across the global cellular network. +The answer is that over time 3GPP has become a vendor\sphinxhyphen{}dominated +organization, whereas O\sphinxhyphen{}RAN was created more recently by network +operators. (AT\&T and China Mobile were the founding members.) O\sphinxhyphen{}RAN’s +goal is to catalyze a software\sphinxhyphen{}based implementation that breaks the +vendor lock\sphinxhyphen{}in that dominates today’s marketplace. The E2 interface +in particular, which is architected around the idea of supporting +different Service Models, is central to this strategy. Whether the +operators will be successful in their ultimate goal is yet to be seen. + + +\chapter{Chapter 5: Advanced Capabilities} +\label{\detokenize{disaggregate:chapter-5-advanced-capabilities}}\label{\detokenize{disaggregate::doc}} +\sphinxAtStartPar +Disaggregating the cellular network pays dividends. This chapter +explores three examples. Stepping back to look at the big picture, +Chapter 3 (Architecture) described “what is” (the basics of 3GPP) and +Chapter 4 (RAN Internals) described “what will be” (where the industry +is clearly headed), whereas this chapter describes “what might be” +(our best judgement on cutting\sphinxhyphen{}edge capabilities that will eventually +be realized). + + +\section{5.1 Optimized Data Plane} +\label{\detokenize{disaggregate:optimized-data-plane}} +\sphinxAtStartPar +There are many reasons to disaggregate functionality, but one of the +most compelling is that decoupling control and data code paths allows +them to be optimized independently. The data path, for example, can be +optimized by +programming it into specialized hardware. Modern white\sphinxhyphen{}box switches with +programmable packet forwarding pipelines are a perfect example of +specialized hardware we can exploit in the cellular network. +\hyperref[\detokenize{disaggregate:fig-e2e}]{Figure \ref{\detokenize{disaggregate:fig-e2e}}} shows the first step in the process +of doing this. The figure also pulls together all the elements we’ve +been describing up to this point. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide21}.png} +\caption{End\sphinxhyphen{}to\sphinxhyphen{}end disaggregated system, including Mobile Core +and Split\sphinxhyphen{}RAN.}\label{\detokenize{disaggregate:id1}}\label{\detokenize{disaggregate:fig-e2e}}\end{figure} + +\sphinxAtStartPar +There are several things to note +about this diagram. First, the figure combines both the Mobile Core and RAN elements, +organized according to the major subsystems: Mobile Core, Central Unit +(CU), Distributed Unit (DU), and Radio Unit (RU). The figure also shows +one possible mapping of these subsystems onto physical locations, with +the first two co\sphinxhyphen{}located in a Central Office and the latter two +co\sphinxhyphen{}located in a cell tower. As discussed earlier, other configurations +are also possible. + +\sphinxAtStartPar +Second, the figure shows the Mobile Core’s two user plane elements +(PGW, SGW) and the Central Unit’s single user plane element (PDCP) +further disaggregated into control/user plane pairs, denoted PGW\sphinxhyphen{}C / +PGW\sphinxhyphen{}U, SGW\sphinxhyphen{}C / SGW\sphinxhyphen{}U, and PDCP\sphinxhyphen{}C / PDCP\sphinxhyphen{}U, respectively. Exactly how +this decoupling is realized is an implementation choice (i.e., not +specified by 3GPP), but the idea is to reduce the User Plane component +to the minimal Receive\sphinxhyphen{}Packet / Process\sphinxhyphen{}Packet / Send\sphinxhyphen{}Packet +processing core, and elevate all control\sphinxhyphen{}related aspects into the +Control Plane component. + +\sphinxAtStartPar +Third, the PHY (Physical) element of the RAN pipeline is split between +the DU and RU partition. Although beyond the scope of this book, the +3GPP spec specifies the PHY element as a collection of functional +blocks, some of which can be effectively implemented by software running +on a general\sphinxhyphen{}purpose processor and some of which are best implemented in +specialized hardware (e.g., a Digital Signal Processor). These two +subsets of functional blocks map to the PHY Upper (part of the DU) and +the PHY Lower (part of the RU), respectively. + +\sphinxAtStartPar +Fourth, and somewhat confusingly, \hyperref[\detokenize{disaggregate:fig-e2e}]{Figure \ref{\detokenize{disaggregate:fig-e2e}}} +shows the PDCP\sphinxhyphen{}C +element and the Control Plane (Forwarding) element combined into a +single functional block, with a data path (blue line) connecting that +block to both the RLC and the MME. Exactly how this pair is realized is +an implementation choice (e.g., they could map onto two or more +microservices), but the end result is that they are part of an +end\sphinxhyphen{}to\sphinxhyphen{}end path over which the MME can send control packets to the UE. +Note that this means responsibility for demultiplexing incoming packets +between the control plane and user plane falls to the RLC. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide22}.png} +\caption{Implementing data plane elements of the User Plane in +programmable switches.}\label{\detokenize{disaggregate:id2}}\label{\detokenize{disaggregate:fig-e2e-p4}}\end{figure} + +\sphinxAtStartPar +\hyperref[\detokenize{disaggregate:fig-e2e-p4}]{Figure \ref{\detokenize{disaggregate:fig-e2e-p4}}} shows why we disaggregated these +components: it allows us to realize the three user plane elements +(PGW\sphinxhyphen{}U, SGW\sphinxhyphen{}U, PDCP\sphinxhyphen{}U) in switching hardware. This can be done using a +combination of a language that is tailored for programming forwarding +pipelines (e.g., P4), and a protocol\sphinxhyphen{}independent switching +architecture (e.g., Intel’s Tofino). For now, the important takeaway is that +the RAN and Mobile Core user plane can be mapped directly onto an +SDN\sphinxhyphen{}enabled data plane. + +\phantomsection\label{\detokenize{disaggregate:reading-p4}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +For more information about P4 and programmable switching chips, we +recommend \sphinxhref{https://sdn.systemsapproach.org/switch.html}{White\sphinxhyphen{}Box Switches}, a chapter in +\sphinxstyleemphasis{Software\sphinxhyphen{}Defined Networking: A Systems Approach}, March 2020. +\end{sphinxadmonition} + +\sphinxAtStartPar +Pushing RAN and Mobile Core forwarding functionality into the switching +hardware results in overlapping terminology that can be confusing. +5G separates the functional blocks into control and user planes, +while SDN disaggregates a given functional block into control and data +plane halves. The overlap comes from our choosing to implement +the 5G user plane by splitting it into its SDN\sphinxhyphen{}based control and data +plane parts. As one simplification, we refer to the Control Plane +(Forwarding) and PDCP\sphinxhyphen{}C combination as the CU\sphinxhyphen{}C (Central Unit \sphinxhyphen{} Control) +going forward. + +\sphinxAtStartPar +Finally, the SDN\sphinxhyphen{}prescribed control/data plane disaggregation comes with +an implied implementation strategy, namely, the use of a scalable and +highly available \sphinxstyleemphasis{Network Operating System (NOS)}. Like a traditional +OS, a NOS sits between application programs (control apps) and the +underlying hardware devices (whitebox switches), providing higher levels +abstractions (e.g., network graph) to those applications, while hiding +the low\sphinxhyphen{}level details of the underlying hardware. To make the discussion +more concrete, we use ONOS (Open Network Operating System) as an example +NOS, where PGW\sphinxhyphen{}C, SGW\sphinxhyphen{}C, and PDCP\sphinxhyphen{}C are all realized as control +applications running on top of ONOS. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=400\sphinxpxdimen]{{Slide23}.png} +\caption{Control Plane elements of the User Plane implemented +as Control Applications running on an SDN Controller (e.g., ONOS).}\label{\detokenize{disaggregate:id3}}\label{\detokenize{disaggregate:fig-onos}}\end{figure} + +\sphinxAtStartPar +\hyperref[\detokenize{disaggregate:fig-onos}]{Figure \ref{\detokenize{disaggregate:fig-onos}}} shows one possible configuration in +which the underlying switches are interconnected to form a leaf\sphinxhyphen{}spine +fabric. Keep in mind that the linear sequence of switches implied by +\hyperref[\detokenize{disaggregate:fig-e2e-p4}]{Figure \ref{\detokenize{disaggregate:fig-e2e-p4}}} is logical, but that in no way +restricts the actual hardware to the same topology. The reason we use +a leaf\sphinxhyphen{}spine topology is related to our ultimate goal of building an +edge cloud, and leaf\sphinxhyphen{}spine is the prototypical structure for such +cloud\sphinxhyphen{}based clusters. This means the three control applications must +work in concert to implement an end\sphinxhyphen{}to\sphinxhyphen{}end path through the fabric, +which in practice happens with the aid of other, fabric\sphinxhyphen{}aware, control +applications (as implied by the “…” in the Figure). We describe the +complete picture in more detail in the next chapter, but for now, the +big takeaway is that the control plane components of the 5G overlay +can be realized as control applications for an SDN\sphinxhyphen{}based underlay. + + +\section{5.2 Multi\sphinxhyphen{}Cloud} +\label{\detokenize{disaggregate:multi-cloud}} +\sphinxAtStartPar +Another consequence of disaggregating functionality is that once +decoupled, different functions can be placed in different physical +locations. We have already seen this when we split the RAN, placing some +functions (e.g., the PDCP and RRC) in the Central Unit and others (e.g., +RLC and MAC) in Distributed Units. This allows for simpler (less +expensive) hardware in remote locations, where there are often space, +power, and cooling constraints. + +\sphinxAtStartPar +This process can be repeated by distributing the more centralized +elements across multiple clouds, including large datacenters that +already benefit from elasticity and economies of +scale. \hyperref[\detokenize{disaggregate:fig-multicloud}]{Figure \ref{\detokenize{disaggregate:fig-multicloud}}} shows the resulting +multi\sphinxhyphen{}cloud realization of the Mobile Core. We leave the user plane at +the edge of the network (e.g., in the Central Office) and move control +plane to a centralized cloud. It could even be a public cloud like +Google or Amazon. This includes not only the MME, PCRF, and HSS, but +also the PGW\sphinxhyphen{}C and SGW\sphinxhyphen{}C we decoupled in the previous section. (Note +that \hyperref[\detokenize{disaggregate:fig-multicloud}]{Figure \ref{\detokenize{disaggregate:fig-multicloud}}} renames the PDCP\sphinxhyphen{}U from +earlier diagrams as the CU\sphinxhyphen{}U; either label is valid.) + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide24}.png} +\caption{Multi\sphinxhyphen{}Cloud implementation, with MME, HSS, PCRF and +Control Plane elements of the PGW and SGW running in a centralized +cloud.}\label{\detokenize{disaggregate:id4}}\label{\detokenize{disaggregate:fig-multicloud}}\end{figure} + +\sphinxAtStartPar +What is the value in doing this? Just like the DU and RU, the Edge Cloud +likely has limited resources. If we want room to run new edge services +there, it helps to move any components that need not be local to a +larger facility with more abundant resources. Centralization also +facilitates collecting and analyzing data across multiple edge +locations, which is harder to do if that information is distributed over +multiple sites. (Analytics performed on this data also benefits from +having abundant compute resources available.) + +\sphinxAtStartPar +Another reason worth calling out is that it lowers the barrier for +anyone (not just the companies that own and operate the RAN +infrastructure) to offer mobile services to customers. These entities +are called \sphinxstyleemphasis{MVNOs (Mobile Virtual Network Operators)} and one clean +way to engineer an MVNO is to run your own Mobile Core in a cloud of +your choosing. + +\sphinxAtStartPar +But the biggest motivation for the configuration shown in +\hyperref[\detokenize{disaggregate:fig-multicloud}]{Figure \ref{\detokenize{disaggregate:fig-multicloud}}} is that keeping the user plane +elements of the mobile core at the edge makes it possible to “break +out” local traffic without having to traverse a “hairpin” route that +goes through a central site. This has the potential to dramatically +reduce latency for any edge\sphinxhyphen{}hosted services. We return to this topic +in Chapter 7. + + +\section{5.3 Network Slicing} +\label{\detokenize{disaggregate:network-slicing}} +\sphinxAtStartPar +One of the most compelling value propositions of 5G is the ability to +differentiate the level of service offered to different applications +and customers. Differentiation, of course, is key to being able to +charge some customers more than others, but the monetization case +is only part of the story. It is also necessary to support +applications with widely varying requirements. For example, streaming video requires high bandwidth +but can tolerate larger latencies, while IoT has +minimal bandwidth needs but sometimes requires extremely low and predictable +latencies, and entails connecting a \sphinxstyleemphasis{massively scalable} number of +devices. + +\sphinxAtStartPar +The mechanism that supports this sort of differentiation is called +network slicing, and it fundamentally comes down to scheduling, both in +the RAN (deciding which segments to transmit) and in the Mobile Core +(scaling microservice instances and placing those instances on the +available servers). The following introduces the basic idea, starting +with the RAN. + +\sphinxAtStartPar +But before getting into the details, we note that a network slice is a +realization of the QoS Class Identifier (QCI) discussed earlier. 3GPP +specifies a standard set of network slices, called \sphinxstyleemphasis{Standardized Slice +Type (SST)} values. For example, SST 1 corresponds to mobile broadband, +SST 2 corresponds to Ultra\sphinxhyphen{}Reliable Low Latency Communications, SST 3 +corresponds to Massive IoT, and so on. It is also possible to extend +this standard set with additional slice behaviors, as well as define +multiple slices for each SST (e.g., to further differentiate subscribers +based on priority). + +\sphinxAtStartPar +Of course, defining a desired set of slices and implementing a slicing +mechanism are two entirely different things. The following sketches +how slices can be implemented. + + +\subsection{RAN Slicing} +\label{\detokenize{disaggregate:ran-slicing}} +\sphinxAtStartPar +We start by reviewing the basic scheduling challenge previewed in +Chapter 2. As depicted in \hyperref[\detokenize{disaggregate:fig-slice-sched}]{Figure \ref{\detokenize{disaggregate:fig-slice-sched}}}, +the radio spectrum can be conceptualized as a 2\sphinxhyphen{}D grid of +\sphinxstyleemphasis{Resource Blocks (RB)}, where the scheduler’s job is to decide how to fill the +grid with the available segments from each user’s transmission queue +based on CQI feedback from the UEs. To restate, the power of OFDMA is +the flexibility it provides in how this mapping is performed. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=450\sphinxpxdimen]{{Slide27}.png} +\caption{Scheduler allocating resource blocks to UEs.}\label{\detokenize{disaggregate:id5}}\label{\detokenize{disaggregate:fig-slice-sched}}\end{figure} + +\sphinxAtStartPar +While in principle one could define an uber scheduler that takes dozens +of different factors into account, the key to network slicing is to add +a layer of indirection. As shown in \hyperref[\detokenize{disaggregate:fig-hypervisor}]{Figure \ref{\detokenize{disaggregate:fig-hypervisor}}}, +the idea is to perform a second mapping of Virtual RBs to +Physical RBs. This sort of virtualization is common in resource +allocators throughout computing systems because we want to separate how +many resources are allocated to each user from the decision as to which +physical resources are actually assigned. This virtual\sphinxhyphen{}to\sphinxhyphen{}physical +mapping is performed by a layer typically known as a \sphinxstyleemphasis{Hypervisor}, and +the important thing to keep in mind is that it is totally agnostic about +which user’s segment is affected by each translation. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide28}.png} +\caption{Wireless Hypervisor mapping virtual resource blocks to +physical resource blocks.}\label{\detokenize{disaggregate:id6}}\label{\detokenize{disaggregate:fig-hypervisor}}\end{figure} + +\sphinxAtStartPar +Having decoupled the Virtual RBs from Physical RBs, it is now possible +to define multiple Virtual RB sets (of varying sizes), each with its own +scheduler. \hyperref[\detokenize{disaggregate:fig-multi-sched}]{Figure \ref{\detokenize{disaggregate:fig-multi-sched}}} gives an example with two +equal\sphinxhyphen{}sized RB sets, where the important consequence is that having made +the macro\sphinxhyphen{}decision that the Physical RBs are divided into two equal +partitions, the scheduler associated with each partition is free to +allocate Virtual RBs completely independent from each other. For +example, one scheduler might be designed to deal with high\sphinxhyphen{}bandwidth +video traffic and another scheduler might be optimized for low\sphinxhyphen{}latency +IoT traffic. Alternatively, a certain fraction of the available capacity +could be reserved for premium customers or other high\sphinxhyphen{}priority traffic +(e.g., public safety), with the rest shared among everyone else. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide29}.png} +\caption{Multiple schedulers running on top of wireless +hypervisor.}\label{\detokenize{disaggregate:id7}}\label{\detokenize{disaggregate:fig-multi-sched}}\end{figure} + +\sphinxAtStartPar +Going one level deeper in the implementation details, the real\sphinxhyphen{}time +scheduler running in each DU receives high\sphinxhyphen{}level directives from the +near\sphinxhyphen{}real\sphinxhyphen{}time scheduler running in the CU, and as depicted in +\hyperref[\detokenize{disaggregate:fig-slicing-control}]{Figure \ref{\detokenize{disaggregate:fig-slicing-control}}}, the DUs follow these +directives in making their scheduling decisions \sphinxstyleemphasis{on a +per\sphinxhyphen{}slice basis}. A single RAN Slicing control application is responsible for the +macro\sphinxhyphen{}scheduling decision by allocating resources among a set of +slices. Understanding this implementation detail is important because +all of these control decisions are implemented by software modules, +and hence, easily changed or customized. They are not “locked” into +the underlying system, as they have historically been in 4G’s eNodeBs. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=350\sphinxpxdimen]{{Slide30}.png} +\caption{Centralized near\sphinxhyphen{}real\sphinxhyphen{}time control applications +cooperating with distributed real\sphinxhyphen{}time RAN schedulers.}\label{\detokenize{disaggregate:id8}}\label{\detokenize{disaggregate:fig-slicing-control}}\end{figure} + +\sphinxAtStartPar +In summary, the goal of RAN slicing is to programmatically create +virtual RAN nodes (base stations) that operate on the same hardware +and share the spectrum resources according to a given policy for +different applications, services, users, and so on. Tying RAN slicing +back to RAN disaggregation, one can imagine several possible +configurations, depending on the desired level of isolation between +the slices. \hyperref[\detokenize{disaggregate:fig-ran-slicing}]{Figure \ref{\detokenize{disaggregate:fig-ran-slicing}}} shows four examples, +all of which assume slices share the antennas and RF components, which +is effectively the RU: (a) RAN slices share RU, DU, CU\sphinxhyphen{}U and CU\sphinxhyphen{}C; (b) +RAN slices share RU and DU, but have their own CU\sphinxhyphen{}U and CU\sphinxhyphen{}C; (c) RAN +slices share RU, CU\sphinxhyphen{}U and CU\sphinxhyphen{}C, but have their own DU; and (d) RAN +slices share RU, but have their own DU, CU\sphinxhyphen{}U and CU\sphinxhyphen{}C. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=700\sphinxpxdimen]{{Slide40}.png} +\caption{Four possible configurations of a disaggregated RAN in support of +RAN slicing.}\label{\detokenize{disaggregate:id9}}\label{\detokenize{disaggregate:fig-ran-slicing}}\end{figure} + + +\subsection{Core Slicing} +\label{\detokenize{disaggregate:core-slicing}} +\sphinxAtStartPar +In addition to slicing the RAN, we also need to slice the Mobile Core. +In many ways, this is a well\sphinxhyphen{}understood problem, involving QoS +mechanisms in the network switches (i.e., making sure packets flow +through the switching fabric according to the bandwidth allocated to +each slice) and the cluster processors (i.e., making sure the containers +that implement each microservice are allocated sufficient CPU cores to +sustain the packet forwarding rate of the corresponding slice). + +\sphinxAtStartPar +But packet scheduling and CPU scheduling are low\sphinxhyphen{}level mechanisms. What +makes slicing work is to also virtualize and replicate the entire +service graph that implements the Mobile Core. If you think of a slice as +a system abstraction, then that abstraction needs to keep track of the +set of interconnected microservices that implement each slice, +and then instruct the underlying packet schedulers to allocate +sufficient network bandwidth to the slice’s flows and the underlying CPU +schedulers to allocate sufficient compute cycles to the slice’s +containers. + +\sphinxAtStartPar +For example, if there are two network slices (analogous to the two RAN +schedulers shown in \hyperref[\detokenize{disaggregate:fig-multi-sched}]{Figures \ref{\detokenize{disaggregate:fig-multi-sched}}} and +\hyperref[\detokenize{disaggregate:fig-slicing-control}]{\ref{\detokenize{disaggregate:fig-slicing-control}}}), then there would also need +to be two Mobile Core service graphs: One set of AMF, SMF, UPF,… +microservices running on behalf of the first slice and a second set of +AMF, SMF, UPF,… microservices running on behalf of the second +slice. These two graphs would scale independently (i.e., include a +different number of container instances), depending on their +respective workloads and QoS guarantees. The two slices would also be +free to make different implementation choices, for example, with one +optimized for massive IoT applications and the other optimized for +high\sphinxhyphen{}bandwidth AR/VR applications. + +\sphinxAtStartPar +The one remaining mechanism we need is a demultiplexing function that +maps a given packet flow (e.g., between UE and some Internet +application) onto the appropriate instance of the service graph. This is +the job of the NSSF described in an Chapter 3: it is responsible +for selecting the instance a given slice’s traffic is to traverse. + +\sphinxAtStartPar +The similarity between slicing and the much\sphinxhyphen{}debated topic of network +QoS might lead one to conclude that slicing won’t take off, as QoS +never seemed to provide quite enough benefit in large networks to +justify its complexity. But the one place where QoS \sphinxstyleemphasis{is} effective is +when bandwidth is scarce, e.g., in last\sphinxhyphen{}mile links. For this reason, +slicing is likely to be valuable precisely because it allows efficient +partitioning of the relatively scarce resource that is cellular +spectrum. + +\sphinxAtStartPar +Finally, note that slicing can be viewed as a way to enable overlays on +the cellular network. The Internet has a long history of supporting +innovation through the use of overlays. Many innovations such as +multicast and content delivery networks were developed in this way. So +while we might not know exactly how slicing will be used, it is an +important ingredient in fostering innovation. + + +\chapter{Chapter 6: Exemplar Implementation} +\label{\detokenize{impl:chapter-6-exemplar-implementation}}\label{\detokenize{impl::doc}} +\sphinxAtStartPar +The steps we’ve taken in the previous chapters to virtualize, +disaggregate, optimize, distribute, and slice the cellular network not +only help us understand the inner\sphinxhyphen{}workings of 5G, but they are also +necessary to reduce the entirety of the 5G cellular network to practice. +The goal is an implementation, which by definition, forces us to make +specific engineering choices. This chapter describes one set of +engineering choices that results in a running system. It should be +interpreted as an exemplar, for the sake of completeness, but not the +only possibility. + +\sphinxAtStartPar +The system we describe is called CORD, which you will recall from the +Introduction is an acronym (\sphinxstylestrong{C}entral \sphinxstylestrong{O}ffice +\sphinxstylestrong{R}e\sphinxhyphen{}architected as a \sphinxstylestrong{D}atacenter). More concretely, CORD is a +blueprint for building a 5G deployment from commodity hardware and a +collection of open source software components. We call this +hardware/software combination a CORD POD, where the idea is to deploy a +POD at each edge site that is part of a cellular network. The following +describes CORD in terms of a set of engineering decisions. It is not a +substitute for detailed documentation for installing, developing, and +operating CORD. Also keep in mind that even though CORD includes +“Central Office” in its name, a CORD POD is a general design, and not +strictly limited to being deployed in a conventional Central Office. + +\phantomsection\label{\detokenize{impl:reading-guide}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +To learn how to install, operate, and contribute to the CORD open +source software platform, see the \sphinxhref{https://guide.opencord.org}{CORD Guide}. ONF, March 2020. +\end{sphinxadmonition} + +\sphinxAtStartPar +Before getting into the specifics, it is important to understand that +CORD is a work\sphinxhyphen{}in\sphinxhyphen{}progress, with a sizable open source community +contributing to its code base. Many of the components are quite mature, +and currently running in operator trials and production networks. Others +(largely corresponding to the advanced capabilities described in the +previous chapter) are prototypes that run in “demonstration mode,” but +are not yet complete enough to be included in official releases. Also, +as outlined in the earlier discussion on deployment options, CORD starts +with a production\sphinxhyphen{}quality EPC that is being incrementally evolved into +its 5G counterpart. (This chapter uses the EPC\sphinxhyphen{}specific components for +illustrative purposes.) + + +\section{6.1 Framework} +\label{\detokenize{impl:framework}} +\sphinxAtStartPar +\hyperref[\detokenize{impl:fig-cord}]{Figure \ref{\detokenize{impl:fig-cord}}} gives a schematic overview of a CORD POD. It +connects downstream to a set of DUs (and associated RUs), and upstream +to the rest of the Internet. Internally, it includes a set of commodity +servers (the figure shows four racks of three servers each, but the +design accommodates anywhere from a partial rack to 16 racks) and a set +of white\sphinxhyphen{}box switches arranged in a leaf\sphinxhyphen{}spine topology (the figure +shows two leaves and two spine switches, but the design allows anywhere +from a single switch to two leaf switches per rack and as many spine +switches as necessary to provide sufficient east\sphinxhyphen{}to\sphinxhyphen{}west bandwidth). + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=650\sphinxpxdimen]{{Slide25}.png} +\caption{CORD implementation of RAN and Mobile Core.}\label{\detokenize{impl:id1}}\label{\detokenize{impl:fig-cord}}\end{figure} + +\sphinxAtStartPar +With respect to software, \hyperref[\detokenize{impl:fig-cord}]{Figure \ref{\detokenize{impl:fig-cord}}} shows a +combination of RAN (red) and Mobile Core (blue) components, plus the +modules that define the CORD platform (orange). We describe the +platform components later in this chapter, but you can think of them +as collectively implementing a multi\sphinxhyphen{}tenant cloud on top of which many +different scalable services can run. The RAN and Mobile Core are two +such tenants. The CORD platform can also host other edge services +(which is one reason CORD is built using cloud technology in the first +place), but exactly what other edge services might run on a given CORD +POD is a question we do not try to answer in this book. + +\sphinxAtStartPar +The RAN and Core related components are ones we’ve described in +earlier chapters. They include the Control and User planes of the CU +and Mobile Core, respectively. To simplify the diagram, we show +the SGW and PGW merged into a single S/PGW. One other detail that +deserves closer attention is the RAN Control component included in the +CU Control Plane. This is the Near\sphinxhyphen{}RT RIC introduced in Section 4.3, +which means a CORD POD includes two SDN Controllers: the RIC controls +the RAN and ONOS (shown in \hyperref[\detokenize{impl:fig-cord}]{Figure \ref{\detokenize{impl:fig-cord}}}) controls the +fabric. (The RIC running in CORD actually happens to be a second, +customized version of ONOS, but that’s an implementation detail.) + +\sphinxAtStartPar +One aspect of \hyperref[\detokenize{impl:fig-cord}]{Figure \ref{\detokenize{impl:fig-cord}}} that requires further +elaboration is how each of the RAN and Mobile Core components are +actually realized. Specifically, there are three different +manifestations of the functional components implied by the figure: (1) +the data plane layer of the CU\sphinxhyphen{}U and S/PGW\sphinxhyphen{}U are realized as P4 +programs loaded into the programmable switches; (2) the control plane +layer of the CU\sphinxhyphen{}U and S/PGW\sphinxhyphen{}U (as well as the Trellis platform module) +are realized as control applications loaded onto ONOS; +and (3) the remaining components are realized as Kubernetes\sphinxhyphen{}managed +microservices. (Kubernetes is implied, but not shown in the figure.) + +\sphinxAtStartPar +To expand on this idea, \hyperref[\detokenize{impl:fig-ci-cd}]{Figure \ref{\detokenize{impl:fig-ci-cd}}} gives an +alternative view of a CORD POD, abstracting away the details of \sphinxstyleemphasis{what} +services it hosts, and focusing instead on \sphinxstyleemphasis{how} those services are +instantiated on the POD. In this figure, all the functionality +instantiated onto the POD runs as a combination of Kubernetes\sphinxhyphen{}based +microservices and ONOS\sphinxhyphen{}based control applications. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=350\sphinxpxdimen]{{Slide26}.png} +\caption{Alternative view of CORD, with a CI/CD toolchain +managing the platform and set of services implemented by a +combination of ONOS\sphinxhyphen{}based control apps and Kubernetes\sphinxhyphen{}based +microservices.}\label{\detokenize{impl:id2}}\label{\detokenize{impl:fig-ci-cd}}\end{figure} + +\sphinxAtStartPar +When abstracted in this way, we can view a POD as including three major +subsystems. +\begin{itemize} +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Platform:} The base layer common to all configurations includes +Kubernetes as the container management system and ONOS as the SDN +controller, with Stratum (an open source switch OS) loaded on to each switch. Both ONOS and the +control applications it hosts run as Kubernetes\sphinxhyphen{}managed +microservices. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Profile:} The deployment\sphinxhyphen{}specific collection of microservices and +SDN control apps that have been selected to run on a particular POD. +This is a variable and evolvable set, and it includes the control +plane and edge services described elsewhere. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{CI/CD Toolchain:} Used to assemble, deploy, operate, and upgrade a +particular Platform/Profile combination. It implements a set of +processes that transforms a collection of disaggregated and +virtualized components into an operational system capable of +responding to operator directives and carrying live traffic. + +\end{itemize} + +\sphinxAtStartPar +Although beyond the scope of this book, the CI/CD toolchain uses +standard DevOps tools to bootstrap software onto the cluster of servers +and switches, and rollout/rollback individual microservices and control +applications. It also auto\sphinxhyphen{}generates the Northbound Interface (NBI) that +operators use to manage the POD, based on a declarative specification of +the Profile the POD is configured to support. This NBI is sufficiently +complete to operate a CORD POD in a production environment. + + +\section{6.2 Platform Components} +\label{\detokenize{impl:platform-components}} +\sphinxAtStartPar +We now return to the three platform\sphinxhyphen{}related components shown in +\hyperref[\detokenize{impl:fig-cord}]{Figures \ref{\detokenize{impl:fig-cord}}} and \hyperref[\detokenize{impl:fig-ci-cd}]{\ref{\detokenize{impl:fig-ci-cd}}}. Each is a substantial open source component in its own +right, but for our purposes, it is enough to understand the role they +play in supporting a 5G\sphinxhyphen{}based profile of CORD. +\begin{itemize} +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Stratum:} A thin operating system that runs locally on each +white\sphinxhyphen{}box switch. Its purpose is to provide a hardware\sphinxhyphen{}independent +interface for managing and programming the switches in CORD. This +includes using \sphinxstyleemphasis{P4} to define the forwarding behavior of the switch’s +forwarding pipeline (think of this program as a contract between the +control and data planes), and \sphinxstyleemphasis{P4Runtime} to control that forwarding +contract at runtime. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{ONOS:} A Network Operating System used to configure and control a +network of programmable white\sphinxhyphen{}box switches. It runs off\sphinxhyphen{}switch as a +logically centralized SDN controller, and hosts a collection of SDN +control applications, each of which controls some aspect of the +underlying network. Because it is logically centralized, ONOS is +designed to be highly available and to have scalable performance. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Trellis:} An ONOS\sphinxhyphen{}hosted SDN control application that implements a +leaf\sphinxhyphen{}spine fabric on a network of white\sphinxhyphen{}box switches. It implements +the control plane for several features, including VLANs and L2 +bridging, IPv4 and IPv6 unicast and multicast routing, DHCP L3 relay, +dual\sphinxhyphen{}homing of servers and upstream routers, QinQ +forwarding/termination, MPLS pseudowires, and so on. In addition, +Trellis can make the entire fabric appear as a single (virtual) +router to upstream routers, which communicate with Trellis using +standard BGP. + +\end{itemize} + +\sphinxAtStartPar +Stratum (running on each switch) and ONOS (running off\sphinxhyphen{}switch and +managing a network of switches) communicate using the following +interfaces. +\begin{itemize} +\item {} +\sphinxAtStartPar +\sphinxstylestrong{P4:} Defines the forwarding behavior for programmable switching +chips as well as modeling fixed\sphinxhyphen{}function ASIC pipelines. A P4 program +defines a contract that is implemented by the data plane and +programmable by the control plane. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{P4Runtime:} An SDN\sphinxhyphen{}ready interface for controlling forwarding +behavior at runtime. It is the key for populating forwarding tables +and manipulating forwarding state, and it does so in way that is +hardware\sphinxhyphen{}agnostic. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{OpenConfig Models:} Define a base for device configuration and +management. These models can be programmatically extended for +platform\sphinxhyphen{}specific functionality, but the goal is to minimize model +deviations so as to enable a vendor\sphinxhyphen{}agnostic management plane. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{gNMI} (gRPC Network Management Interface): Improves on the +existing configuration interfaces by using a binary representation on +the wire and enabling bi\sphinxhyphen{}directional streaming. Paired with the +OpenConfig models, gNMI is SDN\sphinxhyphen{}ready. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{gNOI} (gRPC Network Operations Interfaces): A collection of +microservices that enable switch specific operations, like +certificate management, device testing, software upgrade, and +networking troubleshooting. gNOI provides a semantically rich API +that replaces existing CLI\sphinxhyphen{}based approaches. + +\end{itemize} + +\sphinxAtStartPar +Trellis, as an SDN control application running on top of ONOS, controls +packet forwarding across the switching fabric internal to a CORD POD +(i.e., within a single site). But Trellis can also be extended across +multiple sites deeper into the network using multiple stages of spines, +as shown in \hyperref[\detokenize{impl:fig-trellis}]{Figure \ref{\detokenize{impl:fig-trellis}}}. This means Trellis has the +potential to play a role in implementing the backhaul and midhaul +network for the RAN, or alternatively, extending the RAN into customer +premises (denoted “On Site” in the figure). + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=600\sphinxpxdimen]{{Slide31}.png} +\caption{Trellis control application managing a (possibly +distributed) leaf\sphinxhyphen{}spine fabric.}\label{\detokenize{impl:id3}}\label{\detokenize{impl:fig-trellis}}\end{figure} + +\sphinxAtStartPar +The software stack we’ve just described is substantial, and has the +potential to disrupt the way cellular networks are built and operated. +Of particular note, the RAN Intelligent Controller +shown in \hyperref[\detokenize{impl:fig-cord}]{Figure \ref{\detokenize{impl:fig-cord}}} is implemented as a set of +extensions to ONOS. This puts the ONOS\sphinxhyphen{}based RIC at the very center +of the design, where the SDN and 5G worlds intersect. + +\sphinxAtStartPar +This discussion, while focused on just one option for implementing 5G +networks, illustrates one of the reasons 5G is viewed as such a +transformation of the Telco industry. The 5G architecture, far more +than any previous Telco network, capitalizes on several significant, broad +industry trends. These include the rise of SDN, the power of open source +software and its increasing use in networking, and of course the +adoption of cloud technologies as the basis for delivering innovative services. + +\phantomsection\label{\detokenize{impl:reading-sdn}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +For more information about the SDN software stack, we recommend a +companion book: \sphinxhref{https://sdn.systemsapproach.org/}{Software\sphinxhyphen{}Defined Networks: A Systems Approach}. March 2020. +\end{sphinxadmonition} + + +\chapter{Chapter 7: Cloudification of Access} +\label{\detokenize{cloud:chapter-7-cloudification-of-access}}\label{\detokenize{cloud::doc}} +\sphinxAtStartPar +The previous chapters went step\sphinxhyphen{}by\sphinxhyphen{}step, first breaking 5G down into its +elemental components and then showing how those components could be put +back together using best practices in cloud design to build a fully +functional, 3GPP\sphinxhyphen{}compliant 5G cellular network. In doing so, it is easy +to lose sight of the big picture, which is that the cellular network is +undergoing a dramatic transformation. That’s the whole point of 5G. We +conclude by making some observations about this big picture. + + +\section{7.1 Multi\sphinxhyphen{}Cloud} +\label{\detokenize{cloud:multi-cloud}} +\sphinxAtStartPar +To understand the impact of cloud technologies and practices being +applied to the access network, it is helpful to first understand what’s +important about the cloud. The cloud has fundamentally changed the way +we compute, and more importantly, the pace of innovation. It has done +this through a combination of the following. +\begin{itemize} +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Disaggregation:} Breaking vertically integrated systems into +independent components with open interfaces. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Virtualization:} Being able to run multiple independent copies of +those components on a common hardware platform. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Commoditization:} Being able to elastically scale those virtual +components across commodity hardware bricks as workload dictates. + +\end{itemize} + +\sphinxAtStartPar +There is an opportunity for the same to happen with the access network, +or from another perspective, for the cloud to essentially expand so far +as to subsume the access network. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=700\sphinxpxdimen]{{Slide32}.png} +\caption{A collection of multi\sphinxhyphen{}tenant clouds—including virtualized RAN +resources alongside conventional compute, storage, and network +resources—hosting both Telco and Over\sphinxhyphen{}the\sphinxhyphen{}Top (OTT) services and +applications.}\label{\detokenize{cloud:id1}}\label{\detokenize{cloud:fig-cloud}}\end{figure} + +\sphinxAtStartPar +\hyperref[\detokenize{cloud:fig-cloud}]{Figure \ref{\detokenize{cloud:fig-cloud}}} gives a high\sphinxhyphen{}level overview of how the +transformation might play out, with the global cloud spanning edge +clouds, private Telco clouds, and the familiar public clouds. We call +this collection of clouds “multi\sphinxhyphen{}cloud” (although note that there are +a number of other definitions for that term). Each +individual cloud site is potentially owned by a different organization +(this includes the cell towers, as well), and as a consequence, each +site will likely be multi\sphinxhyphen{}tenant in that it is able to host (and +isolate) applications on behalf of many other people and organizations. +Those applications, in turn, will include a combination of the RAN and +Core services (as described throughout this book), Over\sphinxhyphen{}the\sphinxhyphen{}Top (OTT) +applications commonly found today in public clouds (but now also +distributed across edge clouds), and new Telco\sphinxhyphen{}managed applications +(also distributed across centralized and edge locations). + +\sphinxAtStartPar +Eventually, we can expect common APIs to emerge, lowering the barrier +for anyone (not just today’s network operators or cloud providers) to +deploy applications across multiple sites by acquiring the storage, +compute, networking, and connectivity resources they need. + + +\section{7.2 EdgeCloud\sphinxhyphen{}as\sphinxhyphen{}a\sphinxhyphen{}Service} +\label{\detokenize{cloud:edgecloud-as-a-service}} +\sphinxAtStartPar +Of all the potential outcomes discussed in the previous section, one +that is rapidly gaining traction is to run a 5G\sphinxhyphen{}enabled edge cloud as +a centrally managed service. As illustrated in \hyperref[\detokenize{cloud:fig-edgecloud}]{Figure \ref{\detokenize{cloud:fig-edgecloud}}}, the idea is to deploy an edge cloud in enterprises, +configured with the user plane components of the RAN and Mobile Core +(along with any edge services the enterprise wants to run locally), +and then manage that edge deployment from the central cloud. The +central cloud would run a management portal for the edge cloud, along +with the control plane of the Mobile Core. This is similar to the +multi\sphinxhyphen{}cloud configuration discussed in Section 5.2, except with the +added feature of being able to manage multiple edge deployments from +one central location. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=700\sphinxpxdimen]{{Slide36}.png} +\caption{EdgeCloud\sphinxhyphen{}as\sphinxhyphen{}a\sphinxhyphen{}Service, a managed service, with RAN and Mobile +Core user plane components running in the enterprise, and the +control plane of the Mobile Core (along with a management portal) +running centrally in the public cloud.}\label{\detokenize{cloud:id2}}\label{\detokenize{cloud:fig-edgecloud}}\end{figure} + +\sphinxAtStartPar +The value of such a deployment is to bring 5G wireless advantages into +the enterprise, including support for predictable, low\sphinxhyphen{}latency +communication required for real\sphinxhyphen{}time controlling of large numbers of +mobile devices. Factory automation is one compelling use case for such +an edge cloud, but interest in supporting IoT in general is giving +ECaaS significant momentum. + +\sphinxAtStartPar +This momentum has, not surprisingly, led to recent commercial +activity. But there is also an open source variant, called Aether, now +available for early adopters to evaluate and experiment with. Aether +is an ONF\sphinxhyphen{}operated ECaaS with 4G/5G support, built from the open +source components described throughout this book. Aether works with +both licensed and unlicensed frequency bands (e.g., CBRS), but it is +the latter that makes it an easy system to opt into. \hyperref[\detokenize{cloud:fig-aether}]{Figure +\ref{\detokenize{cloud:fig-aether}}} depicts the early stages of Aether’s centrally +managed, multi\sphinxhyphen{}site deployment. + +\begin{figure}[ht] +\centering +\capstart + +\noindent\sphinxincludegraphics[width=700\sphinxpxdimen]{{Slide37}.png} +\caption{Aether is an ONF\sphinxhyphen{}operated EdgeCloud\sphinxhyphen{}as\sphinxhyphen{}a\sphinxhyphen{}Service built from the +SD\sphinxhyphen{}RAN and disaggregated Mobile Core components described +throughout this book. Aether includes a centralized operations +portal running in the Public Cloud.}\label{\detokenize{cloud:id3}}\label{\detokenize{cloud:fig-aether}}\end{figure} + +\sphinxAtStartPar +Note that each edge site in \hyperref[\detokenize{cloud:fig-aether}]{Figure \ref{\detokenize{cloud:fig-aether}}} +corresponds to a CORD POD described in Chapter 6, re\sphinxhyphen{}configured to +offload the O\&M Interface and the Control elements of the Mobile Core +to the central cloud. + +\phantomsection\label{\detokenize{cloud:reading-aether}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +For more information about Aether, visit the \sphinxhref{https://www.opennetworking.org/aether/}{Aether Web Site}. ONF, March 2020. +\end{sphinxadmonition} + + +\section{7.3 Research Opportunities} +\label{\detokenize{cloud:research-opportunities}} +\sphinxAtStartPar +In order for the scenarios described in this Chapter to become a +reality, a wealth of research problems need to be addressed, many of +which are a consequence of the blurring line between access networks +and the edge cloud. We refer to this as the \sphinxstyleemphasis{access\sphinxhyphen{}edge}, and we +conclude by identifying some example challenges/opportunities. +\begin{itemize} +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Multi\sphinxhyphen{}Access:} The access\sphinxhyphen{}edge will need to support multiple +access technologies (e.g., WiFi, 5G, fiber), and allow users to +seamlessly move between them. Research is needed to break down +existing technology silos, and design converged solutions to common +problems (e.g., security, mobility, QoS). + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Heterogeneity:} Since the access\sphinxhyphen{}edge will be about low\sphinxhyphen{}latency +and high\sphinxhyphen{}bandwidth connectivity, much edge functionality will be +implemented by programming the forwarding pipeline in white\sphinxhyphen{}box +switches, and more generally, will use other domain\sphinxhyphen{}specific +processors (e.g., GPUs, TPUs). Research is needed to tailor edge +services to take advantage of heterogeneous resources, as well as +how to construct end\sphinxhyphen{}to\sphinxhyphen{}end applications from such a collection of +building blocks. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Virtualization:} The access\sphinxhyphen{}edge will virtualize the underlying +hardware using a range of techniques, from VMs to containers to +serverless functions, interconnected by a range of L2, L3, and L4/7 virtual +networks, some of which will be managed by SDN control +applications. Research is needed to reconcile the assumptions made +about by cloud native services and access\sphinxhyphen{}oriented Virtualized +Network Functions (VNFs) about how to virtualize compute, storage, +and networking resources. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Multi\sphinxhyphen{}Tenancy:} The access\sphinxhyphen{}edge will be multi\sphinxhyphen{}tenant, with +potentially different stakeholders (operators, service providers, +application developers, enterprises) responsible for managing +different components. It will not be feasible to run the entire +access\sphinxhyphen{}edge in a single trust domain, as different components will +operate with different levels of autonomy. Research is needed to +minimize the overhead isolation imposes on tenants. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Customization:} Monetizing the access\sphinxhyphen{}edge will require the +ability to offer differentiated and customized services to different +classes of subscribers/applications. Sometimes called network +slicing (see Section 5.3), this involves support for performance isolation at the +granularity of service chains—the sequence of functional elements +running on behalf of some subscriber. Research is needed to enforce +performance isolation in support of service guarantees. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Near\sphinxhyphen{}Real Time:} The access\sphinxhyphen{}edge will be a highly dynamic +environment, with functionality constantly adapting in response to +mobility, workload, and application requirements. Supporting such an +environment requires tight control loops, with control software +running at the edge. Research is needed to analyze control loops, +define analytic\sphinxhyphen{}based controllers, and design dynamically adaptable +mechanisms. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Data Reduction:} The access\sphinxhyphen{}edge will connect an increasing +number of devices (not just humans and their handsets), all of which +are capable of generating data. Supporting data reduction will be +critical, which implies the need for substantial compute capacity +(likely including domain\sphinxhyphen{}specific processors) to be available in the +access\sphinxhyphen{}edge. Research is needed to refactor applications into their +edge\sphinxhyphen{}reduction/backend\sphinxhyphen{}analysis subcomponents. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Distributed Services:} Services will become inherently +distributed, with some aspects running at the access\sphinxhyphen{}edge, some +aspects running in the datacenter, and some running on\sphinxhyphen{}premises or +in an end device (e.g., on\sphinxhyphen{}vehicle). Supporting such an environment +requires a multi\sphinxhyphen{}cloud solution that is decoupled from any single +infrastructure\sphinxhyphen{}based platform, with research needed to develop +heuristics for function placement. + +\item {} +\sphinxAtStartPar +\sphinxstylestrong{Scalability:} The access\sphinxhyphen{}edge will potentially span thousands or +even tens of thousands of edge sites. Scaling up the ability to +remotely orchestrate that many edge sites (even at just the +infrastructure level) will be a qualitatively different challenge +than managing a single datacenter. Research is needed to scale both +the edge platform and widely deployed edge services. + +\end{itemize} +\phantomsection\label{\detokenize{cloud:reading-democratizing}} +\begin{sphinxadmonition}{note}{Further Reading} + +\sphinxAtStartPar +To better understand the research opportunity at the access\sphinxhyphen{}edge, +see \sphinxhref{https://ccronline.sigcomm.org/wp-content/uploads/2019/05/acmdl19-289.pdf}{Democratizing the Network Edge}. +ACM SIGCOMM CCR, April 2019. +\end{sphinxadmonition} + + +\chapter{About The Book} +\label{\detokenize{README:about-the-book}}\label{\detokenize{README::doc}} +\sphinxAtStartPar +Source for \sphinxstyleemphasis{5G Mobile Networks: A Systems Approach} is available on +GitHub under +terms of the \sphinxhref{https://creativecommons.org/licenses/by-nc-nd/4.0}{Creative Commons (CC BY\sphinxhyphen{}NC\sphinxhyphen{}ND 4.0)} license. The +community is invited to contribute corrections, improvements, updates, +and new material under the same terms. While this license does not +automatically grant the right to make derivative works, we are keen to +discuss derivative works (such as translations) with interested +parties. Please reach out to \sphinxhref{mailto:discuss@systemsapproach.org}{discuss@systemsapproach.org}. + +\sphinxAtStartPar +If you make use of this work, the attribution should include the +following information: + +\begin{DUlineblock}{0em} +\item[] \sphinxstyleemphasis{Title: 5G Mobile Networks: A Systems Approach} +\item[] \sphinxstyleemphasis{Authors: Larry Peterson and Oguz Sunay} +\item[] \sphinxstyleemphasis{Source:} \sphinxurl{https://github.com/SystemsApproach/5G} +\item[] \sphinxstyleemphasis{License:} \sphinxhref{https://creativecommons.org/licenses/by-nc-nd/4.0}{CC BY\sphinxhyphen{}NC\sphinxhyphen{}ND 4.0} +\end{DUlineblock} + + +\section{Read the Book} +\label{\detokenize{README:read-the-book}} +\sphinxAtStartPar +This book is part of the \sphinxhref{https://www.systemsapproach.org}{Systems Approach Series}, with an online version published at +\sphinxhref{https://5g.systemsapproach.org}{https://5G.systemsapproach.org}. + +\sphinxAtStartPar +To track progress and receive notices about new versions, you can follow +the project on +\sphinxhref{https://www.facebook.com/Computer-Networks-A-Systems-Approach-110933578952503/}{Facebook} +and \sphinxhref{https://twitter.com/SystemsAppr}{Twitter}. To read a running +commentary on how the Internet is evolving, follow the \sphinxhref{https://systemsapproach.substack.com}{Systems Approach +on Substack}. + + +\section{Build the Book} +\label{\detokenize{README:build-the-book}} +\sphinxAtStartPar +To build a web\sphinxhyphen{}viewable version, you first need to download the source: + +\begin{sphinxVerbatim}[commandchars=\\\{\}] +\PYGZdl{} mkdir \PYGZti{}/systemsapproach +\PYGZdl{} cd \PYGZti{}/systemsapproach +\PYGZdl{} git clone https://github.com/SystemsApproach/5G.git +\PYGZdl{} cd 5G +\end{sphinxVerbatim} + +\sphinxAtStartPar +The build process is stored in the Makefile and requires Python be +installed. The Makefile will create a virtualenv (\sphinxcode{\sphinxupquote{venv\sphinxhyphen{}docs}}) which +installs the documentation generation toolset. You may also need to +install the \sphinxcode{\sphinxupquote{enchant}} C library using your system’s package manager +for the spelling checker to function properly. + +\sphinxAtStartPar +To generate HTML in \sphinxcode{\sphinxupquote{\_build/html}}, run \sphinxcode{\sphinxupquote{make html}}. + +\sphinxAtStartPar +To check the formatting of the book, run \sphinxcode{\sphinxupquote{make lint}}. + +\sphinxAtStartPar +To check spelling, run \sphinxcode{\sphinxupquote{make spelling}}. If there are additional +words, names, or acronyms that are correctly spelled but not in the dictionary, +please add them to the \sphinxcode{\sphinxupquote{dict.txt}} file. + +\sphinxAtStartPar +To see the other available output formats, run \sphinxcode{\sphinxupquote{make}}. + + +\section{Contribute to the Book} +\label{\detokenize{README:contribute-to-the-book}} +\sphinxAtStartPar +We hope that if you use this material, you are also willing to +contribute back to it. If you are new to open source, you might check +out this \sphinxhref{https://opensource.guide/how-to-contribute/}{How to Contribute to Open +Source} guide. Among +other things, you’ll learn about posting \sphinxstyleemphasis{Issues} that you’d like to see +addressed, and issuing \sphinxstyleemphasis{Pull Requests} to merge your improvements back +into GitHub. + +\sphinxAtStartPar +If you’d like to contribute and are looking for something that needs +attention, see the \sphinxhref{https://github.com/SystemsApproach/5G/wiki}{wiki} +for the current TODO list. + + +\chapter{About The Authors} +\label{\detokenize{authors:about-the-authors}}\label{\detokenize{authors::doc}} +\sphinxAtStartPar +\sphinxstylestrong{Larry Peterson} is the Robert E. Kahn Professor of Computer +Science, Emeritus at Princeton University, where he served as Chair +from 2003\sphinxhyphen{}2009. He is a co\sphinxhyphen{}author of the best selling networking +textbook \sphinxstyleemphasis{Computer Networks: A Systems Approach (6e)}, which is now +available as open source on GitHub. His research focuses on the +design, implementation, and operation of Internet\sphinxhyphen{}scale distributed +systems, including the widely used PlanetLab and MeasurementLab +platforms. He is currently leading the CORD and Aether access\sphinxhyphen{}edge +cloud projects at the Open Networking Foundation (ONF), where he +serves CTO. Professor Peterson is a member of the National Academy of +Engineering, a Fellow of the ACM and the IEEE, the 2010 recipient of +the IEEE Kobayashi Computer and Communication Award, and the 2013 +recipient of the ACM SIGCOMM Award. He received his Ph.D. degree from +Purdue University in 1985. + +\sphinxAtStartPar +\sphinxstylestrong{Oguz Sunay} is currently the Vice President for Research \& +Development at ONF, where he leads all mobile\sphinxhyphen{}related projects. Prior +to that, he served as the Chief Architect for Mobile Networking at +ONF. Before joining ONF, Sunay was the CTO at Argela\sphinxhyphen{}USA, where he was +the innovator of a Programmable Radio Access Network Architecture +(ProgRAN) for 5G that enabled the world’s first dynamically +programmable RAN slicing solution. He has also held prior industry +positions at Nokia Research Center and Bell Laboratories, where he +focused on 3G and 4G end\sphinxhyphen{}to\sphinxhyphen{}end systems architectures and participated +and chaired various standardization activities. Sunay has also spent +over 10 years in academia, as a Professor of Electrical and Computer +Engineering. He holds many U.S. and European patents on various +aspects of 3G, 4G, and 5G, and has authored numerous journal and +conference publications. He received his Ph.D. and M.Sc. from Queen’s +University, Canada, and his B.Sc.Hon. from METU, Turkey. + + +\chapter{Read the Latest!} +\label{\detokenize{latest:read-the-latest}}\label{\detokenize{latest::doc}} +\sphinxAtStartPar +\sphinxhref{https://systemsapproach.substack.com/}{Substack Newsletter:} Stay +up\sphinxhyphen{}to\sphinxhyphen{}date with the latest developments by following the authors on +\sphinxhref{https://systemsapproach.substack.com/}{Substack}, where they +connect the concepts and lessons in this book to what’s happening in +the Internet today. + +\sphinxAtStartPar +\sphinxhref{https://systemsapproach.org/books/}{Book Series:} Also check out +our companion books that cover emerging topics in more depth. +\begin{itemize} +\item {} +\sphinxAtStartPar +\sphinxhref{https://sdn.systemsapproach.org}{Software\sphinxhyphen{}Defined Networks: A Systems Approach} + +\item {} +\sphinxAtStartPar +\sphinxhref{https://tcpcc.systemsapproach.org}{TCP Congestion Control: A Systems Approach} + +\item {} +\sphinxAtStartPar +\sphinxhref{https://ops.systemsapproach.org}{Edge Cloud Operations: A Systems Approach} + +\end{itemize} + + +\chapter{Print Copies} +\label{\detokenize{print:print-copies}}\label{\detokenize{print::doc}} +\sphinxAtStartPar +We make all books in the \sphinxstyleemphasis{Systems Approach} series available as both +print and e\sphinxhyphen{}books. This book is available via Amazon: \sphinxhref{https://amzn.to/3EjwMH0}{5G Mobile Networks: A Systems Approach} + +\sphinxAtStartPar +\sphinxhref{https://systemsapproach.org/books/}{Book Series:} Also check out +our companion books that cover networking and emerging topics in more depth. +\begin{itemize} +\item {} +\sphinxAtStartPar +\sphinxhref{https://amzn.to/3CtG81U}{Computer Networks: A Systems Approach} + +\item {} +\sphinxAtStartPar +\sphinxhref{https://amzn.to/3rmLdCP}{Software\sphinxhyphen{}Defined Networks: A Systems Approach} + +\item {} +\sphinxAtStartPar +\sphinxhref{https://amzn.to/3UTYi3T}{TCP Congestion Control: A Systems Approach} + +\item {} +\sphinxAtStartPar +\sphinxhref{https://amzn.to/3MfvK13}{Edge Cloud Operations: A Systems Approach} + +\end{itemize} + +\sphinxAtStartPar +As participants in the Amazon Associate program we may earn income from qualifying purchases using the links above. + + + +\renewcommand{\indexname}{Index} +\printindex +\end{document} \ No newline at end of file diff --git a/latexmkjarc b/latexmkjarc new file mode 100644 index 0000000..6e36b19 --- /dev/null +++ b/latexmkjarc @@ -0,0 +1,22 @@ +$latex = 'pdflatex ' . $ENV{'LATEXOPTS'} . ' -kanji=utf8 %O %S'; +$dvipdf = 'dvipdfmx %O -o %D %S'; +$makeindex = 'internal mendex %S %B %D'; +sub mendex { + my ($source, $basename, $destination) = @_; + my $dictfile = $basename . ".dic"; + unlink($destination); + system("mendex", "-U", "-f", "-d", $dictfile, "-s", "python.ist", $source); + if ($? > 0) { + print("mendex exited with error code $? (ignored)\n"); + } + if (!-e $destination) { + # create an empty .ind file if nothing + open(FH, ">" . $destination); + close(FH); + } + return 0; +} +add_cus_dep( "glo", "gls", 0, "makeglo" ); +sub makeglo { + return system( "mendex -J -f -s gglo.ist -o '$_[0].gls' '$_[0].glo'" ); +} \ No newline at end of file diff --git a/latexmkrc b/latexmkrc new file mode 100644 index 0000000..bba17fa --- /dev/null +++ b/latexmkrc @@ -0,0 +1,9 @@ +$latex = 'latex ' . $ENV{'LATEXOPTS'} . ' %O %S'; +$pdflatex = 'pdflatex ' . $ENV{'LATEXOPTS'} . ' %O %S'; +$lualatex = 'lualatex ' . $ENV{'LATEXOPTS'} . ' %O %S'; +$xelatex = 'xelatex --no-pdf ' . $ENV{'LATEXOPTS'} . ' %O %S'; +$makeindex = 'makeindex -s python.ist %O -o %D %S'; +add_cus_dep( "glo", "gls", 0, "makeglo" ); +sub makeglo { + return system( "makeindex -s gglo.ist -o '$_[0].gls' '$_[0].glo'" ); +} \ No newline at end of file diff --git a/make.bat b/make.bat new file mode 100644 index 0000000..94bda21 --- /dev/null +++ b/make.bat @@ -0,0 +1,31 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +pushd %~dp0 + +set PDFLATEX=latexmk -pdf -dvi- -ps- + +set "LATEXOPTS= " + +if "%1" == "" goto all-pdf + +if "%1" == "all-pdf" ( + :all-pdf + for %%i in (*.tex) do ( + %PDFLATEX% %LATEXMKOPTS% %%i + ) + goto end +) + +if "%1" == "all-pdf-ja" ( + goto all-pdf +) + +if "%1" == "clean" ( + del /q /s *.dvi *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla *.ps *.tar *.tar.gz *.tar.bz2 *.tar.xz *.fls *.fdb_latexmk + goto end +) + +:end +popd \ No newline at end of file diff --git a/python.ist b/python.ist new file mode 100644 index 0000000..70536a6 --- /dev/null +++ b/python.ist @@ -0,0 +1,16 @@ +line_max 100 +headings_flag 1 +heading_prefix " \\bigletter " + +preamble "\\begin{sphinxtheindex} +\\let\\bigletter\\sphinxstyleindexlettergroup +\\let\\spxpagem \\sphinxstyleindexpagemain +\\let\\spxentry \\sphinxstyleindexentry +\\let\\spxextra \\sphinxstyleindexextra + +" + +postamble "\n\n\\end{sphinxtheindex}\n" + +symhead_positive "{\\sphinxsymbolsname}" +numhead_positive "{\\sphinxnumbersname}" diff --git a/sphinx.sty b/sphinx.sty new file mode 100644 index 0000000..4d42199 --- /dev/null +++ b/sphinx.sty @@ -0,0 +1,351 @@ +% +% sphinx.sty +% +% Adapted from the old python.sty, mostly written by Fred Drake, +% by Georg Brandl. +% + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesPackage{sphinx}[2021/01/27 v4.0.0 LaTeX package (Sphinx markup)] + +% provides \ltx@ifundefined +% (many packages load ltxcmds: graphicx does for pdftex and lualatex but +% not xelatex, and anyhow kvoptions does, but it may be needed in future to +% use \sphinxdeprecationwarning earlier, and it needs \ltx@ifundefined) +\RequirePackage{ltxcmds} + +%% for deprecation warnings +\newcommand\sphinxdeprecationwarning[4]{% #1 the deprecated macro or name, +% #2 = when deprecated, #3 = when removed, #4 = additional info + \edef\spx@tempa{\detokenize{#1}}% + \ltx@ifundefined{sphinx_depr_\spx@tempa}{% + \global\expandafter\let\csname sphinx_depr_\spx@tempa\endcsname\spx@tempa + \expandafter\AtEndDocument\expandafter{\expandafter\let\expandafter + \sphinxdeprecatedmacro\csname sphinx_depr_\spx@tempa\endcsname + \PackageWarningNoLine{sphinx}{^^J**** SPHINX DEPRECATION WARNING:^^J + \sphinxdeprecatedmacro^^J + \@spaces- is deprecated at Sphinx #2^^J + \@spaces- and removed at Sphinx #3.^^J + #4^^J****}}% + }{% warning already emitted (at end of latex log), don't repeat + }} + + +%% OPTION HANDLING +% + +% We first handle options then load packages, but we need \definecolor from +% xcolor/color. + +% FIXME: we should \RequirePackage{xcolor} always now +% The xcolor package draws better fcolorboxes around verbatim code +\IfFileExists{xcolor.sty}{ + \RequirePackage{xcolor} +}{ + \RequirePackage{color} +} + +% Handle options via "kvoptions" (later loaded by hyperref anyhow) +\RequirePackage{kvoptions} +\SetupKeyvalOptions{prefix=spx@opt@} % use \spx@opt@ prefix + +% Sphinx legacy text layout: 1in margins on all four sides +\ifx\@jsc@uplatextrue\@undefined +\DeclareStringOption[1in]{hmargin} +\DeclareStringOption[1in]{vmargin} +\DeclareStringOption[.5in]{marginpar} +\else +% Japanese standard document classes handle \mag in a special way +\DeclareStringOption[\inv@mag in]{hmargin} +\DeclareStringOption[\inv@mag in]{vmargin} +\DeclareStringOption[.5\dimexpr\inv@mag in\relax]{marginpar} +\fi + +\DeclareStringOption[0]{maxlistdepth}% \newcommand*\spx@opt@maxlistdepth{0} +\DeclareStringOption[-1]{numfigreset} +\DeclareBoolOption[false]{nonumfigreset} +\DeclareBoolOption[false]{mathnumfig} +\define@key{sphinx}{bookmarksdepth}{\AtBeginDocument{\hypersetup{bookmarksdepth=#1}}} +\AtBeginDocument{\define@key{sphinx}{bookmarksdepth}{\hypersetup{bookmarksdepth=#1}}} +% \DeclareBoolOption[false]{usespart}% not used +% dimensions, we declare the \dimen registers here. +\newdimen\sphinxverbatimsep +\newdimen\sphinxverbatimborder +\newdimen\sphinxshadowsep +\newdimen\sphinxshadowsize +\newdimen\sphinxshadowrule +% \DeclareStringOption is not convenient for the handling of these dimensions +% because we want to assign the values to the corresponding registers. Even if +% we added the code to the key handler it would be too late for the initial +% set-up and we would need to do initial assignments explicitly. We end up +% using \define@key directly. +% verbatim +\sphinxverbatimsep=\fboxsep + \define@key{sphinx}{verbatimsep}{\sphinxverbatimsep\dimexpr #1\relax} +\sphinxverbatimborder=\fboxrule + \define@key{sphinx}{verbatimborder}{\sphinxverbatimborder\dimexpr #1\relax} +% topic boxes +\sphinxshadowsep =5pt + \define@key{sphinx}{shadowsep}{\sphinxshadowsep\dimexpr #1\relax} +\sphinxshadowsize=4pt + \define@key{sphinx}{shadowsize}{\sphinxshadowsize\dimexpr #1\relax} +\sphinxshadowrule=\fboxrule + \define@key{sphinx}{shadowrule}{\sphinxshadowrule\dimexpr #1\relax} +% verbatim +\DeclareBoolOption[true]{verbatimwithframe} +\DeclareBoolOption[true]{verbatimwrapslines} +\DeclareBoolOption[false]{verbatimforcewraps} +\DeclareStringOption[3]{verbatimmaxoverfull} +\DeclareStringOption[100]{verbatimmaxunderfull} +\DeclareBoolOption[true]{verbatimhintsturnover} +\DeclareBoolOption[true]{inlineliteralwraps} +\DeclareStringOption[t]{literalblockcappos} +\DeclareStringOption[r]{verbatimcontinuedalign} +\DeclareStringOption[r]{verbatimcontinuesalign} +% parsed literal +\DeclareBoolOption[true]{parsedliteralwraps} +% \textvisiblespace for compatibility with fontspec+XeTeX/LuaTeX +\DeclareStringOption[\textcolor{red}{\textvisiblespace}]{verbatimvisiblespace} +\DeclareStringOption % must use braces to hide the brackets + [{\makebox[2\fontcharwd\font`\x][r]{\textcolor{red}{\tiny$\m@th\hookrightarrow$}}}]% + {verbatimcontinued} +% notices/admonitions +% the dimensions for notices/admonitions are kept as macros and assigned to +% \spx@notice@border at time of use, hence \DeclareStringOption is ok for this +\newdimen\spx@notice@border +\DeclareStringOption[0.5pt]{noteborder} +\DeclareStringOption[0.5pt]{hintborder} +\DeclareStringOption[0.5pt]{importantborder} +\DeclareStringOption[0.5pt]{tipborder} +\DeclareStringOption[1pt]{warningborder} +\DeclareStringOption[1pt]{cautionborder} +\DeclareStringOption[1pt]{attentionborder} +\DeclareStringOption[1pt]{dangerborder} +\DeclareStringOption[1pt]{errorborder} +% footnotes +\DeclareStringOption[\mbox{ }]{AtStartFootnote} +% we need a public macro name for direct use in latex file +\newcommand*{\sphinxAtStartFootnote}{\spx@opt@AtStartFootnote} +% no such need for this one, as it is used inside other macros +\DeclareStringOption[\leavevmode\unskip]{BeforeFootnote} +% some font styling. +\DeclareStringOption[\sffamily\bfseries]{HeaderFamily} +% colours +% same problems as for dimensions: we want the key handler to use \definecolor. +% first, some colours with no prefix, for backwards compatibility +\newcommand*{\sphinxDeclareColorOption}[2]{% + \definecolor{#1}#2% + \define@key{sphinx}{#1}{\definecolor{#1}##1}% +}% +\sphinxDeclareColorOption{TitleColor}{{rgb}{0.126,0.263,0.361}} +\sphinxDeclareColorOption{InnerLinkColor}{{rgb}{0.208,0.374,0.486}} +\sphinxDeclareColorOption{OuterLinkColor}{{rgb}{0.216,0.439,0.388}} +\sphinxDeclareColorOption{VerbatimColor}{{rgb}{1,1,1}} +\sphinxDeclareColorOption{VerbatimBorderColor}{{rgb}{0,0,0}} +% now the colours defined with "sphinx" prefix in their names +\newcommand*{\sphinxDeclareSphinxColorOption}[2]{% + % set the initial default + \definecolor{sphinx#1}#2% + % set the key handler. The "value" ##1 must be acceptable by \definecolor. + \define@key{sphinx}{#1}{\definecolor{sphinx#1}##1}% +}% +% Default color chosen to be as in minted.sty LaTeX package! +\sphinxDeclareSphinxColorOption{VerbatimHighlightColor}{{rgb}{0.878,1,1}} +% admonition boxes, "light" style +\sphinxDeclareSphinxColorOption{noteBorderColor}{{rgb}{0,0,0}} +\sphinxDeclareSphinxColorOption{hintBorderColor}{{rgb}{0,0,0}} +\sphinxDeclareSphinxColorOption{importantBorderColor}{{rgb}{0,0,0}} +\sphinxDeclareSphinxColorOption{tipBorderColor}{{rgb}{0,0,0}} +% admonition boxes, "heavy" style +\sphinxDeclareSphinxColorOption{warningBorderColor}{{rgb}{0,0,0}} +\sphinxDeclareSphinxColorOption{cautionBorderColor}{{rgb}{0,0,0}} +\sphinxDeclareSphinxColorOption{attentionBorderColor}{{rgb}{0,0,0}} +\sphinxDeclareSphinxColorOption{dangerBorderColor}{{rgb}{0,0,0}} +\sphinxDeclareSphinxColorOption{errorBorderColor}{{rgb}{0,0,0}} +\sphinxDeclareSphinxColorOption{warningBgColor}{{rgb}{1,1,1}} +\sphinxDeclareSphinxColorOption{cautionBgColor}{{rgb}{1,1,1}} +\sphinxDeclareSphinxColorOption{attentionBgColor}{{rgb}{1,1,1}} +\sphinxDeclareSphinxColorOption{dangerBgColor}{{rgb}{1,1,1}} +\sphinxDeclareSphinxColorOption{errorBgColor}{{rgb}{1,1,1}} + +\DeclareDefaultOption{\@unknownoptionerror} +\ProcessKeyvalOptions* +% don't allow use of maxlistdepth via \sphinxsetup. +\DisableKeyvalOption{sphinx}{maxlistdepth} +\DisableKeyvalOption{sphinx}{numfigreset} +\DisableKeyvalOption{sphinx}{nonumfigreset} +\DisableKeyvalOption{sphinx}{mathnumfig} +% FIXME: this is unrelated to an option, move this elsewhere +% To allow hyphenation of first word in narrow contexts; no option, +% customization to be done via 'preamble' key +\newcommand*\sphinxAtStartPar{\leavevmode\nobreak\hskip\z@skip} +% No need for the \hspace{0pt} trick (\hskip\z@skip) with luatex +\ifdefined\directlua\let\sphinxAtStartPar\@empty\fi +% user interface: options can be changed midway in a document! +\newcommand\sphinxsetup[1]{\setkeys{sphinx}{#1}} + + +%% MISCELLANEOUS CONTEXT +% +% flag to be set in a framed environment +% (defined here as currently needed by three sphinxlatex....sty files and +% even if not needed if such files are replaced, the definition does no harm) +\newif\ifspx@inframed +% +% \spx@ifcaptionpackage (defined at begin document) +% is needed currently in macros from: +% sphinxlatexliterals.sty (sphinxVerbatim) +% sphinxlatextables.sty (for some macros used in the table templates) +% +% \sphinxcaption is mark-up injected by the tabular and tabulary templates +% it is defined in sphinxlatextables.sty +% +% store the original \caption macro for usage with figures inside longtable +% and tabulary cells. Make sure we get the final \caption in presence of +% caption package, whether the latter was loaded before or after sphinx. +\AtBeginDocument{% + \let\spx@originalcaption\caption + \@ifpackageloaded{caption} + {\let\spx@ifcaptionpackage\@firstoftwo + \caption@AtBeginDocument*{\let\spx@originalcaption\caption}% +% in presence of caption package, drop our own \sphinxcaption whose aim was to +% ensure same width of caption to all kinds of tables (tabular(y), longtable), +% because caption package has its own width (or margin) option + \def\sphinxcaption{\caption}% + }% + {\let\spx@ifcaptionpackage\@secondoftwo}% +} + +%% PASS OPTIONS +% +% pass options to hyperref; it must not have been loaded already +\input{sphinxoptionshyperref.sty} +% pass options to geometry; it must not have been loaded already +\input{sphinxoptionsgeometry.sty} + + +%% COLOR (general) +% +% FIXME: these two should be deprecated +% +% FIXME: \normalcolor should be used and \py@NormalColor never defined +\def\py@NormalColor{\color{black}} +% FIXME: \color{TitleColor} should be used directly and \py@TitleColor +% should never get defined. +\def\py@TitleColor{\color{TitleColor}} + + +%% PACKAGES +% +% as will be indicated below, secondary style files load some more packages +% +% For \text macro (sphinx.util.texescape) +% also for usage of \firstchoice@true(false) in sphinxlatexgraphics.sty +\RequirePackage{amstext} +% It was passed "warn" option from latex template in case it is already loaded +% via some other package before \usepackage{sphinx} in preamble +\RequirePackage{textcomp} +% For the H specifier. Do not \restylefloat{figure}, it breaks Sphinx code +% for allowing figures in tables. +\RequirePackage{float} +% For floating figures in the text. Better to load after float. +\RequirePackage{wrapfig} +% Provides \captionof, used once by latex writer (\captionof{figure}) +\RequirePackage{capt-of} +% Support hlist directive +\RequirePackage{multicol} + + +%% GRAPHICS +% +% It will always be needed, so let's load it here +\RequirePackage{graphicx} +\input{sphinxlatexgraphics.sty} + + +%% FRAMED ENVIRONMENTS +% +\input{sphinxlatexadmonitions.sty} +\input{sphinxlatexliterals.sty} +\input{sphinxlatexshadowbox.sty} + + +%% CONTAINERS +% +\input{sphinxlatexcontainers.sty} + + +%% PYGMENTS +% stylesheet for highlighting with pygments +\RequirePackage{sphinxhighlight} + + +%% TABLES +% +\input{sphinxlatextables.sty} + + +%% NUMBERING OF FIGURES, TABLES, AND LITERAL BLOCKS +% +\input{sphinxlatexnumfig.sty} + + +%% LISTS +% +\input{sphinxlatexlists.sty} + + +%% FOOTNOTES +% +% Support scopes for footnote numbering +\newcounter{sphinxscope} +\newcommand{\sphinxstepscope}{\stepcounter{sphinxscope}} +% Explicitly numbered footnotes may be referred to, and for this to be +% clickable we need to have only one target. So we will step this at each +% explicit footnote and let \thesphinxscope take it into account +\newcounter{sphinxexplicit} +\newcommand{\sphinxstepexplicit}{\stepcounter{sphinxexplicit}} +% Some babel/polyglossia languages fiddle with \@arabic, so let's be extra +% cautious and redefine \thesphinxscope with \number not \@arabic. +% Memo: we expect some subtle redefinition of \thesphinxscope to be a part of page +% scoping for footnotes, when we shall implement it. +\renewcommand{\thesphinxscope}{\number\value{sphinxscope}.\number\value{sphinxexplicit}} +\newcommand\sphinxthefootnotemark[2]{% + % this is used to make reference to an explicitly numbered footnote not on same page + % #1=label of footnote text, #2=page number where footnote text was printed + \ifdefined\pagename + \pagename\space#2, % <- space + \else + p. #2, % <- space + \fi #1% no space +} +% support large numbered footnotes in minipage; but this is now obsolete +% from systematic use of savenotes environment around minipages +\def\thempfootnote{\arabic{mpfootnote}} +% This package is needed to support hyperlinked footnotes in tables and +% framed contents, and to allow code-blocks in footnotes. +\RequirePackage{sphinxpackagefootnote} + + +%% INDEX, BIBLIOGRAPHY, APPENDIX, TABLE OF CONTENTS +% +\input{sphinxlatexindbibtoc.sty} + + +%% STYLING +% +\input{sphinxlatexstylepage.sty} +\input{sphinxlatexstyleheadings.sty} +\input{sphinxlatexstyletext.sty} + + +%% MODULE RELEASE DATA AND OBJECT DESCRIPTIONS +% +\input{sphinxlatexobjects.sty} + + +% FIXME: this line should be dropped, as "9" is default anyhow. +\ifdefined\pdfcompresslevel\pdfcompresslevel = 9 \fi + + +\endinput diff --git a/sphinx.xdy b/sphinx.xdy new file mode 100644 index 0000000..0dcf113 --- /dev/null +++ b/sphinx.xdy @@ -0,0 +1,230 @@ +;;; -*- mode: lisp; coding: utf-8; -*- + +;; Unfortunately xindy is out-of-the-box hyperref-incompatible. This +;; configuration is a workaround, which requires to pass option +;; hyperindex=false to hyperref. +;; textit and emph not currently used, spxpagem replaces former textbf +(define-attributes (("textbf" "textit" "emph" "spxpagem" "default"))) +(markup-locref :open "\textbf{\hyperpage{" :close "}}" :attr "textbf") +(markup-locref :open "\textit{\hyperpage{" :close "}}" :attr "textit") +(markup-locref :open "\emph{\hyperpage{" :close "}}" :attr "emph") +(markup-locref :open "\spxpagem{\hyperpage{" :close "}}" :attr "spxpagem") +(markup-locref :open "\hyperpage{" :close "}" :attr "default") + +(require "numeric-sort.xdy") + +;; xindy base module latex.xdy loads tex.xdy and the latter instructs +;; xindy to ignore **all** TeX macros in .idx entries, except those +;; explicitly described in merge rule. But when after applying all +;; merge rules an empty string results, xindy raises an error: + +;; ERROR: CHAR: index 0 should be less than the length of the string + +;; For example when using pdflatex with utf-8 characters the index +;; file will contain \IeC macros and they will get ignored except if +;; suitable merge rules are loaded early. The texindy script coming +;; with xindy provides this, but only for Latin scripts. The texindy +;; man page says to use rather xelatex or lualatex in case of Cyrillic +;; scripts. + +;; Sphinx contributes LICRcyr2utf8.xdy to provide support for Cyrillic +;; scripts for the pdflatex engine. + +;; Another issue caused by xindy ignoring all TeX macros except those +;; explicitly declared reveals itself when attempting to index ">>>", +;; as the ">" is converted to "\textgreater{}" by Sphinx's LaTeX +;; escaping. + +;; To fix this, Sphinx does **not** use texindy, and does not even +;; load the xindy latex.xdy base module. + +;(require "latex.xdy") + +;; Rather it incorporates some suitable extracts from latex.xdy and +;; tex.xdy with additional Sphinx contributed rules. + +;; But, this means for pdflatex and Latin scripts that the xindy file +;; tex/inputenc/uf8.xdy is not usable because it refers to the macro +;; \IeC only sporadically, and as tex.xdy is not loaded, a rule such as +;; (merge-rule "\'e" "é" :string) +;; does not work, it must be +;; (merge-rule "\IeC {\'e}" "é" :string) +;; So Sphinx contributes LICRlatin2utf8.xdy to mitigate that problem. + +;;;;;;;; extracts from tex.xdy (discarding most original comments): + +;;; +;;; TeX conventions +;;; + +;; Discard leading and trailing white space. Collapse multiple white +;; space characters to blank. + +(merge-rule "^ +" "" :eregexp) +(merge-rule " +$" "" :eregexp) +(merge-rule " +" " " :eregexp) + +;; Handle TeX markup + +(merge-rule "\\([{}$%&#])" "\1" :eregexp) + +;;;;;;;; end of extracts from xindy's tex.xdy + +;;;;;;;; extracts from latex.xdy: + +;; Standard location classes: arabic and roman numbers, and alphabets. + +(define-location-class "arabic-page-numbers" ("arabic-numbers")) +(define-location-class "roman-page-numbers" ("roman-numbers-lowercase")) +(define-location-class "Roman-page-numbers" ("roman-numbers-uppercase")) +(define-location-class "alpha-page-numbers" ("alpha")) +(define-location-class "Alpha-page-numbers" ("ALPHA")) + +;; Output Markup + +(markup-letter-group-list :sep "~n~n \indexspace~n") + +(markup-indexentry :open "~n \item " :depth 0) +(markup-indexentry :open "~n \subitem " :depth 1) +(markup-indexentry :open "~n \subsubitem " :depth 2) + +(markup-locclass-list :open ", " :sep ", ") +(markup-locref-list :sep ", ") + +;;;;;;;; end of extracts from latex.xdy + +;; The LaTeX \index command turns \ into normal character so the TeX macros +;; written to .idx files are not followed by a blank. This is different +;; from non-ascii letters which end up (with pdflatex) as \IeC macros in .idx +;; file, with a blank space after \IeC + +;; Details of the syntax are explained at +;; http://xindy.sourceforge.net/doc/manual-3.html +;; In absence of :string, "xindy uses an auto-detection mechanism to decide, +;; if the pattern is a regular expression or not". But it is not obvious to +;; guess, for example "\\_" is not detected as RE but "\\P\{\}" is, so for +;; being sure we apply the :string switch everywhere and do not use \\ etc... + +;; Go back from sphinx.util.texescape TeX macros to UTF-8 + +(merge-rule "\sphinxleftcurlybrace{}" "{" :string) +(merge-rule "\sphinxrightcurlybrace{}" "}" :string) +(merge-rule "\_" "_" :string) +(merge-rule "{[}" "[" :string) +(merge-rule "{]}" "]" :string) +(merge-rule "\textbackslash{}" "\" :string) ; " for Emacs syntax highlighting +(merge-rule "\textasciitilde{}" "~~" :string); the ~~ escape is needed here +(merge-rule "\textasciicircum{}" "^" :string) +(merge-rule "\sphinxhyphen{}" "-" :string) +(merge-rule "\textquotesingle{}" "'" :string) +(merge-rule "\textasciigrave{}" "`" :string) +(merge-rule "\textless{}" "<" :string) +(merge-rule "\textgreater{}" ">" :string) +(merge-rule "\P{}" "¶" :string) +(merge-rule "\S{}" "§" :string) +(merge-rule "\texteuro{}" "€" :string) +(merge-rule "\(\infty\)" "∞" :string) +(merge-rule "\(\pm\)" "±" :string) +(merge-rule "\(\rightarrow\)" "→" :string) +(merge-rule "\(\checkmark\)" "✓" :string) +(merge-rule "\textendash{}" "–" :string) +(merge-rule "\textbar{}" "|" :string) +(merge-rule "\(\sp{\text{0}}\)" "⁰" :string) +(merge-rule "\(\sp{\text{1}}\)" "¹" :string) +(merge-rule "\(\sp{\text{2}}\)" "²" :string) +(merge-rule "\(\sp{\text{3}}\)" "³" :string) +(merge-rule "\(\sp{\text{4}}\)" "⁴" :string) +(merge-rule "\(\sp{\text{5}}\)" "⁵" :string) +(merge-rule "\(\sp{\text{6}}\)" "⁶" :string) +(merge-rule "\(\sp{\text{7}}\)" "⁷" :string) +(merge-rule "\(\sp{\text{8}}\)" "⁸" :string) +(merge-rule "\(\sp{\text{9}}\)" "⁹" :string) +(merge-rule "\(\sb{\text{0}}\)" "₀" :string) +(merge-rule "\(\sb{\text{1}}\)" "₁" :string) +(merge-rule "\(\sb{\text{2}}\)" "₂" :string) +(merge-rule "\(\sb{\text{3}}\)" "₃" :string) +(merge-rule "\(\sb{\text{4}}\)" "₄" :string) +(merge-rule "\(\sb{\text{5}}\)" "₅" :string) +(merge-rule "\(\sb{\text{6}}\)" "₆" :string) +(merge-rule "\(\sb{\text{7}}\)" "₇" :string) +(merge-rule "\(\sb{\text{8}}\)" "₈" :string) +(merge-rule "\(\sb{\text{9}}\)" "₉" :string) +(merge-rule "\IeC {\textalpha }" "α" :string) +(merge-rule "\IeC {\textbeta }" "β" :string) +(merge-rule "\IeC {\textgamma }" "γ" :string) +(merge-rule "\IeC {\textdelta }" "δ" :string) +(merge-rule "\IeC {\textepsilon }" "ε" :string) +(merge-rule "\IeC {\textzeta }" "ζ" :string) +(merge-rule "\IeC {\texteta }" "η" :string) +(merge-rule "\IeC {\texttheta }" "θ" :string) +(merge-rule "\IeC {\textiota }" "ι" :string) +(merge-rule "\IeC {\textkappa }" "κ" :string) +(merge-rule "\IeC {\textlambda }" "λ" :string) +(merge-rule "\IeC {\textmu }" "μ" :string) +(merge-rule "\IeC {\textnu }" "ν" :string) +(merge-rule "\IeC {\textxi }" "ξ" :string) +(merge-rule "\IeC {\textomicron }" "ο" :string) +(merge-rule "\IeC {\textpi }" "π" :string) +(merge-rule "\IeC {\textrho }" "ρ" :string) +(merge-rule "\IeC {\textsigma }" "σ" :string) +(merge-rule "\IeC {\texttau }" "τ" :string) +(merge-rule "\IeC {\textupsilon }" "υ" :string) +(merge-rule "\IeC {\textphi }" "φ" :string) +(merge-rule "\IeC {\textchi }" "χ" :string) +(merge-rule "\IeC {\textpsi }" "ψ" :string) +(merge-rule "\IeC {\textomega }" "ω" :string) +(merge-rule "\IeC {\textAlpha }" "Α" :string) +(merge-rule "\IeC {\textBeta }" "Β" :string) +(merge-rule "\IeC {\textGamma }" "Γ" :string) +(merge-rule "\IeC {\textDelta }" "Δ" :string) +(merge-rule "\IeC {\textEpsilon }" "Ε" :string) +(merge-rule "\IeC {\textZeta }" "Ζ" :string) +(merge-rule "\IeC {\textEta }" "Η" :string) +(merge-rule "\IeC {\textTheta }" "Θ" :string) +(merge-rule "\IeC {\textIota }" "Ι" :string) +(merge-rule "\IeC {\textKappa }" "Κ" :string) +(merge-rule "\IeC {\textLambda }" "Λ" :string) +(merge-rule "\IeC {\textMu }" "Μ" :string) +(merge-rule "\IeC {\textNu }" "Ν" :string) +(merge-rule "\IeC {\textTheta }" "Θ" :string) +(merge-rule "\IeC {\textIota }" "Ι" :string) +(merge-rule "\IeC {\textKappa }" "Κ" :string) +(merge-rule "\IeC {\textLambda }" "Λ" :string) +(merge-rule "\IeC {\textMu }" "Μ" :string) +(merge-rule "\IeC {\textNu }" "Ν" :string) +(merge-rule "\IeC {\textXi }" "Ξ" :string) +(merge-rule "\IeC {\textOmicron }" "Ο" :string) +(merge-rule "\IeC {\textPi }" "Π" :string) +(merge-rule "\IeC {\textRho }" "Ρ" :string) +(merge-rule "\IeC {\textSigma }" "Σ" :string) +(merge-rule "\IeC {\textTau }" "Τ" :string) +(merge-rule "\IeC {\textUpsilon }" "Υ" :string) +(merge-rule "\IeC {\textPhi }" "Φ" :string) +(merge-rule "\IeC {\textChi }" "Χ" :string) +(merge-rule "\IeC {\textPsi }" "Ψ" :string) +(merge-rule "\IeC {\textOmega }" "Ω" :string) +(merge-rule "\IeC {\textohm }" "Ω" :string) + +;; This xindy module provides some basic support for "see" +(require "makeindex.xdy") + +;; This creates one-letter headings and works fine with utf-8 letters. +;; For Cyrillic with pdflatex works thanks to LICRcyr2utf8.xdy +(require "latin-lettergroups.xdy") + +;; currently we don't (know how to easily) separate "Numbers" from +;; "Symbols" with xindy as is the case with makeindex. +(markup-index :open "\begin{sphinxtheindex} +\let\lettergroup\sphinxstyleindexlettergroup +\let\lettergroupDefault\sphinxstyleindexlettergroupDefault +\let\spxpagem\sphinxstyleindexpagemain +\let\spxentry\sphinxstyleindexentry +\let\spxextra\sphinxstyleindexextra + +" + :close " + +\end{sphinxtheindex} +" + :tree) + diff --git a/sphinxhighlight.sty b/sphinxhighlight.sty new file mode 100644 index 0000000..83b523c --- /dev/null +++ b/sphinxhighlight.sty @@ -0,0 +1,106 @@ +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesPackage{sphinxhighlight}[2016/05/29 stylesheet for highlighting with pygments] +% Its contents depend on pygments_style configuration variable. + + +\makeatletter +\def\PYG@reset{\let\PYG@it=\relax \let\PYG@bf=\relax% + \let\PYG@ul=\relax \let\PYG@tc=\relax% + \let\PYG@bc=\relax \let\PYG@ff=\relax} +\def\PYG@tok#1{\csname PYG@tok@#1\endcsname} +\def\PYG@toks#1+{\ifx\relax#1\empty\else% + \PYG@tok{#1}\expandafter\PYG@toks\fi} +\def\PYG@do#1{\PYG@bc{\PYG@tc{\PYG@ul{% + \PYG@it{\PYG@bf{\PYG@ff{#1}}}}}}} +\def\PYG#1#2{\PYG@reset\PYG@toks#1+\relax+\PYG@do{#2}} + +\@namedef{PYG@tok@w}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.73,0.73}{##1}}} +\@namedef{PYG@tok@c}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}} +\@namedef{PYG@tok@cp}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@cs}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}\def\PYG@bc##1{{\setlength{\fboxsep}{0pt}\colorbox[rgb]{1.00,0.94,0.94}{\strut ##1}}}} +\@namedef{PYG@tok@k}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@kp}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@kt}{\def\PYG@tc##1{\textcolor[rgb]{0.56,0.13,0.00}{##1}}} +\@namedef{PYG@tok@o}{\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}} +\@namedef{PYG@tok@ow}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@nb}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@nf}{\def\PYG@tc##1{\textcolor[rgb]{0.02,0.16,0.49}{##1}}} +\@namedef{PYG@tok@nc}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.05,0.52,0.71}{##1}}} +\@namedef{PYG@tok@nn}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.05,0.52,0.71}{##1}}} +\@namedef{PYG@tok@ne}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@nv}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}} +\@namedef{PYG@tok@no}{\def\PYG@tc##1{\textcolor[rgb]{0.38,0.68,0.84}{##1}}} +\@namedef{PYG@tok@nl}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.13,0.44}{##1}}} +\@namedef{PYG@tok@ni}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.84,0.33,0.22}{##1}}} +\@namedef{PYG@tok@na}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@nt}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.02,0.16,0.45}{##1}}} +\@namedef{PYG@tok@nd}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.33,0.33,0.33}{##1}}} +\@namedef{PYG@tok@s}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@sd}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@si}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.44,0.63,0.82}{##1}}} +\@namedef{PYG@tok@se}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@sr}{\def\PYG@tc##1{\textcolor[rgb]{0.14,0.33,0.53}{##1}}} +\@namedef{PYG@tok@ss}{\def\PYG@tc##1{\textcolor[rgb]{0.32,0.47,0.09}{##1}}} +\@namedef{PYG@tok@sx}{\def\PYG@tc##1{\textcolor[rgb]{0.78,0.36,0.04}{##1}}} +\@namedef{PYG@tok@m}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@gh}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}} +\@namedef{PYG@tok@gu}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.50,0.00,0.50}{##1}}} +\@namedef{PYG@tok@gd}{\def\PYG@tc##1{\textcolor[rgb]{0.63,0.00,0.00}{##1}}} +\@namedef{PYG@tok@gi}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.63,0.00}{##1}}} +\@namedef{PYG@tok@gr}{\def\PYG@tc##1{\textcolor[rgb]{1.00,0.00,0.00}{##1}}} +\@namedef{PYG@tok@ge}{\let\PYG@it=\textit} +\@namedef{PYG@tok@gs}{\let\PYG@bf=\textbf} +\@namedef{PYG@tok@gp}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.78,0.36,0.04}{##1}}} +\@namedef{PYG@tok@go}{\def\PYG@tc##1{\textcolor[rgb]{0.20,0.20,0.20}{##1}}} +\@namedef{PYG@tok@gt}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.27,0.87}{##1}}} +\@namedef{PYG@tok@err}{\def\PYG@bc##1{{\setlength{\fboxsep}{\string -\fboxrule}\fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{\strut ##1}}}} +\@namedef{PYG@tok@kc}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@kd}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@kn}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@kr}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@bp}{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}} +\@namedef{PYG@tok@fm}{\def\PYG@tc##1{\textcolor[rgb]{0.02,0.16,0.49}{##1}}} +\@namedef{PYG@tok@vc}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}} +\@namedef{PYG@tok@vg}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}} +\@namedef{PYG@tok@vi}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}} +\@namedef{PYG@tok@vm}{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}} +\@namedef{PYG@tok@sa}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@sb}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@sc}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@dl}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@s2}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@sh}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@s1}{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}} +\@namedef{PYG@tok@mb}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@mf}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@mh}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@mi}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@il}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@mo}{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}} +\@namedef{PYG@tok@ch}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}} +\@namedef{PYG@tok@cm}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}} +\@namedef{PYG@tok@cpf}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}} +\@namedef{PYG@tok@c1}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}} + +\def\PYGZbs{\char`\\} +\def\PYGZus{\char`\_} +\def\PYGZob{\char`\{} +\def\PYGZcb{\char`\}} +\def\PYGZca{\char`\^} +\def\PYGZam{\char`\&} +\def\PYGZlt{\char`\<} +\def\PYGZgt{\char`\>} +\def\PYGZsh{\char`\#} +\def\PYGZpc{\char`\%} +\def\PYGZdl{\char`\$} +\def\PYGZhy{\char`\-} +\def\PYGZsq{\char`\'} +\def\PYGZdq{\char`\"} +\def\PYGZti{\char`\~} +% for compatibility with earlier versions +\def\PYGZat{@} +\def\PYGZlb{[} +\def\PYGZrb{]} +\makeatother + +\renewcommand\PYGZsq{\textquotesingle} diff --git a/sphinxhowto.cls b/sphinxhowto.cls new file mode 100644 index 0000000..951cf81 --- /dev/null +++ b/sphinxhowto.cls @@ -0,0 +1,102 @@ +% +% sphinxhowto.cls for Sphinx (https://www.sphinx-doc.org/) +% + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesClass{sphinxhowto}[2019/12/01 v2.3.0 Document class (Sphinx howto)] + +% 'oneside' option overriding the 'twoside' default +\newif\if@oneside +\DeclareOption{oneside}{\@onesidetrue} +% Pass remaining document options to the parent class. +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{\sphinxdocclass}} +\ProcessOptions\relax + +% Default to two-side document +\if@oneside +% nothing to do (oneside is the default) +\else +\PassOptionsToClass{twoside}{\sphinxdocclass} +\fi + +\LoadClass{\sphinxdocclass} + +% Set some sane defaults for section numbering depth and TOC depth. You can +% reset these counters in your preamble. +% +\setcounter{secnumdepth}{2} +\setcounter{tocdepth}{2}% i.e. section and subsection + +% Adapt \and command to the flushright context of \sphinxmaketitle, to +% avoid ragged line endings if author names do not fit all on one single line +\DeclareRobustCommand{\and}{% + \end{tabular}\kern-\tabcolsep + \allowbreak + \hskip\dimexpr1em+\tabcolsep\@plus.17fil\begin{tabular}[t]{c}% +}% +% If it is desired that each author name be on its own line, use in preamble: +%\DeclareRobustCommand{\and}{% +% \end{tabular}\kern-\tabcolsep\\\begin{tabular}[t]{c}% +%}% +% Change the title page to look a bit better, and fit in with the fncychap +% ``Bjarne'' style a bit better. +% +\newcommand{\sphinxmaketitle}{% + \noindent\rule{\textwidth}{1pt}\par + \begingroup % for PDF information dictionary + \def\endgraf{ }\def\and{\& }% + \pdfstringdefDisableCommands{\def\\{, }}% overwrite hyperref setup + \hypersetup{pdfauthor={\@author}, pdftitle={\@title}}% + \endgroup + \begin{flushright} + \sphinxlogo + \py@HeaderFamily + {\Huge \@title }\par + {\itshape\large \py@release \releaseinfo}\par + \vspace{25pt} + {\Large + \begin{tabular}[t]{c} + \@author + \end{tabular}\kern-\tabcolsep}\par + \vspace{25pt} + \@date \par + \py@authoraddress \par + \end{flushright} + \@thanks + \setcounter{footnote}{0} + \let\thanks\relax\let\maketitle\relax + %\gdef\@thanks{}\gdef\@author{}\gdef\@title{} +} + +\newcommand{\sphinxtableofcontents}{% + \begingroup + \parskip \z@skip + \sphinxtableofcontentshook + \tableofcontents + \endgroup + \noindent\rule{\textwidth}{1pt}\par + \vspace{12pt}% +} +\newcommand\sphinxtableofcontentshook{} +\pagenumbering{arabic} + +% Fix the bibliography environment to add an entry to the Table of +% Contents. +% For an article document class this environment is a section, +% so no page break before it. +% +\newenvironment{sphinxthebibliography}[1]{% + % \phantomsection % not needed here since TeXLive 2010's hyperref + \begin{thebibliography}{#1}% + \addcontentsline{toc}{section}{\ifdefined\refname\refname\else\ifdefined\bibname\bibname\fi\fi}}{\end{thebibliography}} + + +% Same for the indices. +% The memoir class already does this, so we don't duplicate it in that case. +% +\@ifclassloaded{memoir} + {\newenvironment{sphinxtheindex}{\begin{theindex}}{\end{theindex}}} + {\newenvironment{sphinxtheindex}{% + \phantomsection % needed because no chapter, section, ... is created by theindex + \begin{theindex}% + \addcontentsline{toc}{section}{\indexname}}{\end{theindex}}} diff --git a/sphinxlatexadmonitions.sty b/sphinxlatexadmonitions.sty new file mode 100644 index 0000000..1e418c8 --- /dev/null +++ b/sphinxlatexadmonitions.sty @@ -0,0 +1,148 @@ +%% NOTICES AND ADMONITIONS +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexadmonitions.sty}[2021/01/27 admonitions] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - sphinxadmonition (environment) +% This is a dispatch supporting +% +% - note, hint, important, tip (via sphinxlightbox) +% - warning, caution, attention, danger, error (via sphinxheavybox) +% +% Each sphinx environment can be redefined by user. +% The defaults are customizable via various colour and dimension +% settings, cf sphinx docs (latex customization). +% +% Requires: +\RequirePackage{framed}% used by sphinxheavybox +% +% Dependencies (they do not need to be defined at time of loading): +% - of course the various colour and dimension options handled via sphinx.sty +% - \sphinxstrong (for sphinxlightbox and sphinxheavybox) +% - dimension register \spx@image@maxheight from sphinxlatexgraphics.sty +% - \savenotes/\spewnotes from sphinxpackagefootnote (for sphinxheavybox) + +% Provides: (also in sphinxlatexliterals.sty) +\providecommand*\sphinxvspacefixafterfrenchlists{% + \ifvmode\ifdim\lastskip<\z@ \vskip\parskip\fi\else\par\fi +} + +% Some are quite plain +% the spx@notice@bordercolor etc are set in the sphinxadmonition environment +\newenvironment{sphinxlightbox}{% + \par + \noindent{\color{spx@notice@bordercolor}% + \rule{\linewidth}{\spx@notice@border}}\par\nobreak + {\parskip\z@skip\noindent}% + } + {% + % counteract previous possible negative skip (French lists!): + % (we can't cancel that any earlier \vskip introduced a potential pagebreak) + \sphinxvspacefixafterfrenchlists + \nobreak\vbox{\noindent\kern\@totalleftmargin + {\color{spx@notice@bordercolor}% + \rule[\dimexpr.4\baselineskip-\spx@notice@border\relax] + {\linewidth}{\spx@notice@border}}\hss}\allowbreak + }% end of sphinxlightbox environment definition +% may be renewenvironment'd by user for complete customization +\newenvironment{sphinxnote}[1] + {\begin{sphinxlightbox}\sphinxstrong{#1} }{\end{sphinxlightbox}} +\newenvironment{sphinxhint}[1] + {\begin{sphinxlightbox}\sphinxstrong{#1} }{\end{sphinxlightbox}} +\newenvironment{sphinximportant}[1] + {\begin{sphinxlightbox}\sphinxstrong{#1} }{\end{sphinxlightbox}} +\newenvironment{sphinxtip}[1] + {\begin{sphinxlightbox}\sphinxstrong{#1} }{\end{sphinxlightbox}} +% or just use the package options +% these are needed for common handling by notice environment of lightbox +% and heavybox but they are currently not used by lightbox environment +% and there is consequently no corresponding package option +\definecolor{sphinxnoteBgColor}{rgb}{1,1,1} +\definecolor{sphinxhintBgColor}{rgb}{1,1,1} +\definecolor{sphinximportantBgColor}{rgb}{1,1,1} +\definecolor{sphinxtipBgColor}{rgb}{1,1,1} + +% Others get more distinction +% Code adapted from framed.sty's "snugshade" environment. +% Nesting works (inner frames do not allow page breaks). +\newenvironment{sphinxheavybox}{\par + \setlength{\FrameRule}{\spx@notice@border}% + \setlength{\FrameSep}{\dimexpr.6\baselineskip-\FrameRule\relax} + \advance\spx@image@maxheight + -\dimexpr2\FrameRule + +2\FrameSep + +\baselineskip\relax % will happen again if nested, needed indeed! + % configure framed.sty's parameters to obtain same vertical spacing + % as for "light" boxes. We need for this to manually insert parskip glue and + % revert a skip done by framed before the frame. + \ltx@ifundefined{OuterFrameSep}{}{\OuterFrameSep\z@skip}% + \vspace{\FrameHeightAdjust} + % copied/adapted from framed.sty's snugshade + \def\FrameCommand##1{\hskip\@totalleftmargin + \fboxsep\FrameSep \fboxrule\FrameRule + \fcolorbox{spx@notice@bordercolor}{spx@notice@bgcolor}{##1}% + \hskip-\linewidth \hskip-\@totalleftmargin \hskip\columnwidth}% + \savenotes + % use a minipage if we are already inside a framed environment + \ifspx@inframed + \noindent\begin{minipage}{\linewidth} + \else + % handle case where notice is first thing in a list item (or is quoted) + \if@inlabel + \noindent\par\vspace{-\baselineskip} + \else + \vspace{\parskip} + \fi + \fi + \MakeFramed {\spx@inframedtrue + \advance\hsize-\width \@totalleftmargin\z@ \linewidth\hsize + % minipage initialization copied from LaTeX source code. + \@pboxswfalse + \let\@listdepth\@mplistdepth \@mplistdepth\z@ + \@minipagerestore + \@setminipage }% + } + {% + \par\unskip + \@minipagefalse + \endMakeFramed + \ifspx@inframed\end{minipage}\fi + % set footnotes at bottom of page + \spewnotes + % arrange for similar spacing below frame as for "light" boxes. + \vskip .4\baselineskip + }% end of sphinxheavybox environment definition +% may be renewenvironment'd by user for complete customization +\newenvironment{sphinxwarning}[1] + {\begin{sphinxheavybox}\sphinxstrong{#1} }{\end{sphinxheavybox}} +\newenvironment{sphinxcaution}[1] + {\begin{sphinxheavybox}\sphinxstrong{#1} }{\end{sphinxheavybox}} +\newenvironment{sphinxattention}[1] + {\begin{sphinxheavybox}\sphinxstrong{#1} }{\end{sphinxheavybox}} +\newenvironment{sphinxdanger}[1] + {\begin{sphinxheavybox}\sphinxstrong{#1} }{\end{sphinxheavybox}} +\newenvironment{sphinxerror}[1] + {\begin{sphinxheavybox}\sphinxstrong{#1} }{\end{sphinxheavybox}} +% or just use package options + +% the \colorlet of xcolor (if at all loaded) is overkill for our use case +\newcommand{\sphinxcolorlet}[2] + {\expandafter\let\csname\@backslashchar color@#1\expandafter\endcsname + \csname\@backslashchar color@#2\endcsname } + +% the main dispatch for all types of notices +\newenvironment{sphinxadmonition}[2]{% #1=type, #2=heading + % can't use #1 directly in definition of end part + \def\spx@noticetype {#1}% + % set parameters of heavybox/lightbox + \sphinxcolorlet{spx@notice@bordercolor}{sphinx#1BorderColor}% + \sphinxcolorlet{spx@notice@bgcolor}{sphinx#1BgColor}% + \spx@notice@border \dimexpr\csname spx@opt@#1border\endcsname\relax + % start specific environment, passing the heading as argument + \begin{sphinx#1}{#2}} + % workaround some LaTeX "feature" of \end command + {\edef\spx@temp{\noexpand\end{sphinx\spx@noticetype}}\spx@temp} + +\endinput diff --git a/sphinxlatexcontainers.sty b/sphinxlatexcontainers.sty new file mode 100644 index 0000000..93b2c8c --- /dev/null +++ b/sphinxlatexcontainers.sty @@ -0,0 +1,22 @@ +%% CONTAINER DIRECTIVES +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexcontainers.sty}[2021/05/03 containers] + +% The purpose of this file is to provide a dummy environment sphinxclass which +% will be inserted for each class in each container directive. The class name +% will be passed as the argument to the environment. +% +% For a class foo, the user can define customised handling of that class by +% defining the sphinxclassfoo LaTeX environment. + +\newenvironment{sphinxuseclass}[1]{% + \def\sphinxClassFunctionName{sphinxclass#1}% + \ltx@ifundefined{\sphinxClassFunctionName}% + {}% undefined so do nothing + {\expandafter\begin\expandafter{\sphinxClassFunctionName}}% +}{% + \ltx@ifundefined{\sphinxClassFunctionName}% + {}% we did nothing so we keep doing nothing + {\expandafter\end\expandafter{\sphinxClassFunctionName}}% +}% diff --git a/sphinxlatexgraphics.sty b/sphinxlatexgraphics.sty new file mode 100644 index 0000000..fd0aae6 --- /dev/null +++ b/sphinxlatexgraphics.sty @@ -0,0 +1,122 @@ +%% GRAPHICS +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexgraphics.sty}[2021/01/27 graphics] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - macros: +% +% - \sphinxfigcaption +% - \sphinxincludegraphics +% +% - environments: +% +% - sphinxfigure-in-table +% +% May change: +% +% - \sphinxcaption (at begin document) +% +% Also provides: +% +% - \sphinxsafeincludegraphics (default of \sphinxincludegraphics since 2.0) +% - \spx@image@maxheight dimension (used by sphinxlatexadmonitions.sty) +% - \spx@image@box scratch box register (also used by sphinxlatexliterals.sty) +% +% Requires: +% \RequirePackage{graphicx}% done in sphinx.sty +\RequirePackage{amstext}% needed for \firstchoice@true(false) + +% \sphinxincludegraphics resizes images larger than the TeX \linewidth (which +% is adjusted in indented environments), or taller than a certain maximal +% height (usually \textheight and this is reduced in the environments which use +% framed.sty to avoid infinite loop if image too tall). +% +% In case height or width options are present the rescaling is done +% (since 2.0), in a way keeping the width:height ratio either native from +% image or from the width and height options if both were present. +% +\newdimen\spx@image@maxheight +\AtBeginDocument{\spx@image@maxheight\textheight} + +% box scratch register +\newbox\spx@image@box +\newcommand*{\sphinxsafeincludegraphics}[2][]{% + % #1 contains possibly width=, height=, but no scale= since 1.8.4 + \setbox\spx@image@box\hbox{\includegraphics[#1,draft]{#2}}% + \in@false % use some handy boolean flag + \ifdim \wd\spx@image@box>\linewidth + \in@true % flag to remember to adjust options and set box dimensions + % compute height which results from rescaling width to \linewidth + % and keep current aspect ratio. multiply-divide in \numexpr uses + % temporarily doubled precision, hence no overflow. (of course we + % assume \ht is not a few sp's below \maxdimen...(about 16384pt). + \edef\spx@image@rescaledheight % with sp units + {\the\numexpr\ht\spx@image@box + *\linewidth/\wd\spx@image@box sp}% + \ifdim\spx@image@rescaledheight>\spx@image@maxheight + % the rescaled height will be too big, so it is height which decides + % the rescaling factor + \def\spx@image@requiredheight{\spx@image@maxheight}% dimen register + \edef\spx@image@requiredwidth % with sp units + {\the\numexpr\wd\spx@image@box + *\spx@image@maxheight/\ht\spx@image@box sp}% + % TODO: decide if this commented-out block could be needed due to + % rounding in numexpr operations going up + % \ifdim\spx@image@requiredwidth>\linewidth + % \def\spx@image@requiredwidth{\linewidth}% dimen register + % \fi + \else + \def\spx@image@requiredwidth{\linewidth}% dimen register + \let\spx@image@requiredheight\spx@image@rescaledheight% sp units + \fi + \else + % width is ok, let's check height + \ifdim\ht\spx@image@box>\spx@image@maxheight + \in@true + \edef\spx@image@requiredwidth % with sp units + {\the\numexpr\wd\spx@image@box + *\spx@image@maxheight/\ht\spx@image@box sp}% + \def\spx@image@requiredheight{\spx@image@maxheight}% dimen register + \fi + \fi % end of check of width and height + \ifin@ + \setbox\spx@image@box + \hbox{\includegraphics + [%#1,% contained only width and/or height and overruled anyhow + width=\spx@image@requiredwidth,height=\spx@image@requiredheight]% + {#2}}% + % \includegraphics does not set box dimensions to the exactly + % requested ones, see https://github.com/latex3/latex2e/issues/112 + \wd\spx@image@box\spx@image@requiredwidth + \ht\spx@image@box\spx@image@requiredheight + \leavevmode\box\spx@image@box + \else + % here we do not modify the options, no need to adjust width and height + % on output, they will be computed exactly as with "draft" option + \setbox\spx@image@box\box\voidb@x % clear memory + \includegraphics[#1]{#2}% + \fi +}% +% Use the "safe" one by default (2.0) +\def\sphinxincludegraphics{\sphinxsafeincludegraphics} + + +%% FIGURE IN TABLE +% +\newenvironment{sphinxfigure-in-table}[1][\linewidth]{% + \def\@captype{figure}% + \sphinxsetvskipsforfigintablecaption + \begin{minipage}{#1}% +}{\end{minipage}} +% tabulary expands twice contents, we need to prevent double counter stepping +\newcommand*\sphinxfigcaption + {\ifx\equation$%$% this is trick to identify tabulary first pass + \firstchoice@false\else\firstchoice@true\fi + \spx@originalcaption } +\newcommand*\sphinxsetvskipsforfigintablecaption + {\abovecaptionskip\smallskipamount + \belowcaptionskip\smallskipamount} + +\endinput diff --git a/sphinxlatexindbibtoc.sty b/sphinxlatexindbibtoc.sty new file mode 100644 index 0000000..79e30a1 --- /dev/null +++ b/sphinxlatexindbibtoc.sty @@ -0,0 +1,69 @@ +%% INDEX, BIBLIOGRAPHY, APPENDIX, TABLE OF CONTENTS +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexindbibtoc.sty}[2021/01/27 index, bib., toc] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - environments: (backup defaults or get redefined) +% +% - sphinxtheindex (direct mark-up or via python.ist or sphinx.xdy) +% - sphinxthebibliography +% +% - macros: (defines defaults) +% +% - \sphinxmaketitle +% - \sphinxtableofcontents +% - \sphinxnonalphabeticalgroupname +% - \sphinxsymbolsname +% - \sphinxnumbersname +% - \sphinxcite +% +% Requires: +\RequirePackage{makeidx} + +% fix the double index and bibliography on the table of contents +% in jsclasses (Japanese standard document classes) +\ifx\@jsc@uplatextrue\@undefined\else + \renewenvironment{sphinxtheindex} + {\cleardoublepage\phantomsection + \begin{theindex}} + {\end{theindex}} + + \renewenvironment{sphinxthebibliography}[1] + {\cleardoublepage% \phantomsection % not needed here since TeXLive 2010's hyperref + \begin{thebibliography}{#1}} + {\end{thebibliography}} +\fi + +% disable \@chappos in Appendix in pTeX +\ifx\kanjiskip\@undefined\else + \let\py@OldAppendix=\appendix + \renewcommand{\appendix}{ + \py@OldAppendix + \gdef\@chappos{} + } +\fi + +% make commands known to non-Sphinx document classes +\providecommand*{\sphinxmaketitle}{\maketitle} +\providecommand*{\sphinxtableofcontents}{\tableofcontents} +\ltx@ifundefined{sphinxthebibliography} + {\newenvironment + {sphinxthebibliography}{\begin{thebibliography}}{\end{thebibliography}}% + } + {}% else clause of \ltx@ifundefined +\ltx@ifundefined{sphinxtheindex} + {\newenvironment{sphinxtheindex}{\begin{theindex}}{\end{theindex}}}% + {}% else clause of \ltx@ifundefined + +% for usage with xindy: this string gets internationalized in preamble +\newcommand*{\sphinxnonalphabeticalgroupname}{} +% redefined in preamble, headings for makeindex produced index +\newcommand*{\sphinxsymbolsname}{} +\newcommand*{\sphinxnumbersname}{} + +\protected\def\sphinxcite{\cite} + + +\endinput diff --git a/sphinxlatexlists.sty b/sphinxlatexlists.sty new file mode 100644 index 0000000..ed7521c --- /dev/null +++ b/sphinxlatexlists.sty @@ -0,0 +1,97 @@ +%% ALPHANUMERIC LIST ITEMS +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexlists.sty}[2021/01/27 lists] + +% Provides support for this output mark-up from Sphinx latex writer: +% - \sphinxsetlistlabels + +% Dependencies: the \spx@opt@maxlistdepth from sphinx.sty + +\newcommand\sphinxsetlistlabels[5] +{% #1 = style, #2 = enum, #3 = enumnext, #4 = prefix, #5 = suffix + % #2 and #3 are counters used by enumerate environment e.g. enumi, enumii. + % #1 is a macro such as \arabic or \alph + % prefix and suffix are strings (by default empty and a dot). + \@namedef{the#2}{#1{#2}}% + \@namedef{label#2}{#4\@nameuse{the#2}#5}% + \@namedef{p@#3}{\@nameuse{p@#2}#4\@nameuse{the#2}#5}% +}% + + +%% MAXLISTDEPTH +% +% remove LaTeX's cap on nesting depth if 'maxlistdepth' key used. +% This is a hack, which works with the standard classes: it assumes \@toodeep +% is always used in "true" branches: "\if ... \@toodeep \else .. \fi." + +% will force use the "false" branch (if there is one) +\def\spx@toodeep@hack{\fi\iffalse} + +% do nothing if 'maxlistdepth' key not used or if package enumitem loaded. +\ifnum\spx@opt@maxlistdepth=\z@\expandafter\@gobbletwo\fi +\AtBeginDocument{% +\@ifpackageloaded{enumitem}{\remove@to@nnil}{}% + \let\spx@toodeepORI\@toodeep + \def\@toodeep{% + \ifnum\@listdepth<\spx@opt@maxlistdepth\relax + \expandafter\spx@toodeep@hack + \else + \expandafter\spx@toodeepORI + \fi}% +% define all missing \@list... macros + \count@\@ne + \loop + \ltx@ifundefined{@list\romannumeral\the\count@} + {\iffalse}{\iftrue\advance\count@\@ne}% + \repeat + \loop + \ifnum\count@>\spx@opt@maxlistdepth\relax\else + \expandafter\let + \csname @list\romannumeral\the\count@\expandafter\endcsname + \csname @list\romannumeral\the\numexpr\count@-\@ne\endcsname + % workaround 2.6--3.2d babel-french issue (fixed in 3.2e; no change needed) + \ltx@ifundefined{leftmargin\romannumeral\the\count@} + {\expandafter\let + \csname leftmargin\romannumeral\the\count@\expandafter\endcsname + \csname leftmargin\romannumeral\the\numexpr\count@-\@ne\endcsname}{}% + \advance\count@\@ne + \repeat +% define all missing enum... counters and \labelenum... macros and \p@enum.. + \count@\@ne + \loop + \ltx@ifundefined{c@enum\romannumeral\the\count@} + {\iffalse}{\iftrue\advance\count@\@ne}% + \repeat + \loop + \ifnum\count@>\spx@opt@maxlistdepth\relax\else + \newcounter{enum\romannumeral\the\count@}% + \expandafter\def + \csname labelenum\romannumeral\the\count@\expandafter\endcsname + \expandafter + {\csname theenum\romannumeral\the\numexpr\count@\endcsname.}% + \expandafter\def + \csname p@enum\romannumeral\the\count@\expandafter\endcsname + \expandafter + {\csname p@enum\romannumeral\the\numexpr\count@-\@ne\expandafter + \endcsname\csname theenum\romannumeral\the\numexpr\count@-\@ne\endcsname.}% + \advance\count@\@ne + \repeat +% define all missing labelitem... macros + \count@\@ne + \loop + \ltx@ifundefined{labelitem\romannumeral\the\count@} + {\iffalse}{\iftrue\advance\count@\@ne}% + \repeat + \loop + \ifnum\count@>\spx@opt@maxlistdepth\relax\else + \expandafter\let + \csname labelitem\romannumeral\the\count@\expandafter\endcsname + \csname labelitem\romannumeral\the\numexpr\count@-\@ne\endcsname + \advance\count@\@ne + \repeat + \PackageInfo{sphinx}{maximal list depth extended to \spx@opt@maxlistdepth}% +\@gobble\@nnil +} + +\endinput diff --git a/sphinxlatexliterals.sty b/sphinxlatexliterals.sty new file mode 100644 index 0000000..cc768c2 --- /dev/null +++ b/sphinxlatexliterals.sty @@ -0,0 +1,804 @@ +%% LITERAL BLOCKS +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexliterals.sty}[2021/12/06 code-blocks and parsed literals] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - macros: +% - \sphinxLiteralBlockLabel +% - \sphinxSetupCaptionForVerbatim +% - \sphinxSetupCodeBlockInFootnote +% - \sphinxhref +% - \sphinxnolinkurl +% - \sphinxresetverbatimhllines +% - \sphinxunactivateextrasandspace +% - \sphinxupquote +% - \sphinxurl +% +% - environments: +% - sphinxVerbatim +% - sphinxVerbatimintable +% - sphinxalltt +% +% Dependency: +% +% - hyperref (for \phantomsection and \capstart) (loaded later) +% +% Executes \RequirePackage for: +% +% - framed +% - fancyvrb +% - alltt +% - upquote +% - needspace + +% also in sphinxlatexadmonitions.sty: +% This is a workaround to a "feature" of French lists, when literal block +% follows immediately; usable generally (does only \par then), a priori... +\providecommand*\sphinxvspacefixafterfrenchlists{% + \ifvmode\ifdim\lastskip<\z@ \vskip\parskip\fi\else\par\fi +} + +% For framing allowing pagebreaks +\RequirePackage{framed} +% For source code +% MEMO: fancyvrb is used mainly to +% 1- control horizontal and vertical spacing +% 2- optional line numbering +% 3- optional line emphasizing +% 4- while still allowing expansion of Pygments latex mark-up +% Other aspects such as framing, caption handling, codeline wrapping are +% added on top of it. We should stop using fancyvrb and implement +% 1, 2, 3, 4 by own Sphinx fully native Verbatim. This would allow to solve +% limitations with wrapped long code line not allowing page break. +\RequirePackage{fancyvrb} +% For parsed-literal blocks. +\RequirePackage{alltt} +% Display "real" single quotes in literal blocks. +\RequirePackage{upquote} +% Skip to next page if not enough space at bottom +\RequirePackage{needspace} + +% Based on use of "fancyvrb.sty"'s Verbatim. +% - with framing allowing page breaks ("framed.sty") +% - with breaking of long lines (exploits Pygments mark-up), +% - with possibly of a top caption, non-separable by pagebreak. +% - and usable inside tables or footnotes ("sphinxpackagefootnote.sty"). + +% for emphasizing lines +\define@key{FV}{hllines}{\def\sphinx@verbatim@checkifhl##1{\in@{, ##1,}{#1}}} +% sphinxVerbatim must be usable by third party without requiring hllines set-up +\def\sphinxresetverbatimhllines{\def\sphinx@verbatim@checkifhl##1{\in@false}} +\sphinxresetverbatimhllines + +% Prior to Sphinx 1.5, \Verbatim and \endVerbatim were modified by Sphinx. +% The aliases defined here are used in sphinxVerbatim environment and can +% serve as hook-points with no need to modify \Verbatim itself. +\let\OriginalVerbatim \Verbatim +\let\endOriginalVerbatim\endVerbatim + +% for captions of literal blocks +% at start of caption title +\newcommand*{\fnum@literalblock}{\literalblockname\nobreakspace\theliteralblock} +% this will be overwritten in document preamble by Babel translation +\newcommand*{\literalblockname}{Listing } +% file extension needed for \caption's good functioning, the file is created +% only if a \listof{literalblock}{foo} command is encountered, which is +% analogous to \listoffigures, but for the code listings (foo = chosen title.) +\newcommand*{\ext@literalblock}{lol} + +% if forced use of minipage encapsulation is needed (e.g. table cells) +\newif\ifsphinxverbatimwithminipage \sphinxverbatimwithminipagefalse + +% Framing macro for use with framed.sty's \FrameCommand +% - it obeys current indentation, +% - frame is \fboxsep separated from the contents, +% - the contents use the full available text width, +% - #1 = color of frame, #2 = color of background, +% - #3 = above frame, #4 = below frame, #5 = within frame, +% - #3 and #4 must be already typeset boxes; they must issue \normalcolor +% or similar, else, they are under scope of color #1 +\long\def\spx@fcolorbox #1#2#3#4#5{% + \hskip\@totalleftmargin + \hskip-\fboxsep\hskip-\fboxrule + % use of \color@b@x here is compatible with both xcolor.sty and color.sty + \color@b@x {\color{#1}\spx@CustomFBox{#3}{#4}}{\color{#2}}{#5}% + \hskip-\fboxsep\hskip-\fboxrule + \hskip-\linewidth \hskip-\@totalleftmargin \hskip\columnwidth +}% +% #1 = for material above frame, such as a caption or a "continued" hint +% #2 = for material below frame, such as a caption or "continues on next page" +% #3 = actual contents, which will be typeset with a background color +\long\def\spx@CustomFBox#1#2#3{% + \begingroup + \setbox\@tempboxa\hbox{{#3}}% inner braces to avoid color leaks + \vbox{#1% above frame + % draw frame border _latest_ to avoid pdf viewer issue + \kern\fboxrule + \hbox{\kern\fboxrule + \copy\@tempboxa + \kern-\wd\@tempboxa\kern-\fboxrule + \vrule\@width\fboxrule + \kern\wd\@tempboxa + \vrule\@width\fboxrule}% + \kern-\dimexpr\ht\@tempboxa+\dp\@tempboxa+\fboxrule\relax + \hrule\@height\fboxrule + \kern\dimexpr\ht\@tempboxa+\dp\@tempboxa\relax + \hrule\@height\fboxrule + #2% below frame + }% + \endgroup +}% +\def\spx@fcolorbox@put@c#1{% hide width from framed.sty measuring + \moveright\dimexpr\fboxrule+.5\wd\@tempboxa\hb@xt@\z@{\hss#1\hss}% +}% +\def\spx@fcolorbox@put@r#1{% right align with contents, width hidden + \moveright\dimexpr\fboxrule+\wd\@tempboxa-\fboxsep\hb@xt@\z@{\hss#1}% +}% +\def\spx@fcolorbox@put@l#1{% left align with contents, width hidden + \moveright\dimexpr\fboxrule+\fboxsep\hb@xt@\z@{#1\hss}% +}% +% +\def\sphinxVerbatim@Continued + {\csname spx@fcolorbox@put@\spx@opt@verbatimcontinuedalign\endcsname + {\normalcolor\sphinxstylecodecontinued\literalblockcontinuedname}}% +\def\sphinxVerbatim@Continues + {\csname spx@fcolorbox@put@\spx@opt@verbatimcontinuesalign\endcsname + {\normalcolor\sphinxstylecodecontinues\literalblockcontinuesname}}% +\def\sphinxVerbatim@Title + {\spx@fcolorbox@put@c{\unhcopy\sphinxVerbatim@TitleBox}}% +\let\sphinxVerbatim@Before\@empty +\let\sphinxVerbatim@After\@empty +% Defaults are redefined in document preamble according to language +\newcommand*\literalblockcontinuedname{continued from previous page}% +\newcommand*\literalblockcontinuesname{continues on next page}% +% +\def\spx@verbatimfcolorbox{\spx@fcolorbox{VerbatimBorderColor}{VerbatimColor}}% +\def\sphinxVerbatim@FrameCommand + {\spx@verbatimfcolorbox\sphinxVerbatim@Before\sphinxVerbatim@After}% +\def\sphinxVerbatim@FirstFrameCommand + {\spx@verbatimfcolorbox\sphinxVerbatim@Before\sphinxVerbatim@Continues}% +\def\sphinxVerbatim@MidFrameCommand + {\spx@verbatimfcolorbox\sphinxVerbatim@Continued\sphinxVerbatim@Continues}% +\def\sphinxVerbatim@LastFrameCommand + {\spx@verbatimfcolorbox\sphinxVerbatim@Continued\sphinxVerbatim@After}% + +% For linebreaks inside Verbatim environment from package fancyvrb. +\newbox\sphinxcontinuationbox +\newbox\sphinxvisiblespacebox +\newcommand*\sphinxafterbreak {\copy\sphinxcontinuationbox} + +% Take advantage of the already applied Pygments mark-up to insert +% potential linebreaks for TeX processing. +% {, <, #, %, $, ' and ": go to next line. +% _, }, ^, &, >, -, ~, and \: stay at end of broken line. +% Use of \textquotesingle for straight quote. +% FIXME: convert this to package options ? +\newcommand*\sphinxbreaksbeforelist {% + \do\PYGZob\{\do\PYGZlt\<\do\PYGZsh\#\do\PYGZpc\%% {, <, #, %, + \do\PYGZdl\$\do\PYGZdq\"% $, " + \def\PYGZsq + {\discretionary{}{\sphinxafterbreak\textquotesingle}{\textquotesingle}}% ' +} +\newcommand*\sphinxbreaksafterlist {% + \do\PYGZus\_\do\PYGZcb\}\do\PYGZca\^\do\PYGZam\&% _, }, ^, &, + \do\PYGZgt\>\do\PYGZhy\-\do\PYGZti\~% >, -, ~ + \do\PYGZbs\\% \ +} +\newcommand*\sphinxbreaksatspecials {% + \def\do##1##2% + {\def##1{\discretionary{}{\sphinxafterbreak\char`##2}{\char`##2}}}% + \sphinxbreaksbeforelist + \def\do##1##2% + {\def##1{\discretionary{\char`##2}{\sphinxafterbreak}{\char`##2}}}% + \sphinxbreaksafterlist +} + +\def\sphinx@verbatim@nolig@list {\do \`}% +% Some characters . , ; ? ! / are neither pygmentized nor "tex-escaped". +% This macro makes them "active" and they will insert potential linebreaks. +% Not compatible with math mode (cf \sphinxunactivateextras). +\newcommand*\sphinxbreaksbeforeactivelist {}% none +\newcommand*\sphinxbreaksafteractivelist {\do\.\do\,\do\;\do\?\do\!\do\/} +\newcommand*\sphinxbreaksviaactive {% + \def\do##1{\lccode`\~`##1% + \lowercase{\def~}{\discretionary{}{\sphinxafterbreak\char`##1}{\char`##1}}% + \catcode`##1\active}% + \sphinxbreaksbeforeactivelist + \def\do##1{\lccode`\~`##1% + \lowercase{\def~}{\discretionary{\char`##1}{\sphinxafterbreak}{\char`##1}}% + \catcode`##1\active}% + \sphinxbreaksafteractivelist + \lccode`\~`\~ +} + +% If the linebreak is at a space, the latter will be displayed as visible +% space at end of first line, and a continuation symbol starts next line. +\def\spx@verbatim@space {% + \nobreak\hskip\z@skip + \discretionary{\copy\sphinxvisiblespacebox}{\sphinxafterbreak} + {\kern\fontdimen2\font}% +}% + +% if the available space on page is less than \literalblockneedspace, insert pagebreak +\newcommand{\sphinxliteralblockneedspace}{5\baselineskip} +\newcommand{\sphinxliteralblockwithoutcaptionneedspace}{1.5\baselineskip} +% The title (caption) is specified from outside as macro \sphinxVerbatimTitle. +% \sphinxVerbatimTitle is reset to empty after each use of Verbatim. +\newcommand*\sphinxVerbatimTitle {} +% This box to typeset the caption before framed.sty multiple passes for framing. +\newbox\sphinxVerbatim@TitleBox +% This box to measure contents if nested as inner \MakeFramed requires then +% minipage encapsulation but too long contents then break outer \MakeFramed +\newbox\sphinxVerbatim@ContentsBox +% Holder macro for labels of literal blocks. Set-up by LaTeX writer. +\newcommand*\sphinxLiteralBlockLabel {} +\newcommand*\sphinxSetupCaptionForVerbatim [1] +{% + \sphinxvspacefixafterfrenchlists + \needspace{\sphinxliteralblockneedspace}% +% insert a \label via \sphinxLiteralBlockLabel +% reset to normal the color for the literal block caption + \def\sphinxVerbatimTitle + {\py@NormalColor\sphinxcaption{\sphinxLiteralBlockLabel #1}}% +} +\newcommand*\sphinxSetupCodeBlockInFootnote {% + \fvset{fontsize=\footnotesize}\let\caption\sphinxfigcaption + \sphinxverbatimwithminipagetrue % reduces vertical spaces + % we counteract (this is in a group) the \@normalsize from \caption + \let\normalsize\footnotesize\let\@parboxrestore\relax + \def\spx@abovecaptionskip{\sphinxverbatimsmallskipamount}% +} +\newcommand*{\sphinxverbatimsmallskipamount}{\smallskipamount} +% serves to implement line highlighting and line wrapping +\newcommand\sphinxFancyVerbFormatLine[1]{% + \expandafter\sphinx@verbatim@checkifhl\expandafter{\the\FV@CodeLineNo}% + \ifin@ + \sphinxVerbatimHighlightLine{#1}% + \else + \sphinxVerbatimFormatLine{#1}% + \fi +}% +\newcommand\sphinxVerbatimHighlightLine[1]{% + \edef\sphinxrestorefboxsep{\fboxsep\the\fboxsep\relax}% + \fboxsep0pt\relax % cf LaTeX bug graphics/4524 + \colorbox{sphinxVerbatimHighlightColor}% + {\sphinxrestorefboxsep\sphinxVerbatimFormatLine{#1}}% + % no need to restore \fboxsep here, as this ends up in a \hbox from fancyvrb +}% +% \sphinxVerbatimFormatLine will be set locally to one of those two: +\newcommand\sphinxVerbatimFormatLineWrap{% + \hsize\linewidth + \ifspx@opt@verbatimforcewraps + \expandafter\spx@verb@FormatLineForceWrap + \else\expandafter\spx@verb@FormatLineWrap + \fi +}% +\newcommand\sphinxVerbatimFormatLineNoWrap[1]{\hb@xt@\linewidth{\strut #1\hss}}% +\long\def\spx@verb@FormatLineWrap#1{% + \vtop{\raggedright\hyphenpenalty\z@\exhyphenpenalty\z@ + \doublehyphendemerits\z@\finalhyphendemerits\z@ + \strut #1\strut}% +}% +% +% The normal line wrapping allows breaks at spaces and ascii non +% letters, non digits. The \raggedright above means there will be +% an overfilled line only if some non-breakable "word" was +% encountered, which is longer than a line (it is moved always to +% be on its own on a new line). +% +% The "forced" line wrapping will parse the tokens to add potential +% breakpoints at each character. As some strings are highlighted, +% we have to apply the highlighting character per character, which +% requires to manipulate the output of the Pygments LaTeXFormatter. +% +% Doing this at latex level is complicated. The contents should +% be as expected: i.e. some active characters from +% \sphinxbreaksviaactive, some Pygments character escapes such as +% \PYGZdl{}, and the highlighting \PYG macro with always 2 +% arguments. No other macros should be there, except perhaps +% zero-parameter macros. In particular: +% - the texcomments Pygments option must be set to False +% +% With pdflatex, Unicode input gives multi-bytes characters +% where the first byte is active. We support the "utf8" macros +% only. "utf8x" is not supported. +% +% The highlighting macro \PYG will be applied character per +% character. Highlighting via a colored background gives thus a +% chain of small colored boxes which may cause some artefact in +% some pdf viewers. Can't do anything here if we do want the line +% break to be possible. +% +% First a measurement step is done of what would the standard line +% wrapping give (i.e line breaks only at spaces and non-letter, +% non-digit ascii characters), cf TeX by Topic for the basic +% dissecting technique: TeX unfortunately when building a vertical +% box does not store in an accessible way what was the maximal +% line-width during paragraph building. +% +% Avoid LaTeX 2021 alteration of \@@par which potentially could break our +% measurement step (typically if the para/after hook is configured to use +% \vspace). Of course, breakage could happen only from user or package +% adding things to basic Sphinx latex. And perhaps spring LaTeX 2021 will +% provide a non-hooked \@@par, but this should work anyway and can't be +% beaten for speed. +\ltx@ifundefined{tex_par:D} +% We could use \@ifl@t@r\fmtversion{2020/02/02}{use \tex_par:D}{use \@@par}. + {\let\spx@par\@@par}% \@@par is then expected to be TeX's original \par + {\expandafter\let\expandafter\spx@par\csname tex_par:D\endcsname} +% More hesitation for avoiding the at-start-of-par hooks for our +% measurement : 1. with old LaTeX, we can not avoid hooks from everyhook +% or similar packages, 2. and perhaps the hooks add stuff which we should +% actually measure. Ideally, hooks are for inserting things in margin +% which do not change spacing. Most everything else in fact should not be +% executed in our scratch box for measurement, such as counter stepping. +\ltx@ifundefined{tex_everypar:D} + {\let\spx@everypar\everypar} + {\expandafter\let\expandafter\spx@everypar\csname tex_everypar:D\endcsname} +% +% If the max width exceeds the linewidth by more than verbatimmaxoverfull +% character widths, or if the min width plus verbatimmaxunderfull character +% widths is inferior to linewidth, then we apply the "force wrapping" with +% potential line break at each character, else we don't. +\long\def\spx@verb@FormatLineForceWrap#1{% + % \spx@image@box is a scratch box register that we can use here + \global\let\spx@verb@maxwidth\z@ + \global\let\spx@verb@minwidth\linewidth + \setbox\spx@image@box + \vtop{\raggedright\hyphenpenalty\z@\exhyphenpenalty\z@ + \doublehyphendemerits\z@\finalhyphendemerits\z@ + \spx@everypar{}\noindent\strut #1\strut\spx@par + \spx@verb@getwidths}% + \ifdim\spx@verb@maxwidth> + \dimexpr\linewidth+\spx@opt@verbatimmaxoverfull\fontcharwd\font`X \relax + \spx@verb@FormatLineWrap{\spx@verb@wrapPYG #1\spx@verb@wrapPYG}% + \else + \ifdim\spx@verb@minwidth< + \dimexpr\linewidth-\spx@opt@verbatimmaxunderfull\fontcharwd\font`X \relax + \spx@verb@FormatLineWrap{\spx@verb@wrapPYG #1\spx@verb@wrapPYG}% + \else + \spx@verb@FormatLineWrap{#1}% + \fi\fi +}% +% auxiliary paragraph dissector to get max and min widths +% but minwidth must not take into account the last line +\newbox\spx@scratchbox +\def\spx@verb@getwidths {% + \unskip\unpenalty + \setbox\spx@scratchbox\lastbox + \ifvoid\spx@scratchbox + \else + \setbox\spx@scratchbox\hbox{\unhbox\spx@scratchbox}% + \ifdim\spx@verb@maxwidth<\wd\spx@scratchbox + \xdef\spx@verb@maxwidth{\number\wd\spx@scratchbox sp}% + \fi + \expandafter\spx@verb@getwidths@loop + \fi +}% +\def\spx@verb@getwidths@loop {% + \unskip\unpenalty + \setbox\spx@scratchbox\lastbox + \ifvoid\spx@scratchbox + \else + \setbox\spx@scratchbox\hbox{\unhbox\spx@scratchbox}% + \ifdim\spx@verb@maxwidth<\wd\spx@scratchbox + \xdef\spx@verb@maxwidth{\number\wd\spx@scratchbox sp}% + \fi + \ifdim\spx@verb@minwidth>\wd\spx@scratchbox + \xdef\spx@verb@minwidth{\number\wd\spx@scratchbox sp}% + \fi + \expandafter\spx@verb@getwidths@loop + \fi +}% +% auxiliary macros to implement "cut long line even in middle of word" +\catcode`Z=3 % safe delimiter +\def\spx@verb@wrapPYG{% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@i +}% +\def\spx@verb@wrapPYG@i{% + \ifx\spx@nexttoken\spx@verb@wrapPYG\let\next=\@gobble\else + \ifx\spx@nexttoken\PYG\let\next=\spx@verb@wrapPYG@PYG@onebyone\else + \discretionary{}{\sphinxafterbreak}{}% + \let\next\spx@verb@wrapPYG@ii + \fi\fi + \next +}% +% Let's recognize active characters. We don't support utf8x only utf8. +% And here #1 should not have picked up (non empty) braced contents +\long\def\spx@verb@wrapPYG@ii#1{% + \ifcat\noexpand~\noexpand#1\relax% active character + \expandafter\spx@verb@wrapPYG@active + \else % non-active character, control sequence such as \PYGZdl, or empty + \expandafter\spx@verb@wrapPYG@one + \fi {#1}% +}% +\long\def\spx@verb@wrapPYG@active#1{% +% Let's hope expansion of active character does not really require arguments, +% as we certainly don't want to go into expanding upfront token stream anyway. + \expandafter\spx@verb@wrapPYG@iii#1{}{}{}{}{}{}{}{}{}Z#1% +}% +\long\def\spx@verb@wrapPYG@iii#1#2Z{% + \ifx\UTFviii@four@octets#1\let\next=\spx@verb@wrapPYG@four\else + \ifx\UTFviii@three@octets#1\let\next=\spx@verb@wrapPYG@three\else + \ifx\UTFviii@two@octets#1\let\next=\spx@verb@wrapPYG@two\else + \let\next=\spx@verb@wrapPYG@one + \fi\fi\fi + \next +}% +\long\def\spx@verb@wrapPYG@one #1{#1\futurelet\spx@nexttoken\spx@verb@wrapPYG@i}% +\long\def\spx@verb@wrapPYG@two #1#2{#1#2\futurelet\spx@nexttoken\spx@verb@wrapPYG@i}% +\long\def\spx@verb@wrapPYG@three #1#2#3{#1#2#3\futurelet\spx@nexttoken\spx@verb@wrapPYG@i}% +\long\def\spx@verb@wrapPYG@four #1#2#3#4{#1#2#3#4\futurelet\spx@nexttoken\spx@verb@wrapPYG@i}% +% Replace \PYG by itself applied one character at a time! This way breakpoints +% can be inserted. +\def\spx@verb@wrapPYG@PYG@onebyone#1#2#3{% #1 = \PYG, #2 = highlight spec, #3 = tokens + \def\spx@verb@wrapPYG@PYG@spec{{#2}}% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@PYG@i#3Z% +}% +\def\spx@verb@wrapPYG@PYG@i{% + \ifx\spx@nexttokenZ\let\next=\spx@verb@wrapPYG@PYG@done\else + \discretionary{}{\sphinxafterbreak}{}% + \let\next\spx@verb@wrapPYG@PYG@ii + \fi + \next +}% +\def\spx@verb@wrapPYG@PYG@doneZ{\futurelet\spx@nexttoken\spx@verb@wrapPYG@i}% +\long\def\spx@verb@wrapPYG@PYG@ii#1{% + \ifcat\noexpand~\noexpand#1\relax% active character + \expandafter\spx@verb@wrapPYG@PYG@active + \else % non-active character, control sequence such as \PYGZdl, or empty + \expandafter\spx@verb@wrapPYG@PYG@one + \fi {#1}% +}% +\long\def\spx@verb@wrapPYG@PYG@active#1{% +% Let's hope expansion of active character does not really require arguments, +% as we certainly don't want to go into expanding upfront token stream anyway. + \expandafter\spx@verb@wrapPYG@PYG@iii#1{}{}{}{}{}{}{}{}{}Z#1% +}% +\long\def\spx@verb@wrapPYG@PYG@iii#1#2Z{% + \ifx\UTFviii@four@octets#1\let\next=\spx@verb@wrapPYG@PYG@four\else + \ifx\UTFviii@three@octets#1\let\next=\spx@verb@wrapPYG@PYG@three\else + \ifx\UTFviii@two@octets#1\let\next=\spx@verb@wrapPYG@PYG@two\else + \let\next=\spx@verb@wrapPYG@PYG@one + \fi\fi\fi + \next +}% +\long\def\spx@verb@wrapPYG@PYG@one#1{% + \expandafter\PYG\spx@verb@wrapPYG@PYG@spec{#1}% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@PYG@i +}% +\long\def\spx@verb@wrapPYG@PYG@two#1#2{% + \expandafter\PYG\spx@verb@wrapPYG@PYG@spec{#1#2}% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@PYG@i +}% +\long\def\spx@verb@wrapPYG@PYG@three#1#2#3{% + \expandafter\PYG\spx@verb@wrapPYG@PYG@spec{#1#2#3}% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@PYG@i +}% +\long\def\spx@verb@wrapPYG@PYG@four#1#2#3#4{% + \expandafter\PYG\spx@verb@wrapPYG@PYG@spec{#1#2#3#4}% + \futurelet\spx@nexttoken\spx@verb@wrapPYG@PYG@i +}% +\catcode`Z 11 % +% +\g@addto@macro\FV@SetupFont{% + \sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}% + \sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}% +}% +\newenvironment{sphinxVerbatim}{% + % first, let's check if there is a caption + \ifx\sphinxVerbatimTitle\empty + \sphinxvspacefixafterfrenchlists + \parskip\z@skip + \vskip\sphinxverbatimsmallskipamount + % there was no caption. Check if nevertheless a label was set. + \ifx\sphinxLiteralBlockLabel\empty\else + % we require some space to be sure hyperlink target from \phantomsection + % will not be separated from upcoming verbatim by a page break + \needspace{\sphinxliteralblockwithoutcaptionneedspace}% + \phantomsection\sphinxLiteralBlockLabel + \fi + \else + \parskip\z@skip + \if t\spx@opt@literalblockcappos + \vskip\spx@abovecaptionskip + \def\sphinxVerbatim@Before + {\sphinxVerbatim@Title\nointerlineskip + \kern\dimexpr-\dp\strutbox+\sphinxbelowcaptionspace + % if no frame (code-blocks inside table cells), remove + % the "verbatimsep" whitespace from the top (better visually) + \ifspx@opt@verbatimwithframe\else-\sphinxverbatimsep\fi + % caption package adds \abovecaptionskip vspace, remove it + \spx@ifcaptionpackage{-\abovecaptionskip}{}\relax}% + \else + \vskip\sphinxverbatimsmallskipamount + \def\sphinxVerbatim@After + {\nointerlineskip\kern\dimexpr\dp\strutbox + \ifspx@opt@verbatimwithframe\else-\sphinxverbatimsep\fi + \spx@ifcaptionpackage{-\abovecaptionskip}{}\relax + \sphinxVerbatim@Title}% + \fi + \def\@captype{literalblock}% + \capstart + % \sphinxVerbatimTitle must reset color + \setbox\sphinxVerbatim@TitleBox + \hbox{\begin{minipage}{\linewidth}% + % caption package may detect wrongly if top or bottom, so we help it + \spx@ifcaptionpackage + {\caption@setposition{\spx@opt@literalblockcappos}}{}% + \sphinxVerbatimTitle + \end{minipage}}% + \fi + \global\let\sphinxLiteralBlockLabel\empty + \global\let\sphinxVerbatimTitle\empty + \fboxsep\sphinxverbatimsep \fboxrule\sphinxverbatimborder + \ifspx@opt@verbatimwithframe\else\fboxrule\z@\fi + \let\FrameCommand \sphinxVerbatim@FrameCommand + \let\FirstFrameCommand\sphinxVerbatim@FirstFrameCommand + \let\MidFrameCommand \sphinxVerbatim@MidFrameCommand + \let\LastFrameCommand \sphinxVerbatim@LastFrameCommand + \ifspx@opt@verbatimhintsturnover\else + \let\sphinxVerbatim@Continued\@empty + \let\sphinxVerbatim@Continues\@empty + \fi + \ifspx@opt@verbatimwrapslines + % fancyvrb's Verbatim puts each input line in (unbreakable) horizontal boxes. + % This customization wraps each line from the input in a \vtop, thus + % allowing it to wrap and display on two or more lines in the latex output. + % - The codeline counter will be increased only once. + % - The wrapped material will not break across pages, it is impossible + % to achieve this without extensive rewrite of fancyvrb. + % - The (not used in sphinx) obeytabs option to Verbatim is + % broken by this change (showtabs and tabspace work). + \let\sphinxVerbatimFormatLine\sphinxVerbatimFormatLineWrap + \let\FV@Space\spx@verbatim@space + % Allow breaks at special characters using \PYG... macros. + \sphinxbreaksatspecials + % Breaks at punctuation characters . , ; ? ! and / (needs catcode activation) + \fvset{codes*=\sphinxbreaksviaactive}% + \else % end of conditional code for wrapping long code lines + \let\sphinxVerbatimFormatLine\sphinxVerbatimFormatLineNoWrap + \fi + \let\FancyVerbFormatLine\sphinxFancyVerbFormatLine + \VerbatimEnvironment + % workaround to fancyvrb's check of current list depth + \def\@toodeep {\advance\@listdepth\@ne}% + % The list environment is needed to control perfectly the vertical space. + % Note: \OuterFrameSep used by framed.sty is later set to \topsep hence 0pt. + % - if caption: distance from last text baseline to caption baseline is + % A+(B-F)+\ht\strutbox, A = \abovecaptionskip (default 10pt), B = + % \baselineskip, F is the framed.sty \FrameHeightAdjust macro, default 6pt. + % Formula valid for F < 10pt. + % - distance of baseline of caption to top of frame is like for tables: + % \sphinxbelowcaptionspace (=0.5\baselineskip) + % - if no caption: distance of last text baseline to code frame is S+(B-F), + % with S = \sphinxverbatimtopskip (=\smallskip) + % - and distance from bottom of frame to next text baseline is + % \baselineskip+\parskip. + % The \trivlist is used to avoid possible "too deeply nested" error. + \itemsep \z@skip + \topsep \z@skip + \partopsep \z@skip + % trivlist will set \parsep to \parskip (which itself is set to zero above) + % \leftmargin will be set to zero by trivlist + \rightmargin\z@ + \parindent \z@% becomes \itemindent. Default zero, but perhaps overwritten. + \trivlist\item\relax + \ifspx@inframed\setbox\sphinxVerbatim@ContentsBox\vbox\bgroup + \@setminipage\hsize\linewidth + % use bulk of minipage paragraph shape restores (this is needed + % in indented contexts, at least for some) + \textwidth\hsize \columnwidth\hsize \@totalleftmargin\z@ + \leftskip\z@skip \rightskip\z@skip \@rightskip\z@skip + \else + \ifsphinxverbatimwithminipage\noindent\begin{minipage}{\linewidth}\fi + \MakeFramed {% adapted over from framed.sty's snugshade environment + \advance\hsize-\width\@totalleftmargin\z@\linewidth\hsize\@setminipage + }% + \fi + % For grid placement from \strut's in \FancyVerbFormatLine + \lineskip\z@skip + % active comma should not be overwritten by \@noligs + \ifspx@opt@verbatimwrapslines + \let\verbatim@nolig@list \sphinx@verbatim@nolig@list + \fi + % will fetch its optional arguments if any + \OriginalVerbatim +} +{% + \endOriginalVerbatim + \ifspx@inframed + \egroup % finish \sphinxVerbatim@ContentsBox vbox + \nobreak % update page totals + \ifdim\dimexpr\ht\sphinxVerbatim@ContentsBox+ + \dp\sphinxVerbatim@ContentsBox+ + \ht\sphinxVerbatim@TitleBox+ + \dp\sphinxVerbatim@TitleBox+ + 2\fboxsep+2\fboxrule+ + % try to account for external frame parameters + \FrameSep+\FrameRule+ + % Usage here of 2 baseline distances is empirical. + % In border case where code-block fits barely in remaining space, + % it gets framed and looks good but the outer frame may continue + % on top of next page and give (if no contents after code-block) + % an empty framed line, as testing showed. + 2\baselineskip+ + % now add all to accumulated page totals and compare to \pagegoal + \pagetotal+\pagedepth>\pagegoal + % long contents: do not \MakeFramed. Do make a caption (either before or + % after) if title exists. Continuation hints across pagebreaks dropped. + % FIXME? a bottom caption may end up isolated at top of next page + % (no problem with a top caption, which is default) + \spx@opt@verbatimwithframefalse + \def\sphinxVerbatim@Title{\noindent\box\sphinxVerbatim@TitleBox\par}% + \sphinxVerbatim@Before + \noindent\unvbox\sphinxVerbatim@ContentsBox\par + \sphinxVerbatim@After + \else + % short enough contents: use \MakeFramed. As it is nested, this requires + % minipage encapsulation. + \noindent\begin{minipage}{\linewidth}% + \MakeFramed {% Use it now with the fetched contents + \advance\hsize-\width\@totalleftmargin\z@\linewidth\hsize\@setminipage + }% + \unvbox\sphinxVerbatim@ContentsBox + % some of this may be superfluous: + \par\unskip\@minipagefalse\endMakeFramed + \end{minipage}% + \fi + \else % non-nested \MakeFramed + \par\unskip\@minipagefalse\endMakeFramed % from framed.sty snugshade + \ifsphinxverbatimwithminipage\end{minipage}\fi + \fi + \endtrivlist +} +\newenvironment {sphinxVerbatimNoFrame} + {\spx@opt@verbatimwithframefalse + \VerbatimEnvironment + \begin{sphinxVerbatim}} + {\end{sphinxVerbatim}} +\newenvironment {sphinxVerbatimintable} + {% don't use a frame if in a table cell + \spx@opt@verbatimwithframefalse + \sphinxverbatimwithminipagetrue + % the literal block caption uses \sphinxcaption which is wrapper of \caption, + % but \caption must be modified because longtable redefines it to work only + % for the own table caption, and tabulary has multiple passes + \let\caption\sphinxfigcaption + % reduce above caption skip + \def\spx@abovecaptionskip{\sphinxverbatimsmallskipamount}% + \VerbatimEnvironment + \begin{sphinxVerbatim}} + {\end{sphinxVerbatim}} + + +%% PARSED LITERALS +% allow long lines to wrap like they do in code-blocks + +% this should be kept in sync with definitions in sphinx.util.texescape +\newcommand*\sphinxbreaksattexescapedchars{% + \def\do##1##2% put potential break point before character + {\def##1{\discretionary{}{\sphinxafterbreak\char`##2}{\char`##2}}}% + \do\{\{\do\textless\<\do\#\#\do\%\%\do\$\$% {, <, #, %, $ + \def\do##1##2% put potential break point after character + {\def##1{\discretionary{\char`##2}{\sphinxafterbreak}{\char`##2}}}% + \do\_\_\do\}\}\do\textasciicircum\^\do\&\&% _, }, ^, &, + \do\textgreater\>\do\textasciitilde\~% >, ~ + \do\textbackslash\\% \ +} +\newcommand*\sphinxbreaksviaactiveinparsedliteral{% + \sphinxbreaksviaactive % by default handles . , ; ? ! / + \lccode`\~`\~ % + % update \dospecials as it is used by \url + % but deactivation will already have been done hence this is unneeded: + % \expandafter\def\expandafter\dospecials\expandafter{\dospecials + % \sphinxbreaksbeforeactivelist\sphinxbreaksafteractivelist\do\-}% +} +\newcommand*\sphinxbreaksatspaceinparsedliteral{% + \lccode`~32 \lowercase{\let~}\spx@verbatim@space\lccode`\~`\~ +} +\newcommand*{\sphinxunactivateextras}{\let\do\@makeother + \sphinxbreaksbeforeactivelist\sphinxbreaksafteractivelist}% +% the \catcode13=5\relax (deactivate end of input lines) is left to callers +\newcommand*{\sphinxunactivateextrasandspace}{\catcode32=10\relax + \sphinxunactivateextras}% +% alltt uses a monospace font and linebreaks at dashes (which are escaped +% to \sphinxhyphen{} which expands to -\kern\z@) are inhibited with pdflatex. +% Not with xelatex (cf \defaultfontfeatures in latex writer), so: +\newcommand*{\sphinxhypheninparsedliteral}{\sphinxhyphennobreak} +% now for the modified alltt environment +\newenvironment{sphinxalltt} +{% at start of next line to workaround Emacs/AUCTeX issue with this file +\begin{alltt}% + \ifspx@opt@parsedliteralwraps + \sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}% + \sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}% + \let\sphinxhyphen\sphinxhypheninparsedliteral + \sphinxbreaksattexescapedchars + \sphinxbreaksviaactiveinparsedliteral + \sphinxbreaksatspaceinparsedliteral +% alltt takes care of the ' as derivative ("prime") in math mode + \everymath\expandafter{\the\everymath\sphinxunactivateextrasandspace + \catcode`\<=12\catcode`\>=12\catcode`\^=7\catcode`\_=8 }% +% not sure if displayed math (align,...) can end up in parsed-literal, anyway + \everydisplay\expandafter{\the\everydisplay + \catcode13=5 \sphinxunactivateextrasandspace + \catcode`\<=12\catcode`\>=12\catcode`\^=7\catcode`\_=8 }% + \fi } +{\end{alltt}} + + +%% INLINE MARK-UP +% + +% Protect \href's first argument in contexts such as sphinxalltt (or +% \sphinxcode). Sphinx uses \#, \%, \& ... always inside \sphinxhref. +\protected\def\sphinxhref#1#2{{% + \sphinxunactivateextrasandspace % never do \scantokens with active space! +% for the \endlinechar business, https://github.com/latex3/latex2e/issues/286 + \endlinechar\m@ne\everyeof{{\endlinechar13 #2}}% keep catcode regime for #2 + \scantokens{\href{#1}}% normalise it for #1 during \href expansion +}} +% Same for \url. And also \nolinkurl for coherence. +\protected\def\sphinxurl#1{{% + \sphinxunactivateextrasandspace\everyeof{}% (<- precaution for \scantokens) + \endlinechar\m@ne\scantokens{\url{#1}}% +}} +\protected\def\sphinxnolinkurl#1{{% + \sphinxunactivateextrasandspace\everyeof{}% + \endlinechar\m@ne\scantokens{\nolinkurl{#1}}% +}} + +% \sphinxupquote +% to obtain straight quotes we execute \@noligs as patched by upquote, and +% \scantokens is needed in cases where it would be too late for the macro to +% first set catcodes and then fetch its argument. We also make the contents +% breakable at non-escaped . , ; ? ! / using \sphinxbreaksviaactive, +% and also at \ character (which is escaped to \textbackslash{}). +\protected\def\sphinxtextbackslashbreakbefore + {\discretionary{}{\sphinxafterbreak\sphinx@textbackslash}{\sphinx@textbackslash}} +\protected\def\sphinxtextbackslashbreakafter + {\discretionary{\sphinx@textbackslash}{\sphinxafterbreak}{\sphinx@textbackslash}} +\let\sphinxtextbackslash\sphinxtextbackslashbreakafter +% - is escaped to \sphinxhyphen{} and this default ensures no linebreak +% behaviour (also with a non monospace font, or with xelatex) +\newcommand*{\sphinxhyphenininlineliteral}{\sphinxhyphennobreak} +% the macro must be protected if it ends up used in moving arguments, +% in 'alltt' \@noligs is done already, and the \scantokens must be avoided. +\protected\def\sphinxupquote#1{{\def\@tempa{alltt}% + \ifx\@tempa\@currenvir\else + \let\sphinxhyphen\sphinxhyphenininlineliteral + \ifspx@opt@inlineliteralwraps + % break at . , ; ? ! / + \sphinxbreaksviaactive + % break also at \ + \setbox8=\hbox{\textbackslash}% + \def\sphinx@textbackslash{\copy8}% + \let\textbackslash\sphinxtextbackslash + % by default, no continuation symbol on next line but may be added + \let\sphinxafterbreak\sphinxafterbreakofinlineliteral + % do not overwrite the comma set-up + \let\verbatim@nolig@list\sphinx@literal@nolig@list + \fi + % fix a space-gobbling issue due to LaTeX's original \do@noligs +% TODO: using \@noligs as patched by upquote.sty is now unneeded because +% either ` and ' are escaped (non-unicode engines) or they don't build +% ligatures (unicode engines). Thus remove this and unify handling of `, <, >, +% ' and - with the characters . , ; ? ! / as handled via +% \sphinxbreaksviaactive. +% Hence \sphinx@do@noligs will be removed, or rather replaced with code +% inserting discretionaries, as they allow a continuation symbol on start of +% next line to achieve common design with code-blocks. + \let\do@noligs\sphinx@do@noligs + \@noligs\endlinechar\m@ne\everyeof{}% (<- in case inside \sphinxhref) + \expandafter\scantokens + \fi {{#1}}}}% extra brace pair to fix end-space gobbling issue... +\def\sphinx@do@noligs #1{\catcode`#1\active\begingroup\lccode`\~`#1\relax + \lowercase{\endgroup\def~{\leavevmode\kern\z@\char`#1 }}} +\def\sphinx@literal@nolig@list {\do\`\do\<\do\>\do\'\do\-}% +\let\sphinxafterbreakofinlineliteral\empty + + +\endinput diff --git a/sphinxlatexnumfig.sty b/sphinxlatexnumfig.sty new file mode 100644 index 0000000..6d72961 --- /dev/null +++ b/sphinxlatexnumfig.sty @@ -0,0 +1,122 @@ +%% NUMBERING OF FIGURES, TABLES, AND LITERAL BLOCKS +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexnumfig.sty}[2021/01/27 numbering] + +% Requires: remreset (old LaTeX only) +% relates to numfig and numfig_secnum_depth configuration variables + +% LaTeX 2018-04-01 and later provides \@removefromreset +\ltx@ifundefined{@removefromreset} + {\RequirePackage{remreset}} + {}% avoid warning +% Everything is delayed to \begin{document} to allow hyperref patches into +% \newcounter to solve duplicate label problems for internal hyperlinks to +% code listings (literalblock counter). User or extension re-definitions of +% \theliteralblock, et al., thus have also to be delayed. (changed at 3.5.0) +\AtBeginDocument{% +\ltx@ifundefined{c@chapter} + {\newcounter{literalblock}}% + {\newcounter{literalblock}[chapter]% + \def\theliteralblock{\ifnum\c@chapter>\z@\arabic{chapter}.\fi + \arabic{literalblock}}% + }% +\ifspx@opt@nonumfigreset + \ltx@ifundefined{c@chapter}{}{% + \@removefromreset{figure}{chapter}% + \@removefromreset{table}{chapter}% + \@removefromreset{literalblock}{chapter}% + \ifspx@opt@mathnumfig + \@removefromreset{equation}{chapter}% + \fi + }% + \def\thefigure{\arabic{figure}}% + \def\thetable {\arabic{table}}% + \def\theliteralblock{\arabic{literalblock}}% + \ifspx@opt@mathnumfig + \def\theequation{\arabic{equation}}% + \fi +\else +\let\spx@preAthefigure\@empty +\let\spx@preBthefigure\@empty +% \ifspx@opt@usespart % <-- LaTeX writer could pass such a 'usespart' boolean +% % as sphinx.sty package option +% If document uses \part, (triggered in Sphinx by latex_toplevel_sectioning) +% LaTeX core per default does not reset chapter or section +% counters at each part. +% But if we modify this, we need to redefine \thechapter, \thesection to +% include the part number and this will cause problems in table of contents +% because of too wide numbering. Simplest is to do nothing. +% \fi +\ifnum\spx@opt@numfigreset>0 + \ltx@ifundefined{c@chapter} + {} + {\g@addto@macro\spx@preAthefigure{\ifnum\c@chapter>\z@\arabic{chapter}.}% + \g@addto@macro\spx@preBthefigure{\fi}}% +\fi +\ifnum\spx@opt@numfigreset>1 + \@addtoreset{figure}{section}% + \@addtoreset{table}{section}% + \@addtoreset{literalblock}{section}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{section}% + \fi% + \g@addto@macro\spx@preAthefigure{\ifnum\c@section>\z@\arabic{section}.}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>2 + \@addtoreset{figure}{subsection}% + \@addtoreset{table}{subsection}% + \@addtoreset{literalblock}{subsection}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{subsection}% + \fi% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subsection>\z@\arabic{subsection}.}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>3 + \@addtoreset{figure}{subsubsection}% + \@addtoreset{table}{subsubsection}% + \@addtoreset{literalblock}{subsubsection}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{subsubsection}% + \fi% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subsubsection>\z@\arabic{subsubsection}.}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>4 + \@addtoreset{figure}{paragraph}% + \@addtoreset{table}{paragraph}% + \@addtoreset{literalblock}{paragraph}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{paragraph}% + \fi% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subparagraph>\z@\arabic{subparagraph}.}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>5 + \@addtoreset{figure}{subparagraph}% + \@addtoreset{table}{subparagraph}% + \@addtoreset{literalblock}{subparagraph}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{subparagraph}% + \fi% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subsubparagraph>\z@\arabic{subsubparagraph}.}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\expandafter\g@addto@macro +\expandafter\spx@preAthefigure\expandafter{\spx@preBthefigure}% +\let\thefigure\spx@preAthefigure +\let\thetable\spx@preAthefigure +\let\theliteralblock\spx@preAthefigure +\g@addto@macro\thefigure{\arabic{figure}}% +\g@addto@macro\thetable{\arabic{table}}% +\g@addto@macro\theliteralblock{\arabic{literalblock}}% + \ifspx@opt@mathnumfig + \let\theequation\spx@preAthefigure + \g@addto@macro\theequation{\arabic{equation}}% + \fi +\fi +}% end of big \AtBeginDocument + +\endinput diff --git a/sphinxlatexobjects.sty b/sphinxlatexobjects.sty new file mode 100644 index 0000000..3deda5c --- /dev/null +++ b/sphinxlatexobjects.sty @@ -0,0 +1,215 @@ +%% MODULE RELEASE DATA AND OBJECT DESCRIPTIONS +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexobjects.sty}[2021/12/05 documentation environments] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - environments +% +% - fulllineitems +% - productionlist +% - optionlist +% - DUlineblock (also "lineblock") +% +% - macros +% +% - \DUrole +% - various legacy support macros related to author and release +% data of documented objects and modules. + +% \moduleauthor{name}{email} +\newcommand{\moduleauthor}[2]{} + +% \sectionauthor{name}{email} +\newcommand{\sectionauthor}[2]{} + +% Allow the release number to be specified independently of the +% \date{}. This allows the date to reflect the document's date and +% release to specify the release that is documented. +% +\newcommand{\py@release}{\releasename\space\version} +\newcommand{\version}{}% part of \py@release, used by title page and headers +% \releaseinfo is used on titlepage (sphinxmanual.cls, sphinxhowto.cls) +\newcommand{\releaseinfo}{} +\newcommand{\setreleaseinfo}[1]{\renewcommand{\releaseinfo}{#1}} +% this is inserted via template and #1=release config variable +\newcommand{\release}[1]{\renewcommand{\version}{#1}} +% this is defined by template to 'releasename' latex_elements key +\newcommand{\releasename}{} +% Fix issue in case release and releasename deliberately left blank +\newcommand{\sphinxheadercomma}{, }% used in fancyhdr header definition +\newcommand{\sphinxifemptyorblank}[1]{% +% test after one expansion of macro #1 if contents is empty or spaces + \if&\expandafter\@firstofone\detokenize\expandafter{#1}&% + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}% +\AtBeginDocument {% + \sphinxifemptyorblank{\releasename} + {\sphinxifemptyorblank{\version}{\let\sphinxheadercomma\empty}{}} + {}% +}% + +% Allow specification of the author's address separately from the +% author's name. This can be used to format them differently, which +% is a good thing. +% +\newcommand{\py@authoraddress}{} +\newcommand{\authoraddress}[1]{\renewcommand{\py@authoraddress}{#1}} + +% {fulllineitems} is the main environment for object descriptions. +% +% With 4.0.0 \pysigline (and \pysiglinewithargsret), used in a fulllineitems +% environment the #1 will already be of the width which is computed here, i.e. +% the available width on line, so the \makebox becomes a bit superfluous +\newcommand{\py@itemnewline}[1]{% macro used as \makelabel in fulllineitems +% Memo: this presupposes \itemindent is 0pt + \kern\labelsep % because \@labels core latex box does \hskip-\labelsep + \makebox[\dimexpr\linewidth+\labelwidth\relax][l]{#1}% + \kern-\labelsep % because at end of \@labels box there is \hskip\labelsep +} + +\newenvironment{fulllineitems}{% + \begin{list}{}{\labelwidth \leftmargin + \rightmargin \z@ \topsep -\parskip \partopsep \parskip + \itemsep -\parsep + \let\makelabel=\py@itemnewline}% +}{\end{list}} + +% Signatures, possibly multi-line +% +\newlength{\py@argswidth} +\newcommand{\py@sigparams}[2]{% + % The \py@argswidth has been computed in \pysiglinewithargsret to make this + % occupy full available width on line. + \parbox[t]{\py@argswidth}{\raggedright #1\sphinxcode{)}#2\strut}% + % final strut is to help get correct vertical separation in case of multi-line + % box with the item contents. +} +\newcommand{\pysigline}[1]{% +% the \py@argswidth is available we use it despite its name (no "args" here) +% the \relax\relax is because \py@argswidth is a "skip" variable and the first +% \relax only ends its "dimen" part + \py@argswidth=\dimexpr\linewidth+\labelwidth\relax\relax + \item[{\parbox[t]{\py@argswidth}{\raggedright #1\strut}}] + \futurelet\sphinx@token\pysigline@preparevspace@i +} +\newcommand{\pysiglinewithargsret}[3]{% + \settowidth{\py@argswidth}{#1\sphinxcode{(}}% + \py@argswidth=\dimexpr\linewidth+\labelwidth-\py@argswidth\relax\relax + \item[{#1\sphinxcode{(}\py@sigparams{#2}{#3}\strut}] + \futurelet\sphinx@token\pysigline@preparevspace@i +} +\def\pysigline@preparevspace@i{% + \ifx\sphinx@token\@sptoken + \expandafter\pysigline@preparevspace@again + \else\expandafter\pysigline@preparevspace@ii + \fi +} +\@firstofone{\def\pysigline@preparevspace@again} {\futurelet\sphinx@token\pysigline@preparevspace@i} +\long\def\pysigline@preparevspace@ii#1{% + \ifx\sphinx@token\bgroup\expandafter\@firstoftwo + \else + \ifx\sphinx@token\phantomsection + \else +% this strange incantation is because at its root LaTeX in fact did not +% imagine a multi-line label, it is always wrapped in a horizontal box at core +% LaTeX level and we have to find tricks to get correct interline distances. +% It interacts badly with a follow-up \phantomsection hence the test above + \leavevmode\par\nobreak\vskip-\parskip\prevdepth\dp\strutbox + \fi + \expandafter\@secondoftwo + \fi + {{#1}}{#1}% +} +\newcommand{\pysigstartmultiline}{% + \def\pysigstartmultiline{\vskip\smallskipamount\parskip\z@skip\itemsep\z@skip}% + \edef\pysigstopmultiline + {\noexpand\leavevmode\parskip\the\parskip\relax\itemsep\the\itemsep\relax}% + \parskip\z@skip\itemsep\z@skip +} + +% Production lists +% +\newenvironment{productionlist}{% +% \def\sphinxoptional##1{{\Large[}##1{\Large]}} + \def\production##1##2{\\\sphinxcode{\sphinxupquote{##1}}&::=&\sphinxcode{\sphinxupquote{##2}}}% + \def\productioncont##1{\\& &\sphinxcode{\sphinxupquote{##1}}}% + \parindent=2em + \indent + \setlength{\LTpre}{0pt}% + \setlength{\LTpost}{0pt}% + \begin{longtable}[l]{lcl} +}{% + \end{longtable} +} + +% Definition lists; requested by AMK for HOWTO documents. Probably useful +% elsewhere as well, so keep in in the general style support. +% +\newenvironment{definitions}{% + \begin{description}% + \def\term##1{\item[{##1}]\mbox{}\\*[0mm]}% +}{% + \end{description}% +} + +%% FROM DOCTUTILS LATEX WRITER +% +% The following is stuff copied from docutils' latex writer. +% +\newcommand{\optionlistlabel}[1]{\normalfont\bfseries #1 \hfill}% \bf deprecated +\newenvironment{optionlist}[1] +{\begin{list}{} + {\setlength{\labelwidth}{#1} + \setlength{\rightmargin}{1cm} + \setlength{\leftmargin}{\rightmargin} + \addtolength{\leftmargin}{\labelwidth} + \addtolength{\leftmargin}{\labelsep} + \renewcommand{\makelabel}{\optionlistlabel}} +}{\end{list}} + +\newlength{\lineblockindentation} +\setlength{\lineblockindentation}{2.5em} +\newenvironment{lineblock}[1] +{\begin{list}{} + {\setlength{\partopsep}{\parskip} + \addtolength{\partopsep}{\baselineskip} + \topsep0pt\itemsep0.15\baselineskip\parsep0pt + \leftmargin#1\relax} + \raggedright} +{\end{list}} + +% From docutils.writers.latex2e +% inline markup (custom roles) +% \DUrole{#1}{#2} tries \DUrole#1{#2} +\providecommand*{\DUrole}[2]{% + \ifcsname DUrole\detokenize{#1}\endcsname + \csname DUrole\detokenize{#1}\endcsname{#2}% + \else% backwards compatibility: try \docutilsrole#1{#2} + \ifcsname docutilsrole\detokenize{#1}\endcsname + \csname docutilsrole\detokenize{#1}\endcsname{#2}% + \else + #2% + \fi + \fi +} + +\providecommand*{\DUprovidelength}[2]{% + \ifdefined#1\else\newlength{#1}\setlength{#1}{#2}\fi +} + +\DUprovidelength{\DUlineblockindent}{2.5em} +\ifdefined\DUlineblock\else + \newenvironment{DUlineblock}[1]{% + \list{}{\setlength{\partopsep}{\parskip} + \addtolength{\partopsep}{\baselineskip} + \setlength{\topsep}{0pt} + \setlength{\itemsep}{0.15\baselineskip} + \setlength{\parsep}{0pt} + \setlength{\leftmargin}{#1}} + \raggedright + } + {\endlist} +\fi + +\endinput diff --git a/sphinxlatexshadowbox.sty b/sphinxlatexshadowbox.sty new file mode 100644 index 0000000..8d6c786 --- /dev/null +++ b/sphinxlatexshadowbox.sty @@ -0,0 +1,100 @@ +%% TOPIC AND CONTENTS BOXES +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexshadowbox.sty}[2021/01/27 sphinxShadowBox] + +% Provides support for this output mark-up from Sphinx latex writer: +% +% - sphinxShadowBox (environment) +% +% Dependencies (they do not need to be defined at time of loading): +% +% - of course the various colour and dimension options handled via sphinx.sty +% - dimension register \spx@image@maxheight from sphinxlatexgraphics.sty +% - \savenotes/\spewnotes from sphinxpackagefootnote +% - \ifspx@inframed defined in sphinx.sty +% +% Requires: +\RequirePackage{framed} + +% Again based on use of "framed.sty", this allows breakable framed boxes. +\long\def\spx@ShadowFBox#1{% + \leavevmode\begingroup + % first we frame the box #1 + \setbox\@tempboxa + \hbox{\vrule\@width\sphinxshadowrule + \vbox{\hrule\@height\sphinxshadowrule + \kern\sphinxshadowsep + \hbox{\kern\sphinxshadowsep #1\kern\sphinxshadowsep}% + \kern\sphinxshadowsep + \hrule\@height\sphinxshadowrule}% + \vrule\@width\sphinxshadowrule}% + % Now we add the shadow, like \shadowbox from fancybox.sty would do + \dimen@\dimexpr.5\sphinxshadowrule+\sphinxshadowsize\relax + \hbox{\vbox{\offinterlineskip + \hbox{\copy\@tempboxa\kern-.5\sphinxshadowrule + % add shadow on right side + \lower\sphinxshadowsize + \hbox{\vrule\@height\ht\@tempboxa \@width\dimen@}% + }% + \kern-\dimen@ % shift back vertically to bottom of frame + % and add shadow at bottom + \moveright\sphinxshadowsize + \vbox{\hrule\@width\wd\@tempboxa \@height\dimen@}% + }% + % move left by the size of right shadow so shadow adds no width + \kern-\sphinxshadowsize + }% + \endgroup +} + +% use framed.sty to allow page breaks in frame+shadow +% works well inside Lists and Quote-like environments +% produced by ``topic'' directive (or local contents) +% could nest if LaTeX writer authorized it +\newenvironment{sphinxShadowBox} + {\def\FrameCommand {\spx@ShadowFBox }% + \advance\spx@image@maxheight + -\dimexpr2\sphinxshadowrule + +2\sphinxshadowsep + +\sphinxshadowsize + +\baselineskip\relax + % configure framed.sty not to add extra vertical spacing + \ltx@ifundefined{OuterFrameSep}{}{\OuterFrameSep\z@skip}% + % the \trivlist will add the vertical spacing on top and bottom which is + % typical of center environment as used in Sphinx <= 1.4.1 + % the \noindent has the effet of an extra blank line on top, to + % imitate closely the layout from Sphinx <= 1.4.1; the \FrameHeightAdjust + % will put top part of frame on this baseline. + \def\FrameHeightAdjust {\baselineskip}% + % use package footnote to handle footnotes + \savenotes + \trivlist\item\noindent + % use a minipage if we are already inside a framed environment + \ifspx@inframed\begin{minipage}{\linewidth}\fi + \MakeFramed {\spx@inframedtrue + % framed.sty puts into "\width" the added width (=2shadowsep+2shadowrule) + % adjust \hsize to what the contents must use + \advance\hsize-\width + % adjust LaTeX parameters to behave properly in indented/quoted contexts + \FrameRestore + % typeset the contents as in a minipage (Sphinx <= 1.4.1 used a minipage and + % itemize/enumerate are therein typeset more tightly, we want to keep + % that). We copy-paste from LaTeX source code but don't do a real minipage. + \@pboxswfalse + \let\@listdepth\@mplistdepth \@mplistdepth\z@ + \@minipagerestore + \@setminipage + }% + }% + {% insert the "endminipage" code + \par\unskip + \@minipagefalse + \endMakeFramed + \ifspx@inframed\end{minipage}\fi + \endtrivlist + % output the stored footnotes + \spewnotes + } + +\endinput diff --git a/sphinxlatexstyleheadings.sty b/sphinxlatexstyleheadings.sty new file mode 100644 index 0000000..fa9be82 --- /dev/null +++ b/sphinxlatexstyleheadings.sty @@ -0,0 +1,83 @@ +%% TITLES +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexstyleheadings.sty}[2021/01/27 headings] + +\RequirePackage[nobottomtitles*]{titlesec} +\@ifpackagelater{titlesec}{2016/03/15}% + {\@ifpackagelater{titlesec}{2016/03/21}% + {}% + {\newif\ifsphinx@ttlpatch@ok + \IfFileExists{etoolbox.sty}{% + \RequirePackage{etoolbox}% + \patchcmd{\ttlh@hang}{\parindent\z@}{\parindent\z@\leavevmode}% + {\sphinx@ttlpatch@oktrue}{}% + \ifsphinx@ttlpatch@ok + \patchcmd{\ttlh@hang}{\noindent}{}{}{\sphinx@ttlpatch@okfalse}% + \fi + }{}% + \ifsphinx@ttlpatch@ok + \typeout{^^J Package Sphinx Info: ^^J + **** titlesec 2.10.1 successfully patched for bugfix ****^^J}% + \else + \AtEndDocument{\PackageWarningNoLine{sphinx}{^^J% +******** titlesec 2.10.1 has a bug, (section numbers disappear) ......|^^J% +******** and Sphinx could not patch it, perhaps because your local ...|^^J% +******** copy is already fixed without a changed release date. .......|^^J% +******** If not, you must update titlesec! ...........................|}}% + \fi + }% + }{} + +% Augment the sectioning commands used to get our own font family in place, +% and reset some internal data items (\titleformat from titlesec package) +\titleformat{\section}{\Large\py@HeaderFamily}% + {\py@TitleColor\thesection}{0.5em}{\py@TitleColor} +\titleformat{\subsection}{\large\py@HeaderFamily}% + {\py@TitleColor\thesubsection}{0.5em}{\py@TitleColor} +\titleformat{\subsubsection}{\py@HeaderFamily}% + {\py@TitleColor\thesubsubsection}{0.5em}{\py@TitleColor} +% By default paragraphs (and subsubsections) will not be numbered because +% sphinxmanual.cls and sphinxhowto.cls set secnumdepth to 2 +\titleformat{\paragraph}{\py@HeaderFamily}% + {\py@TitleColor\theparagraph}{0.5em}{\py@TitleColor} +\titleformat{\subparagraph}{\py@HeaderFamily}% + {\py@TitleColor\thesubparagraph}{0.5em}{\py@TitleColor} + + +% Since Sphinx 1.5, users should use HeaderFamily key to 'sphinxsetup' rather +% than defining their own \py@HeaderFamily command (which is still possible). +% Memo: \py@HeaderFamily is also used by \maketitle as defined in +% sphinxmanual.cls/sphinxhowto.cls +\newcommand{\py@HeaderFamily}{\spx@opt@HeaderFamily} + +% This sets up the fancy chapter headings that make the documents look +% at least a little better than the usual LaTeX output. +\@ifpackagewith{fncychap}{Bjarne}{ + \ChNameVar {\raggedleft\normalsize \py@HeaderFamily} + \ChNumVar {\raggedleft\Large \py@HeaderFamily} + \ChTitleVar{\raggedleft\Large \py@HeaderFamily} + % This creates (numbered) chapter heads without the leading \vspace*{}: + \def\@makechapterhead#1{% + {\parindent \z@ \raggedright \normalfont + \ifnum \c@secnumdepth >\m@ne + \if@mainmatter + \DOCH + \fi + \fi + \interlinepenalty\@M + \if@mainmatter + \DOTI{#1}% + \else% + \DOTIS{#1}% + \fi + }} +}{}% <-- "false" clause of \@ifpackagewith + +% fix fncychap's bug which uses prematurely the \textwidth value +\@ifpackagewith{fncychap}{Bjornstrup} + {\AtBeginDocument{\mylen\textwidth\advance\mylen-2\myhi}}% + {}% <-- "false" clause of \@ifpackagewith + + +\endinput diff --git a/sphinxlatexstylepage.sty b/sphinxlatexstylepage.sty new file mode 100644 index 0000000..4066129 --- /dev/null +++ b/sphinxlatexstylepage.sty @@ -0,0 +1,79 @@ +%% PAGE STYLING +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexstylepage.sty}[2021/01/27 page styling] + +% Separate paragraphs by space by default. +\IfFileExists{parskip-2001-04-09.sty}% since September 2018 TeXLive update +% new parskip.sty, but let it rollback to old one. +% hopefully TeX installation not broken and LaTeX kernel not too old + {\RequirePackage{parskip}[=v1]} +% standard one from 1989. Admittedly \section of article/book gives possibly +% anomalous spacing, but we can't require September 2018 release for some time. + {\RequirePackage{parskip}} + +% Style parameters and macros used by most documents here +\raggedbottom +\sloppy +\hbadness = 5000 % don't print trivial gripes + +% Require package fancyhdr except under memoir class +\@ifclassloaded{memoir}{}{\RequirePackage{fancyhdr}} +% Use \pagestyle{normal} as the primary pagestyle for text. +% Redefine the 'normal' header/footer style when using "fancyhdr" package: +\@ifpackageloaded{fancyhdr}{% + \ltx@ifundefined{c@chapter} + {% no \chapter, "howto" (non-Japanese) docclass + \fancypagestyle{plain}{ + \fancyhf{} + \fancyfoot[C]{{\py@HeaderFamily\thepage}} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0pt} + } + % Same as 'plain', this way we can use it in template + % FIXME: shouldn't this have a running header with Name and Release like 'manual'? + \fancypagestyle{normal}{ + \fancyhf{} + \fancyfoot[C]{{\py@HeaderFamily\thepage}} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0pt} + } + }% + {% classes with \chapter command + \fancypagestyle{normal}{ + \fancyhf{} + \fancyfoot[RO]{{\py@HeaderFamily\thepage}} + \fancyfoot[LO]{{\py@HeaderFamily\nouppercase{\rightmark}}} + \fancyhead[RO]{{\py@HeaderFamily \@title\sphinxheadercomma\py@release}} + \if@twoside + \fancyfoot[LE]{{\py@HeaderFamily\thepage}} + \fancyfoot[RE]{{\py@HeaderFamily\nouppercase{\leftmark}}} + \fancyhead[LE]{{\py@HeaderFamily \@title\sphinxheadercomma\py@release}} + \fi + \renewcommand{\headrulewidth}{0.4pt} + \renewcommand{\footrulewidth}{0.4pt} + % define chaptermark with \@chappos when \@chappos is available for Japanese + \ltx@ifundefined{@chappos}{} + {\def\chaptermark##1{\markboth{\@chapapp\space\thechapter\space\@chappos\space ##1}{}}} + } + % Update the plain style so we get the page number & footer line, + % but not a chapter or section title. This is to keep the first + % page of a chapter `clean.' + \fancypagestyle{plain}{ + \fancyhf{} + \fancyfoot[RO]{{\py@HeaderFamily\thepage}} + \if@twoside\fancyfoot[LE]{{\py@HeaderFamily\thepage}}\fi + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0.4pt} + } + } + } + {% no fancyhdr: memoir class + % Provide default for 'normal' style simply as an alias of 'plain' style + % This way we can use \pagestyle{normal} in LaTeX template + \def\ps@normal{\ps@plain} + % Users of memoir class are invited to redefine 'normal' style in preamble + } + + +\endinput diff --git a/sphinxlatexstyletext.sty b/sphinxlatexstyletext.sty new file mode 100644 index 0000000..539ee0d --- /dev/null +++ b/sphinxlatexstyletext.sty @@ -0,0 +1,134 @@ +%% TEXT STYLING +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexstyletext.sty}[2021/12/06 text styling] + +% Basically everything here consists of macros which are part of the latex +% markup produced by the Sphinx latex writer + +% Some custom font markup commands. +\protected\def\sphinxstrong#1{\textbf{#1}} +\protected\def\sphinxcode#1{\texttt{#1}} +\protected\def\sphinxbfcode#1{\textbf{\sphinxcode{#1}}} +\protected\def\sphinxemail#1{\textsf{#1}} +\protected\def\sphinxtablecontinued#1{\textsf{#1}} +\protected\def\sphinxtitleref#1{\emph{#1}} +\protected\def\sphinxmenuselection#1{\emph{#1}} +\protected\def\sphinxguilabel#1{\emph{#1}} +\protected\def\sphinxkeyboard#1{\sphinxcode{#1}} +\protected\def\sphinxaccelerator#1{\underline{#1}} +\protected\def\sphinxcrossref#1{\emph{#1}} +\protected\def\sphinxtermref#1{\emph{#1}} +% \optional is used for ``[, arg]``, i.e. desc_optional nodes. +\long\protected\def\sphinxoptional#1{% + {\textnormal{\Large[}}{#1}\hspace{0.5mm}{\textnormal{\Large]}}} + +% additional customizable styling +\def\sphinxstyleindexentry #1{\texttt{#1}} +\def\sphinxstyleindexextra #1{ (\emph{#1})} +\def\sphinxstyleindexpageref #1{, \pageref{#1}} +\def\sphinxstyleindexpagemain#1{\textbf{#1}} +\def\spxentry{\@backslashchar spxentry}% let to \sphinxstyleindexentry in index +\def\spxextra{\@backslashchar spxextra}% let to \sphinxstyleindexextra in index +\def\sphinxstyleindexlettergroup #1% + {{\Large\sffamily#1}\nopagebreak\vspace{1mm}} +\def\sphinxstyleindexlettergroupDefault #1% + {{\Large\sffamily\sphinxnonalphabeticalgroupname}\nopagebreak\vspace{1mm}} +\protected\def\sphinxstyletopictitle #1{\textbf{#1}\par\medskip} +\let\sphinxstylesidebartitle\sphinxstyletopictitle +\protected\def\sphinxstyleothertitle #1{\textbf{#1}} +\protected\def\sphinxstylesidebarsubtitle #1{~\\\textbf{#1} \smallskip} +% \text.. commands do not allow multiple paragraphs +\protected\def\sphinxstyletheadfamily {\sffamily} +\protected\def\sphinxstyleemphasis #1{\emph{#1}} +\protected\def\sphinxstyleliteralemphasis#1{\emph{\sphinxcode{#1}}} +\protected\def\sphinxstylestrong #1{\textbf{#1}} +\protected\def\sphinxstyleliteralstrong#1{\sphinxbfcode{#1}} +\protected\def\sphinxstyleabbreviation #1{\textsc{#1}} +\protected\def\sphinxstyleliteralintitle#1{\sphinxcode{#1}} +\newcommand*\sphinxstylecodecontinued[1]{\footnotesize(#1)}% +\newcommand*\sphinxstylecodecontinues[1]{\footnotesize(#1)}% +% figure legend comes after caption and may contain arbitrary body elements +\newenvironment{sphinxlegend}{\par\small}{\par} +% reduce hyperref "Token not allowed in a PDF string" warnings on PDF builds +\AtBeginDocument{\pdfstringdefDisableCommands{% +% all "protected" macros possibly ending up in section titles should be here +% TODO: examine if \sphinxhref, \sphinxurl, \sphinnolinkurl should be handled + \let\sphinxstyleemphasis \@firstofone + \let\sphinxstyleliteralemphasis \@firstofone + \let\sphinxstylestrong \@firstofone + \let\sphinxstyleliteralstrong \@firstofone + \let\sphinxstyleabbreviation \@firstofone + \let\sphinxstyleliteralintitle \@firstofone + \let\sphinxupquote \@firstofone + \let\sphinxstrong \@firstofone + \let\sphinxcode \@firstofone + \let\sphinxbfcode \@firstofone + \let\sphinxemail \@firstofone + \let\sphinxcrossref \@firstofone + \let\sphinxtermref \@firstofone + \let\sphinxhyphen\sphinxhyphenforbookmarks +}} + +% Special characters +% +% The \kern\z@ is to prevent en-dash and em-dash TeX ligatures. +% A linebreak can occur after the dash in regular text (this is +% normal behaviour of "-" in TeX, it is not related to \kern\z@). +% +% Parsed-literals and inline literals also use the \sphinxhyphen +% but linebreaks there are prevented due to monospace font family. +% (xelatex needs a special addition, cf. sphinxlatexliterals.sty) +% +% Inside code-blocks, dashes are escaped via another macro, from +% Pygments latex output (search for \PYGZhy in sphinxlatexliterals.sty), +% and are configured to allow linebreaks despite the monospace font. +% (the #1 swallows the {} from \sphinxhyphen{} mark-up) +\protected\def\sphinxhyphen#1{-\kern\z@} +\protected\def\sphinxhyphennobreak#1{\mbox{-}} +% The {} from texescape mark-up is kept, else -- gives en-dash in PDF bookmark +\def\sphinxhyphenforbookmarks{-} + +% For curly braces inside \index macro +\def\sphinxleftcurlybrace{\{} +\def\sphinxrightcurlybrace{\}} + +% Declare Unicode characters used by linux tree command to pdflatex utf8/utf8x +\def\spx@bd#1#2{% + \leavevmode + \begingroup + \ifx\spx@bd@height \@undefined\def\spx@bd@height{\baselineskip}\fi + \ifx\spx@bd@width \@undefined\setbox0\hbox{0}\def\spx@bd@width{\wd0 }\fi + \ifx\spx@bd@thickness\@undefined\def\spx@bd@thickness{.6\p@}\fi + \ifx\spx@bd@lower \@undefined\def\spx@bd@lower{\dp\strutbox}\fi + \lower\spx@bd@lower#1{#2}% + \endgroup +}% +\@namedef{sphinx@u2500}% BOX DRAWINGS LIGHT HORIZONTAL + {\spx@bd{\vbox to\spx@bd@height} + {\vss\hrule\@height\spx@bd@thickness + \@width\spx@bd@width\vss}}% +\@namedef{sphinx@u2502}% BOX DRAWINGS LIGHT VERTICAL + {\spx@bd{\hb@xt@\spx@bd@width} + {\hss\vrule\@height\spx@bd@height + \@width \spx@bd@thickness\hss}}% +\@namedef{sphinx@u2514}% BOX DRAWINGS LIGHT UP AND RIGHT + {\spx@bd{\hb@xt@\spx@bd@width} + {\hss\raise.5\spx@bd@height + \hb@xt@\z@{\hss\vrule\@height.5\spx@bd@height + \@width \spx@bd@thickness\hss}% + \vbox to\spx@bd@height{\vss\hrule\@height\spx@bd@thickness + \@width.5\spx@bd@width\vss}}}% +\@namedef{sphinx@u251C}% BOX DRAWINGS LIGHT VERTICAL AND RIGHT + {\spx@bd{\hb@xt@\spx@bd@width} + {\hss + \hb@xt@\z@{\hss\vrule\@height\spx@bd@height + \@width \spx@bd@thickness\hss}% + \vbox to\spx@bd@height{\vss\hrule\@height\spx@bd@thickness + \@width.5\spx@bd@width\vss}}}% +\protected\def\sphinxunichar#1{\@nameuse{sphinx@u#1}}% + +% Tell TeX about pathological hyphenation cases: +\hyphenation{Base-HTTP-Re-quest-Hand-ler} + +\endinput diff --git a/sphinxlatextables.sty b/sphinxlatextables.sty new file mode 100644 index 0000000..c3c1d6a --- /dev/null +++ b/sphinxlatextables.sty @@ -0,0 +1,481 @@ +%% TABLES (WITH SUPPORT FOR MERGED CELLS OF GENERAL CONTENTS) +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatextables.sty}[2021/01/27 tables]% + +% Provides support for this output mark-up from Sphinx latex writer +% and table templates: +% +% - the tabulary and longtable environments from the eponymous packages +% - the varwidth environment +% - the >{} etc mark-up possible in tabularcolumns is from array package +% which is loaded by longtable and tabulary +% - \X, \Y, T column types; others (L, C, R, J) are from tabulary package +% - \sphinxaftertopcaption +% - \sphinxatlongtableend +% - \sphinxatlongtablestart +% - \sphinxattableend +% - \sphinxattablestart +% - \sphinxcapstartof +% - \sphinxcolwidth +% - \sphinxlongtablecapskipadjust +% - \sphinxmultirow +% - \sphinxstartmulticolumn +% - \sphinxstopmulticolumn +% - \sphinxtablestrut +% - \sphinxthecaptionisattop +% - \sphinxthelongtablecaptionisattop +% +% Executes \RequirePackage for: +% +% - tabulary +% - longtable +% - varwidth +% +% Extends tabulary and longtable via patches and custom macros to support +% merged cells possibly containing code-blocks in complex tables + +\RequirePackage{tabulary} +% tabulary has a bug with its re-definition of \multicolumn in its first pass +% which is not \long. But now Sphinx does not use LaTeX's \multicolumn but its +% own macro. Hence we don't even need to patch tabulary. See +% sphinxpackagemulticell.sty +% X or S (Sphinx) may have meanings if some table package is loaded hence +% \X was chosen to avoid possibility of conflict +\newcolumntype{\X}[2]{p{\dimexpr + (\linewidth-\arrayrulewidth)*#1/#2-\tw@\tabcolsep-\arrayrulewidth\relax}} +\newcolumntype{\Y}[1]{p{\dimexpr + #1\dimexpr\linewidth-\arrayrulewidth\relax-\tw@\tabcolsep-\arrayrulewidth\relax}} +% using here T (for Tabulary) feels less of a problem than the X could be +\newcolumntype{T}{J}% +% For tables allowing pagebreaks +\RequirePackage{longtable} +% User interface to set-up whitespace before and after tables: +\newcommand*\sphinxtablepre {0pt}% +\newcommand*\sphinxtablepost{\medskipamount}% +% Space from caption baseline to top of table or frame of literal-block +\newcommand*\sphinxbelowcaptionspace{.5\sphinxbaselineskip}% +% as one can not use \baselineskip from inside longtable (it is zero there) +% we need \sphinxbaselineskip, which defaults to \baselineskip +\def\sphinxbaselineskip{\baselineskip}% +% The following is to ensure that, whether tabular(y) or longtable: +% - if a caption is on top of table: +% a) the space between its last baseline and the top rule of table is +% exactly \sphinxbelowcaptionspace +% b) the space from last baseline of previous text to first baseline of +% caption is exactly \parskip+\baselineskip+ height of a strut. +% c) the caption text will wrap at width \LTcapwidth (4in) +% - make sure this works also if "caption" package is loaded by user +% (with its width or margin option taking place of \LTcapwidth role) +% TODO: obtain same for caption of literal block: a) & c) DONE, b) TO BE DONE +% +% To modify space below such top caption, adjust \sphinxbelowcaptionspace +% To add or remove space above such top caption, adjust \sphinxtablepre: +% notice that \abovecaptionskip, \belowcaptionskip, \LTpre are **ignored** +% A. Table with longtable +\def\sphinxatlongtablestart + {\par + \vskip\parskip + \vskip\dimexpr\sphinxtablepre\relax % adjust vertical position + \vbox{}% get correct baseline from above + \LTpre\z@skip\LTpost\z@skip % set to zero longtable's own skips + \edef\sphinxbaselineskip{\dimexpr\the\dimexpr\baselineskip\relax\relax}% + }% +% Compatibility with caption package +\def\sphinxthelongtablecaptionisattop{% + \spx@ifcaptionpackage{\noalign{\vskip-\belowcaptionskip}}{}% +}% +% Achieves exactly \sphinxbelowcaptionspace below longtable caption +\def\sphinxlongtablecapskipadjust + {\dimexpr-\dp\strutbox + -\spx@ifcaptionpackage{\abovecaptionskip}{\sphinxbaselineskip}% + +\sphinxbelowcaptionspace\relax}% +\def\sphinxatlongtableend{\@nobreakfalse % latex3/latex2e#173 + \prevdepth\z@\vskip\sphinxtablepost\relax}% +% B. Table with tabular or tabulary +\def\sphinxattablestart{\par\vskip\dimexpr\sphinxtablepre\relax}% +\let\sphinxattableend\sphinxatlongtableend +% This is used by tabular and tabulary templates +\newcommand*\sphinxcapstartof[1]{% + \vskip\parskip + \vbox{}% force baselineskip for good positioning by capstart of hyperanchor + % hyperref puts the anchor 6pt above this baseline; in case of caption + % this baseline will be \ht\strutbox above first baseline of caption + \def\@captype{#1}% + \capstart +% move back vertically, as tabular (or its caption) will compensate + \vskip-\baselineskip\vskip-\parskip +}% +\def\sphinxthecaptionisattop{% locate it after \sphinxcapstartof + \spx@ifcaptionpackage + {\caption@setposition{t}% + \vskip\baselineskip\vskip\parskip % undo those from \sphinxcapstartof + \vskip-\belowcaptionskip % anticipate caption package skip + % caption package uses a \vbox, not a \vtop, so "single line" case + % gives different result from "multi-line" without this: + \nointerlineskip + }% + {}% +}% +\def\sphinxthecaptionisatbottom{% (not finalized; for template usage) + \spx@ifcaptionpackage{\caption@setposition{b}}{}% +}% +% The aim of \sphinxcaption is to apply to tabular(y) the maximal width +% of caption as done by longtable +\def\sphinxtablecapwidth{\LTcapwidth}% +\newcommand\sphinxcaption{\@dblarg\spx@caption}% +\long\def\spx@caption[#1]#2{% + \noindent\hb@xt@\linewidth{\hss + \vtop{\@tempdima\dimexpr\sphinxtablecapwidth\relax +% don't exceed linewidth for the caption width + \ifdim\@tempdima>\linewidth\hsize\linewidth\else\hsize\@tempdima\fi +% longtable ignores \abovecaptionskip/\belowcaptionskip, so do the same here + \abovecaptionskip\sphinxabovecaptionskip % \z@skip + \belowcaptionskip\sphinxbelowcaptionskip % \z@skip + \caption[{#1}]% + {\strut\ignorespaces#2\ifhmode\unskip\@finalstrut\strutbox\fi}% + }\hss}% + \par\prevdepth\dp\strutbox +}% +\def\sphinxabovecaptionskip{\z@skip}% Do not use! Flagged for removal +\def\sphinxbelowcaptionskip{\z@skip}% Do not use! Flagged for removal +% This wrapper of \abovecaptionskip is used in sphinxVerbatim for top +% caption, and with another value in sphinxVerbatimintable +% TODO: To unify space above caption of a code-block with the one above +% caption of a table/longtable, \abovecaptionskip must not be used +% This auxiliary will get renamed and receive a different meaning +% in future. +\def\spx@abovecaptionskip{\abovecaptionskip}% +% Achieve \sphinxbelowcaptionspace below a caption located above a tabular +% or a tabulary +\newcommand\sphinxaftertopcaption +{% + \spx@ifcaptionpackage + {\par\prevdepth\dp\strutbox\nobreak\vskip-\abovecaptionskip}{\nobreak}% + \vskip\dimexpr\sphinxbelowcaptionspace\relax + \vskip-\baselineskip\vskip-\parskip +}% +% varwidth is crucial for our handling of general contents in merged cells +\RequirePackage{varwidth} +% but addition of a compatibility patch with hyperref is needed +% (tested with varwidth v 0.92 Mar 2009) +\AtBeginDocument {% + \let\@@vwid@Hy@raisedlink\Hy@raisedlink + \long\def\@vwid@Hy@raisedlink#1{\@vwid@wrap{\@@vwid@Hy@raisedlink{#1}}}% + \edef\@vwid@setup{% + \let\noexpand\Hy@raisedlink\noexpand\@vwid@Hy@raisedlink % HYPERREF ! + \unexpanded\expandafter{\@vwid@setup}}% +}% + +%%%%%%%%%%%%%%%%%%%%% +% --- MULTICOLUMN --- +% standard LaTeX's \multicolumn +% 1. does not allow verbatim contents, +% 2. interacts very poorly with tabulary. +% +% It is needed to write own macros for Sphinx: to allow code-blocks in merged +% cells rendered by tabular/longtable, and to allow multi-column cells with +% paragraphs to be taken into account sanely by tabulary algorithm for column +% widths. +% +% This requires quite a bit of hacking. First, in Sphinx, the multi-column +% contents will *always* be wrapped in a varwidth environment. The issue +% becomes to pass it the correct target width. We must trick tabulary into +% believing the multicolumn is simply separate columns, else tabulary does not +% incorporate the contents in its algorithm. But then we must clear the +% vertical rules... +% +% configuration of tabulary +\setlength{\tymin}{3\fontcharwd\font`0 }% minimal width of "squeezed" columns +\setlength{\tymax}{10000pt}% allow enough room for paragraphs to "compete" +% we need access to tabulary's final computed width. \@tempdima is too volatile +% to hope it has kept tabulary's value when \sphinxcolwidth needs it. +\newdimen\sphinx@TY@tablewidth +\def\tabulary{% + \def\TY@final{\sphinx@TY@tablewidth\@tempdima\tabular}% + \let\endTY@final\endtabular + \TY@tabular}% +% next hack is needed only if user has set latex_use_latex_multicolumn to True: +% it fixes tabulary's bug with \multicolumn defined "short" in first pass. (if +% upstream tabulary adds a \long, our extra one causes no harm) +\def\sphinx@tempa #1\def\multicolumn#2#3#4#5#6#7#8#9\sphinx@tempa + {\def\TY@tab{#1\long\def\multicolumn####1####2####3{\multispan####1\relax}#9}}% +\expandafter\sphinx@tempa\TY@tab\sphinx@tempa +% +% TN. 1: as \omit is never executed, Sphinx multicolumn does not need to worry +% like standard multicolumn about |l| vs l|. On the other hand it assumes +% columns are separated by a | ... (if not it will add extraneous +% \arrayrulewidth space for each column separation in its estimate of available +% width). +% +% TN. 1b: as Sphinx multicolumn uses neither \omit nor \span, it can not +% (easily) get rid of extra macros from >{...} or <{...} between columns. At +% least, it has been made compatible with colortbl's \columncolor. +% +% TN. 2: tabulary's second pass is handled like tabular/longtable's single +% pass, with the difference that we hacked \TY@final to set in +% \sphinx@TY@tablewidth the final target width as computed by tabulary. This is +% needed only to handle columns with a "horizontal" specifier: "p" type columns +% (inclusive of tabulary's LJRC) holds the target column width in the +% \linewidth dimension. +% +% TN. 3: use of \begin{sphinxmulticolumn}...\end{sphinxmulticolumn} mark-up +% would need some hacking around the fact that groups can not span across table +% cells (the code does inserts & tokens, see TN1b). It was decided to keep it +% simple with \sphinxstartmulticolumn...\sphinxstopmulticolumn. +% +% MEMO about nesting: if sphinxmulticolumn is encountered in a nested tabular +% inside a tabulary it will think to be at top level in the tabulary. But +% Sphinx generates no nested tables, and if some LaTeX macro uses internally a +% tabular this will not have a \sphinxstartmulticolumn within it! +% +\def\sphinxstartmulticolumn{% + \ifx\equation$% $ tabulary's first pass + \expandafter\sphinx@TYI@start@multicolumn + \else % either not tabulary or tabulary's second pass + \expandafter\sphinx@start@multicolumn + \fi +}% +\def\sphinxstopmulticolumn{% + \ifx\equation$% $ tabulary's first pass + \expandafter\sphinx@TYI@stop@multicolumn + \else % either not tabulary or tabulary's second pass + \ignorespaces + \fi +}% +\def\sphinx@TYI@start@multicolumn#1{% + % use \gdef always to avoid stack space build up + \gdef\sphinx@tempa{#1}\begingroup\setbox\z@\hbox\bgroup +}% +\def\sphinx@TYI@stop@multicolumn{\egroup % varwidth was used with \tymax + \xdef\sphinx@tempb{\the\dimexpr\wd\z@/\sphinx@tempa}% per column width + \endgroup + \expandafter\sphinx@TYI@multispan\expandafter{\sphinx@tempa}% +}% +\def\sphinx@TYI@multispan #1{% + \kern\sphinx@tempb\ignorespaces % the per column occupied width + \ifnum#1>\@ne % repeat, taking into account subtleties of TeX's & ... + \expandafter\sphinx@TYI@multispan@next\expandafter{\the\numexpr#1-\@ne\expandafter}% + \fi +}% +\def\sphinx@TYI@multispan@next{&\relax\sphinx@TYI@multispan}% +% +% Now the branch handling either the second pass of tabulary or the single pass +% of tabular/longtable. This is the delicate part where we gather the +% dimensions from the p columns either set-up by tabulary or by user p column +% or Sphinx \X, \Y columns. The difficulty is that to get the said width, the +% template must be inserted (other hacks would be horribly complicated except +% if we rewrote crucial parts of LaTeX's \@array !) and we can not do +% \omit\span like standard \multicolumn's easy approach. Thus we must cancel +% the \vrule separators. Also, perhaps the column specifier is of the l, c, r +% type, then we attempt an ad hoc rescue to give varwidth a reasonable target +% width. +\def\sphinx@start@multicolumn#1{% + \gdef\sphinx@multiwidth{0pt}\gdef\sphinx@tempa{#1}\sphinx@multispan{#1}% +}% +\def\sphinx@multispan #1{% + \ifnum#1=\@ne\expandafter\sphinx@multispan@end + \else\expandafter\sphinx@multispan@next + \fi {#1}% +}% +\def\sphinx@multispan@next #1{% + % trick to recognize L, C, R, J or p, m, b type columns + \ifdim\baselineskip>\z@ + \gdef\sphinx@tempb{\linewidth}% + \else + % if in an l, r, c type column, try and hope for the best + \xdef\sphinx@tempb{\the\dimexpr(\ifx\TY@final\@undefined\linewidth\else + \sphinx@TY@tablewidth\fi-\arrayrulewidth)/\sphinx@tempa + -\tw@\tabcolsep-\arrayrulewidth\relax}% + \fi + \noindent\kern\sphinx@tempb\relax + \xdef\sphinx@multiwidth + {\the\dimexpr\sphinx@multiwidth+\sphinx@tempb+\tw@\tabcolsep+\arrayrulewidth}% + % hack the \vline and the colortbl macros + \sphinx@hack@vline\sphinx@hack@CT&\relax + % repeat + \expandafter\sphinx@multispan\expandafter{\the\numexpr#1-\@ne}% +}% +% packages like colortbl add group levels, we need to "climb back up" to be +% able to hack the \vline and also the colortbl inserted tokens. This creates +% empty space whether or not the columns were | separated: +\def\sphinx@hack@vline{\ifnum\currentgrouptype=6\relax + \kern\arrayrulewidth\arrayrulewidth\z@\else\aftergroup\sphinx@hack@vline\fi}% +\def\sphinx@hack@CT{\ifnum\currentgrouptype=6\relax + \let\CT@setup\sphinx@CT@setup\else\aftergroup\sphinx@hack@CT\fi}% +% It turns out \CT@row@color is not expanded contrarily to \CT@column@color +% during LaTeX+colortbl preamble preparation, hence it would be possible for +% \sphinx@CT@setup to discard only the column color and choose to obey or not +% row color and cell color. It would even be possible to propagate cell color +% to row color for the duration of the Sphinx multicolumn... the (provisional?) +% choice has been made to cancel the colortbl colours for the multicolumn +% duration. +\def\sphinx@CT@setup #1\endgroup{\endgroup}% hack to remove colour commands +\def\sphinx@multispan@end#1{% + % first, trace back our steps horizontally + \noindent\kern-\dimexpr\sphinx@multiwidth\relax + % and now we set the final computed width for the varwidth environment + \ifdim\baselineskip>\z@ + \xdef\sphinx@multiwidth{\the\dimexpr\sphinx@multiwidth+\linewidth}% + \else + \xdef\sphinx@multiwidth{\the\dimexpr\sphinx@multiwidth+ + (\ifx\TY@final\@undefined\linewidth\else + \sphinx@TY@tablewidth\fi-\arrayrulewidth)/\sphinx@tempa + -\tw@\tabcolsep-\arrayrulewidth\relax}% + \fi + % we need to remove colour set-up also for last cell of the multi-column + \aftergroup\sphinx@hack@CT +}% +\newcommand*\sphinxcolwidth[2]{% + % this dimension will always be used for varwidth, and serves as maximum + % width when cells are merged either via multirow or multicolumn or both, + % as always their contents is wrapped in varwidth environment. + \ifnum#1>\@ne % multi-column (and possibly also multi-row) + % we wrote our own multicolumn code especially to handle that (and allow + % verbatim contents) + \ifx\equation$%$ + \tymax % first pass of tabulary (cf MEMO above regarding nesting) + \else % the \@gobble thing is for compatibility with standard \multicolumn + \sphinx@multiwidth\@gobble{#1/#2}% + \fi + \else % single column multirow + \ifx\TY@final\@undefined % not a tabulary. + \ifdim\baselineskip>\z@ + % in a p{..} type column, \linewidth is the target box width + \linewidth + \else + % l, c, r columns. Do our best. + \dimexpr(\linewidth-\arrayrulewidth)/#2- + \tw@\tabcolsep-\arrayrulewidth\relax + \fi + \else % in tabulary + \ifx\equation$%$% first pass + \tymax % it is set to a big value so that paragraphs can express themselves + \else + % second pass. + \ifdim\baselineskip>\z@ + \linewidth % in a L, R, C, J column or a p, \X, \Y ... + \else + % we have hacked \TY@final to put in \sphinx@TY@tablewidth the table width + \dimexpr(\sphinx@TY@tablewidth-\arrayrulewidth)/#2- + \tw@\tabcolsep-\arrayrulewidth\relax + \fi + \fi + \fi + \fi +}% +% fallback default in case user has set latex_use_latex_multicolumn to True: +% \sphinxcolwidth will use this only inside LaTeX's standard \multicolumn +\def\sphinx@multiwidth #1#2{\dimexpr % #1 to gobble the \@gobble (!) + (\ifx\TY@final\@undefined\linewidth\else\sphinx@TY@tablewidth\fi + -\arrayrulewidth)*#2-\tw@\tabcolsep-\arrayrulewidth\relax}% + +%%%%%%%%%%%%%%%%%% +% --- MULTIROW --- +% standard \multirow +% 1. does not allow verbatim contents, +% 2. does not allow blank lines in its argument, +% 3. its * specifier means to typeset "horizontally" which is very +% bad for paragraph content. 2016 version has = specifier but it +% must be used with p type columns only, else results are bad, +% 4. it requires manual intervention if the contents is too long to fit +% in the asked-for number of rows. +% 5. colour panels (either from \rowcolor or \columncolor) will hide +% the bottom part of multirow text, hence manual tuning is needed +% to put the multirow insertion at the _bottom_. +% +% The Sphinx solution consists in always having contents wrapped +% in a varwidth environment so that it makes sense to estimate how many +% lines it will occupy, and then ensure by insertion of suitable struts +% that the table rows have the needed height. The needed mark-up is done +% by LaTeX writer, which has its own id for the merged cells. +% +% The colour issue is solved by clearing colour panels in all cells, +% whether or not the multirow is single-column or multi-column. +% +% In passing we obtain baseline alignements across rows (only if +% \arraystretch is 1, as LaTeX's does not obey \arraystretch in "p" +% multi-line contents, only first and last line...) +% +% TODO: examine the situation with \arraystretch > 1. The \extrarowheight +% is hopeless for multirow anyhow, it makes baseline alignment strictly +% impossible. +\newcommand\sphinxmultirow[2]{\begingroup + % #1 = nb of spanned rows, #2 = Sphinx id of "cell", #3 = contents + % but let's fetch #3 in a way allowing verbatim contents ! + \def\sphinx@nbofrows{#1}\def\sphinx@cellid{#2}% + \afterassignment\sphinx@multirow\let\next= +}% +\def\sphinx@multirow {% + \setbox\z@\hbox\bgroup\aftergroup\sphinx@@multirow\strut +}% +\def\sphinx@@multirow {% + % The contents, which is a varwidth environment, has been captured in + % \box0 (a \hbox). + % We have with \sphinx@cellid an assigned unique id. The goal is to give + % about the same height to all the involved rows. + % For this Sphinx will insert a \sphinxtablestrut{cell_id} mark-up + % in LaTeX file and the expansion of the latter will do the suitable thing. + \dimen@\dp\z@ + \dimen\tw@\ht\@arstrutbox + \advance\dimen@\dimen\tw@ + \advance\dimen\tw@\dp\@arstrutbox + \count@=\dimen@ % type conversion dim -> int + \count\tw@=\dimen\tw@ + \divide\count@\count\tw@ % TeX division truncates + \advance\dimen@-\count@\dimen\tw@ + % 1300sp is about 0.02pt. For comparison a rule default width is 0.4pt. + % (note that if \count@ holds 0, surely \dimen@>1300sp) + \ifdim\dimen@>1300sp \advance\count@\@ne \fi + % now \count@ holds the count L of needed "lines" + % and \sphinx@nbofrows holds the number N of rows + % we have L >= 1 and N >= 1 + % if L is a multiple of N, ... clear what to do ! + % else write L = qN + r, 1 <= r < N and we will + % arrange for each row to have enough space for: + % q+1 "lines" in each of the first r rows + % q "lines" in each of the (N-r) bottom rows + % for a total of (q+1) * r + q * (N-r) = q * N + r = L + % It is possible that q == 0. + \count\tw@\count@ + % the TeX division truncates + \divide\count\tw@\sphinx@nbofrows\relax + \count4\count\tw@ % q + \multiply\count\tw@\sphinx@nbofrows\relax + \advance\count@-\count\tw@ % r + \expandafter\xdef\csname sphinx@tablestrut_\sphinx@cellid\endcsname + {\noexpand\sphinx@tablestrut{\the\count4}{\the\count@}{\sphinx@cellid}}% + \dp\z@\z@ + % this will use the real height if it is >\ht\@arstrutbox + \sphinxtablestrut{\sphinx@cellid}\box\z@ + \endgroup % group was opened in \sphinxmultirow +}% +\newcommand*\sphinxtablestrut[1]{% + % #1 is a "cell_id", i.e. the id of a merged group of table cells + \csname sphinx@tablestrut_#1\endcsname +}% +% LaTeX typesets the table row by row, hence each execution can do +% an update for the next row. +\newcommand*\sphinx@tablestrut[3]{\begingroup + % #1 = q, #2 = (initially) r, #3 = cell_id, q+1 lines in first r rows + % if #2 = 0, create space for max(q,1) table lines + % if #2 > 0, create space for q+1 lines and decrement #2 + \leavevmode + \count@#1\relax + \ifnum#2=\z@ + \ifnum\count@=\z@\count@\@ne\fi + \else + % next row will be with a #2 decremented by one + \expandafter\xdef\csname sphinx@tablestrut_#3\endcsname + {\noexpand\sphinx@tablestrut{#1}{\the\numexpr#2-\@ne}{#3}}% + \advance\count@\@ne + \fi + \vrule\@height\ht\@arstrutbox + \@depth\dimexpr\count@\ht\@arstrutbox+\count@\dp\@arstrutbox-\ht\@arstrutbox\relax + \@width\z@ + \endgroup + % we need this to avoid colour panels hiding bottom parts of multirow text + \sphinx@hack@CT +}% + +\endinput diff --git a/sphinxmanual.cls b/sphinxmanual.cls new file mode 100644 index 0000000..2e4b30d --- /dev/null +++ b/sphinxmanual.cls @@ -0,0 +1,128 @@ +% +% sphinxmanual.cls for Sphinx (https://www.sphinx-doc.org/) +% + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesClass{sphinxmanual}[2019/12/01 v2.3.0 Document class (Sphinx manual)] + +% chapters starting at odd pages (overridden by 'openany' document option) +\PassOptionsToClass{openright}{\sphinxdocclass} + +% 'oneside' option overriding the 'twoside' default +\newif\if@oneside +\DeclareOption{oneside}{\@onesidetrue} +% Pass remaining document options to the parent class. +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{\sphinxdocclass}} +\ProcessOptions\relax + +% Defaults two-side document +\if@oneside +% nothing to do (oneside is the default) +\else +\PassOptionsToClass{twoside}{\sphinxdocclass} +\fi + +\LoadClass{\sphinxdocclass} + +% Set some sane defaults for section numbering depth and TOC depth. You can +% reset these counters in your preamble. +% +\setcounter{secnumdepth}{2} +\setcounter{tocdepth}{1} + +% Adapt \and command to the flushright context of \sphinxmaketitle, to +% avoid ragged line endings if author names do not fit all on one single line +\DeclareRobustCommand{\and}{% + \end{tabular}\kern-\tabcolsep + \allowbreak + \hskip\dimexpr1em+\tabcolsep\@plus.17fil\begin{tabular}[t]{c}% +}% +% If it is desired that each author name be on its own line, use in preamble: +%\DeclareRobustCommand{\and}{% +% \end{tabular}\kern-\tabcolsep\\\begin{tabular}[t]{c}% +%}% +% Change the title page to look a bit better, and fit in with the fncychap +% ``Bjarne'' style a bit better. +% +\newcommand{\sphinxmaketitle}{% + \let\sphinxrestorepageanchorsetting\relax + \ifHy@pageanchor\def\sphinxrestorepageanchorsetting{\Hy@pageanchortrue}\fi + \hypersetup{pageanchor=false}% avoid duplicate destination warnings + \begin{titlepage}% + \let\footnotesize\small + \let\footnoterule\relax + \noindent\rule{\textwidth}{1pt}\par + \begingroup % for PDF information dictionary + \def\endgraf{ }\def\and{\& }% + \pdfstringdefDisableCommands{\def\\{, }}% overwrite hyperref setup + \hypersetup{pdfauthor={\@author}, pdftitle={\@title}}% + \endgroup + \begin{flushright}% + \sphinxlogo + \py@HeaderFamily + {\Huge \@title \par} + {\itshape\LARGE \py@release\releaseinfo \par} + \vfill + {\LARGE + \begin{tabular}[t]{c} + \@author + \end{tabular}\kern-\tabcolsep + \par} + \vfill\vfill + {\large + \@date \par + \vfill + \py@authoraddress \par + }% + \end{flushright}%\par + \@thanks + \end{titlepage}% + \setcounter{footnote}{0}% + \let\thanks\relax\let\maketitle\relax + %\gdef\@thanks{}\gdef\@author{}\gdef\@title{} + \clearpage + \ifdefined\sphinxbackoftitlepage\sphinxbackoftitlepage\fi + \if@openright\cleardoublepage\else\clearpage\fi + \sphinxrestorepageanchorsetting +} + +\newcommand{\sphinxtableofcontents}{% + \pagenumbering{roman}% + \begingroup + \parskip \z@skip + \sphinxtableofcontentshook + \tableofcontents + \endgroup + % before resetting page counter, let's do the right thing. + \if@openright\cleardoublepage\else\clearpage\fi + \pagenumbering{arabic}% +} + +% This is needed to get the width of the section # area wide enough in the +% library reference. Doing it here keeps it the same for all the manuals. +% +\newcommand{\sphinxtableofcontentshook}{% + \renewcommand*\l@section{\@dottedtocline{1}{1.5em}{2.6em}}% + \renewcommand*\l@subsection{\@dottedtocline{2}{4.1em}{3.5em}}% +} + +% Fix the bibliography environment to add an entry to the Table of +% Contents. +% For a report document class this environment is a chapter. +% +\newenvironment{sphinxthebibliography}[1]{% + \if@openright\cleardoublepage\else\clearpage\fi + % \phantomsection % not needed here since TeXLive 2010's hyperref + \begin{thebibliography}{#1}% + \addcontentsline{toc}{chapter}{\bibname}}{\end{thebibliography}} + +% Same for the indices. +% The memoir class already does this, so we don't duplicate it in that case. +% +\@ifclassloaded{memoir} + {\newenvironment{sphinxtheindex}{\begin{theindex}}{\end{theindex}}} + {\newenvironment{sphinxtheindex}{% + \if@openright\cleardoublepage\else\clearpage\fi + \phantomsection % needed as no chapter, section, ... created + \begin{theindex}% + \addcontentsline{toc}{chapter}{\indexname}}{\end{theindex}}} diff --git a/sphinxmessages.sty b/sphinxmessages.sty new file mode 100644 index 0000000..940ac21 --- /dev/null +++ b/sphinxmessages.sty @@ -0,0 +1,21 @@ +% +% sphinxmessages.sty +% +% message resources for Sphinx +% +\ProvidesPackage{sphinxmessages}[2019/01/04 v2.0 Localized LaTeX macros (Sphinx team)] + +\renewcommand{\literalblockcontinuedname}{continued from previous page} +\renewcommand{\literalblockcontinuesname}{continues on next page} +\renewcommand{\sphinxnonalphabeticalgroupname}{Non\sphinxhyphen{}alphabetical} +\renewcommand{\sphinxsymbolsname}{Symbols} +\renewcommand{\sphinxnumbersname}{Numbers} +\def\pageautorefname{page} + +\addto\captionsenglish{\renewcommand{\figurename}{Figure }} +\def\fnum@figure{\figurename\thefigure{}.} + +\addto\captionsenglish{\renewcommand{\tablename}{Table }} +\def\fnum@table{\tablename\thetable{}.} + +\addto\captionsenglish{\renewcommand{\literalblockname}{Listing}} \ No newline at end of file diff --git a/sphinxoptionsgeometry.sty b/sphinxoptionsgeometry.sty new file mode 100644 index 0000000..af5a804 --- /dev/null +++ b/sphinxoptionsgeometry.sty @@ -0,0 +1,54 @@ +%% OPTIONS FOR GEOMETRY +% +% change this info string if making any custom modification +\ProvidesFile{sphinxoptionsgeometry.sty}[2021/01/27 geometry] + +% geometry +\ifx\kanjiskip\@undefined + \PassOptionsToPackage{% + hmargin={\unexpanded{\spx@opt@hmargin}},% + vmargin={\unexpanded{\spx@opt@vmargin}},% + marginpar=\unexpanded{\spx@opt@marginpar}} + {geometry} +\else + % set text width for Japanese documents to be integer multiple of 1zw + % and text height to be integer multiple of \baselineskip + % the execution is delayed to \sphinxsetup then geometry.sty + \normalsize\normalfont + \newcommand*\sphinxtextwidthja[1]{% + \if@twocolumn\tw@\fi + \dimexpr + \numexpr\dimexpr\paperwidth-\tw@\dimexpr#1\relax\relax/ + \dimexpr\if@twocolumn\tw@\else\@ne\fi zw\relax + zw\relax}% + \newcommand*\sphinxmarginparwidthja[1]{% + \dimexpr\numexpr\dimexpr#1\relax/\dimexpr1zw\relax zw\relax}% + \newcommand*\sphinxtextlinesja[1]{% + \numexpr\@ne+\dimexpr\paperheight-\topskip-\tw@\dimexpr#1\relax\relax/ + \baselineskip\relax}% + \ifx\@jsc@uplatextrue\@undefined\else + % the way we found in order for the papersize special written by + % geometry in the dvi file to be correct in case of jsbook class + \ifnum\mag=\@m\else % do nothing special if nomag class option or 10pt + \PassOptionsToPackage{truedimen}{geometry}% + \fi + \fi + \PassOptionsToPackage{% + hmarginratio={1:1},% + textwidth=\unexpanded{\sphinxtextwidthja{\spx@opt@hmargin}},% + vmarginratio={1:1},% + lines=\unexpanded{\sphinxtextlinesja{\spx@opt@vmargin}},% + marginpar=\unexpanded{\sphinxmarginparwidthja{\spx@opt@marginpar}},% + footskip=2\baselineskip,% + }{geometry}% + \AtBeginDocument + {% update a dimension used by the jsclasses + \ifx\@jsc@uplatextrue\@undefined\else\fullwidth\textwidth\fi + % for some reason, jreport normalizes all dimensions with \@settopoint + \@ifclassloaded{jreport} + {\@settopoint\textwidth\@settopoint\textheight\@settopoint\marginparwidth} + {}% <-- "false" clause of \@ifclassloaded + }% +\fi + +\endinput diff --git a/sphinxoptionshyperref.sty b/sphinxoptionshyperref.sty new file mode 100644 index 0000000..b88f108 --- /dev/null +++ b/sphinxoptionshyperref.sty @@ -0,0 +1,35 @@ +%% Bookmarks and hyperlinks +% +% change this info string if making any custom modification +\ProvidesFile{sphinxoptionshyperref.sty}[2021/01/27 hyperref] + +% to make pdf with correct encoded bookmarks in Japanese +% this should precede the hyperref package +\ifx\kanjiskip\@undefined +% for non-Japanese: make sure bookmarks are ok also with lualatex + \PassOptionsToPackage{pdfencoding=unicode}{hyperref} +\else + \RequirePackage{atbegshi} + \ifx\ucs\@undefined + \ifnum 42146=\euc"A4A2 + \AtBeginShipoutFirst{\special{pdf:tounicode EUC-UCS2}} + \else + \AtBeginShipoutFirst{\special{pdf:tounicode 90ms-RKSJ-UCS2}} + \fi + \else + \AtBeginShipoutFirst{\special{pdf:tounicode UTF8-UCS2}} + \fi +\fi + +\ifx\@jsc@uplatextrue\@undefined\else + \PassOptionsToPackage{setpagesize=false}{hyperref} +\fi + +% These options can be overridden inside 'hyperref' key +% or by later use of \hypersetup. +\PassOptionsToPackage{colorlinks,breaklinks,% + linkcolor=InnerLinkColor,filecolor=OuterLinkColor,% + menucolor=OuterLinkColor,urlcolor=OuterLinkColor,% + citecolor=InnerLinkColor}{hyperref} + +\endinput diff --git a/sphinxpackagecyrillic.sty b/sphinxpackagecyrillic.sty new file mode 100644 index 0000000..9aa62fc --- /dev/null +++ b/sphinxpackagecyrillic.sty @@ -0,0 +1,55 @@ +%% CYRILLIC IN NON-CYRILLIC DOCUMENTS (pdflatex only) +% +% refs: https://tex.stackexchange.com/q/460271/ +\ProvidesPackage{sphinxpackagecyrillic}% + [2018/11/21 v2.0 support for Cyrillic in non-Cyrillic documents] +\RequirePackage{kvoptions} +\SetupKeyvalOptions{prefix=spx@cyropt@} % use \spx@cyropt@ prefix +\DeclareBoolOption[false]{Xtwo} +\DeclareBoolOption[false]{TtwoA} +\DeclareDefaultOption{\@unknownoptionerror} +\ProcessLocalKeyvalOptions* % ignore class options + +\ifspx@cyropt@Xtwo +% original code by tex.sx user egreg (updated 2019/10/28): +% https://tex.stackexchange.com/a/460325/ +% 159 Cyrillic glyphs as available in X2 TeX 8bit font encoding +% This assumes inputenc loaded with utf8 option, or LaTeX release +% as recent as 2018/04/01 which does it automatically. + \@tfor\next:=% + {Ё}{Ђ}{Є}{Ѕ}{І}{Ј}{Љ}{Њ}{Ћ}{Ў}{Џ}{А}{Б}{В}{Г}{Д}{Е}{Ж}{З}{И}{Й}% + {К}{Л}{М}{Н}{О}{П}{Р}{С}{Т}{У}{Ф}{Х}{Ц}{Ч}{Ш}{Щ}{Ъ}{Ы}{Ь}{Э}{Ю}% + {Я}{а}{б}{в}{г}{д}{е}{ж}{з}{и}{й}{к}{л}{м}{н}{о}{п}{р}{с}{т}{у}% + {ф}{х}{ц}{ч}{ш}{щ}{ъ}{ы}{ь}{э}{ю}{я}{ё}{ђ}{є}{ѕ}{і}{ј}{љ}{њ}{ћ}% + {ў}{џ}{Ѣ}{ѣ}{Ѫ}{ѫ}{Ѵ}{ѵ}{Ґ}{ґ}{Ғ}{ғ}{Ҕ}{ҕ}{Җ}{җ}{Ҙ}{ҙ}{Қ}{қ}{Ҝ}{ҝ}% + {Ҟ}{ҟ}{Ҡ}{ҡ}{Ң}{ң}{Ҥ}{ҥ}{Ҧ}{ҧ}{Ҩ}{ҩ}{Ҫ}{ҫ}{Ҭ}{ҭ}{Ү}{ү}{Ұ}{ұ}{Ҳ}{ҳ}% + {Ҵ}{ҵ}{Ҷ}{ҷ}{Ҹ}{ҹ}{Һ}{һ}{Ҽ}{ҽ}{Ҿ}{ҿ}{Ӏ}{Ӄ}{ӄ}{Ӆ}{ӆ}{Ӈ}{ӈ}{Ӌ}{ӌ}% + {Ӎ}{ӎ}{Ӕ}{ӕ}{Ә}{ә}{Ӡ}{ӡ}{Ө}{ө}\do + {% + \begingroup\def\IeC{\protect\DeclareTextSymbolDefault}% + \protected@edef\@temp{\endgroup + \@ifl@t@r{\fmtversion}{2019/10/01}{\csname u8:\next\endcsname}{\next}}% + \@temp{X2}% + }% +\else +\ifspx@cyropt@TtwoA +% original code by tex.sx user jfbu: +% https://tex.stackexchange.com/a/460305/ +% 63*2+1=127 Cyrillic glyphs as found in T2A 8bit TeX font-encoding + \@tfor\@tempa:=% + {ae}{a}{b}{chrdsc}{chvcrs}{ch}{c}{dje}{dze}{dzhe}{d}{erev}{ery}{e}% + {f}{ghcrs}{gup}{g}{hdsc}{hrdsn}{h}{ie}{ii}{ishrt}{i}{je}% + {kbeak}{kdsc}{kvcrs}{k}{lje}{l}{m}{ndsc}{ng}{nje}{n}{otld}{o}{p}{r}% + {schwa}{sdsc}{sftsn}{shch}{shha}{sh}{s}{tshe}{t}{ushrt}{u}{v}% + {ya}{yhcrs}{yi}{yo}{yu}{y}{zdsc}{zhdsc}{zh}{z}\do + {% + \expandafter\DeclareTextSymbolDefault\expandafter + {\csname cyr\@tempa\endcsname}{T2A}% + \expandafter\uppercase\expandafter{\expandafter + \def\expandafter\@tempa\expandafter{\@tempa}}% + \expandafter\DeclareTextSymbolDefault\expandafter + {\csname CYR\@tempa\endcsname}{T2A}% + }% + \DeclareTextSymbolDefault{\CYRpalochka}{T2A}% +\fi\fi +\endinput diff --git a/sphinxpackagefootnote.sty b/sphinxpackagefootnote.sty new file mode 100644 index 0000000..a6071cf --- /dev/null +++ b/sphinxpackagefootnote.sty @@ -0,0 +1,396 @@ +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{sphinxpackagefootnote}% + [2021/02/04 v1.1d footnotehyper adapted to sphinx (Sphinx team)] +% Provides support for this output mark-up from Sphinx latex writer: +% - footnote environment +% - savenotes environment (table templates) +% - \sphinxfootnotemark +% +%% +%% Package: sphinxpackagefootnote +%% Version: based on footnotehyper.sty 2021/02/04 v1.1d +%% as available at https://www.ctan.org/pkg/footnotehyper +%% License: the one applying to Sphinx +%% +%% Refer to the PDF documentation at https://www.ctan.org/pkg/footnotehyper for +%% the code comments. +%% +%% Differences: +%% 1. a partial tabulary compatibility layer added (enough for Sphinx mark-up), +%% 2. use of \spx@opt@BeforeFootnote from sphinx.sty, +%% 3. use of \sphinxunactivateextrasandspace from sphinx.sty, +%% 4. macro definition \sphinxfootnotemark, +%% 5. macro definition \sphinxlongtablepatch +%% 6. replaced some \undefined by \@undefined +\newif\iffootnotehyperparse\footnotehyperparsetrue +\DeclareOption*{\PackageWarning{sphinxpackagefootnote}{Option `\CurrentOption' is unknown}}% +\ProcessOptions\relax +\newbox\FNH@notes +\newtoks\FNH@toks % 1.1c +\newdimen\FNH@width +\let\FNH@colwidth\columnwidth +\newif\ifFNH@savingnotes +\AtBeginDocument {% + \let\FNH@latex@footnote \footnote + \let\FNH@latex@footnotetext\footnotetext + \let\FNH@H@@footnotetext \@footnotetext + \let\FNH@H@@mpfootnotetext \@mpfootnotetext + \newenvironment{savenotes} + {\FNH@savenotes\ignorespaces}{\FNH@spewnotes\ignorespacesafterend}% + \let\spewnotes \FNH@spewnotes + \let\footnote \FNH@footnote + \let\footnotetext \FNH@footnotetext + \let\endfootnote \FNH@endfntext + \let\endfootnotetext\FNH@endfntext + \@ifpackageloaded{hyperref} + {\ifHy@hyperfootnotes + \let\FNH@H@@footnotetext\H@@footnotetext + \let\FNH@H@@mpfootnotetext\H@@mpfootnotetext + \else + \let\FNH@hyper@fntext\FNH@nohyp@fntext + \fi}% + {\let\FNH@hyper@fntext\FNH@nohyp@fntext}% +}% +\def\FNH@hyper@fntext{\FNH@fntext\FNH@hyper@fntext@i}% +\def\FNH@nohyp@fntext{\FNH@fntext\FNH@nohyp@fntext@i}% +\def\FNH@fntext #1{% + \ifx\ifmeasuring@\@undefined + \expandafter\@secondoftwo\else\expandafter\@firstofone\fi +% these two lines modified for Sphinx (tabulary compatibility): + {\ifmeasuring@\expandafter\@gobbletwo\else\expandafter\@firstofone\fi}% + {\ifx\equation$\expandafter\@gobbletwo\fi #1}%$ +}% +\long\def\FNH@hyper@fntext@i#1{% + \global\setbox\FNH@notes\vbox + {\unvbox\FNH@notes + \FNH@startnote + \@makefntext + {\rule\z@\footnotesep\ignorespaces + \ifHy@nesting\expandafter\ltx@firstoftwo + \else\expandafter\ltx@secondoftwo + \fi + {\expandafter\hyper@@anchor\expandafter{\Hy@footnote@currentHref}{#1}}% + {\Hy@raisedlink + {\expandafter\hyper@@anchor\expandafter{\Hy@footnote@currentHref}% + {\relax}}% + \let\@currentHref\Hy@footnote@currentHref + \let\@currentlabelname\@empty + #1}% + \@finalstrut\strutbox + }% + \FNH@endnote + }% +}% +\long\def\FNH@nohyp@fntext@i#1{% + \global\setbox\FNH@notes\vbox + {\unvbox\FNH@notes + \FNH@startnote + \@makefntext{\rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}% + \FNH@endnote + }% +}% +\def\FNH@startnote{% + \hsize\FNH@colwidth + \interlinepenalty\interfootnotelinepenalty + \reset@font\footnotesize + \floatingpenalty\@MM + \@parboxrestore + \protected@edef\@currentlabel{\csname p@\@mpfn\endcsname\@thefnmark}% + \color@begingroup +}% +\def\FNH@endnote{\color@endgroup}% +\def\FNH@savenotes{% + \begingroup + \ifFNH@savingnotes\else + \FNH@savingnotestrue + \let\@footnotetext \FNH@hyper@fntext + \let\@mpfootnotetext \FNH@hyper@fntext + \let\H@@mpfootnotetext\FNH@nohyp@fntext + \FNH@width\columnwidth + \let\FNH@colwidth\FNH@width + \global\setbox\FNH@notes\box\voidb@x + \let\FNH@thempfn\thempfn + \let\FNH@mpfn\@mpfn + \ifx\@minipagerestore\relax\let\@minipagerestore\@empty\fi + \expandafter\def\expandafter\@minipagerestore\expandafter{% + \@minipagerestore + \let\thempfn\FNH@thempfn + \let\@mpfn\FNH@mpfn + }% + \fi +}% +\def\FNH@spewnotes {% + \if@endpe\ifx\par\@@par\FNH@toks{}\else + \FNH@toks\expandafter{\expandafter + \def\expandafter\par\expandafter{\par}\@endpetrue}% + \expandafter\expandafter\expandafter + \FNH@toks + \expandafter\expandafter\expandafter + {\expandafter\the\expandafter\FNH@toks + \expandafter\def\expandafter\@par\expandafter{\@par}}% + \expandafter\expandafter\expandafter + \FNH@toks + \expandafter\expandafter\expandafter + {\expandafter\the\expandafter\FNH@toks + \expandafter\everypar\expandafter{\the\everypar}}\fi + \else\FNH@toks{}\fi + \expandafter + \endgroup\the\FNH@toks + \ifFNH@savingnotes\else + \ifvoid\FNH@notes\else + \begingroup + \let\@makefntext\@empty + \let\@finalstrut\@gobble + \let\rule\@gobbletwo + \ifx\@footnotetext\@mpfootnotetext + \expandafter\FNH@H@@mpfootnotetext + \else + \expandafter\FNH@H@@footnotetext + \fi{\unvbox\FNH@notes}% + \endgroup + \fi + \fi +}% +\def\FNH@footnote@envname {footnote}% +\def\FNH@footnotetext@envname{footnotetext}% +\def\FNH@footnote{% +% this line added for Sphinx: + \spx@opt@BeforeFootnote + \ifx\@currenvir\FNH@footnote@envname + \expandafter\FNH@footnoteenv + \else + \expandafter\FNH@latex@footnote + \fi +}% +\def\FNH@footnoteenv{% +% this line added for Sphinx (footnotes in parsed literal blocks): + \catcode13=5 \sphinxunactivateextrasandspace + \@ifnextchar[% + \FNH@footnoteenv@i %] + {\stepcounter\@mpfn + \protected@xdef\@thefnmark{\thempfn}% + \@footnotemark + \def\FNH@endfntext@fntext{\@footnotetext}% + \FNH@startfntext}% +}% +\def\FNH@footnoteenv@i[#1]{% + \begingroup + \csname c@\@mpfn\endcsname #1\relax + \unrestored@protected@xdef\@thefnmark{\thempfn}% + \endgroup + \@footnotemark + \def\FNH@endfntext@fntext{\@footnotetext}% + \FNH@startfntext +}% +\def\FNH@footnotetext{% + \ifx\@currenvir\FNH@footnotetext@envname + \expandafter\FNH@footnotetextenv + \else + \expandafter\FNH@latex@footnotetext + \fi +}% +\def\FNH@footnotetextenv{% + \@ifnextchar[% + \FNH@footnotetextenv@i %] + {\protected@xdef\@thefnmark{\thempfn}% + \def\FNH@endfntext@fntext{\@footnotetext}% + \FNH@startfntext}% +}% +\def\FNH@footnotetextenv@i[#1]{% + \begingroup + \csname c@\@mpfn\endcsname #1\relax + \unrestored@protected@xdef\@thefnmark{\thempfn}% + \endgroup + \ifFNH@savingnotes + \def\FNH@endfntext@fntext{\FNH@nohyp@fntext}% + \else + \def\FNH@endfntext@fntext{\FNH@H@@footnotetext}% + \fi + \FNH@startfntext +}% +\def\FNH@startfntext{% + \setbox\z@\vbox\bgroup + \FNH@startnote + \FNH@prefntext + \rule\z@\footnotesep\ignorespaces +}% +\def\FNH@endfntext {% + \@finalstrut\strutbox + \FNH@postfntext + \FNH@endnote + \egroup + \begingroup + \let\@makefntext\@empty\let\@finalstrut\@gobble\let\rule\@gobbletwo + \FNH@endfntext@fntext {\unvbox\z@}% + \endgroup +}% +\let\FNH@prefntext\@empty +\let\FNH@postfntext\@empty +\AtBeginDocument{\iffootnotehyperparse\expandafter\FNH@check\fi}% +\def\FNH@safeif#1{% + \iftrue\csname if#1\endcsname\csname fi\endcsname\expandafter\@firstoftwo + \else\csname fi\endcsname\expandafter\@secondoftwo + \fi +}% +\def\FNH@check{% + \ifx\@makefntextFB\@undefined\expandafter\FNH@check@ + \else\expandafter\FNH@frenchb@ + \fi +}% +\def\FNH@frenchb@{% + \def\FNH@prefntext{% + \localleftbox{}% + \let\FBeverypar@save\FBeverypar@quote + \let\FBeverypar@quote\relax + \FNH@safeif{FB@koma}% + {\FNH@safeif{FBFrenchFootnotes}% + {\ifx\footnote\thanks + \let\@@makefnmark\@@makefnmarkTH + \@makefntextTH{} % space as in french.ldf + \else + \let\@@makefnmark\@@makefnmarkFB + \@makefntextFB{} % space as in french.ldf + \fi + }{\let\@@makefnmark\@@makefnmarkORI + \@makefntextORI{}% no space as in french.ldf + }% + }% + {\FNH@safeif{FBFrenchFootnotes}% + {\@makefntextFB{}}% + {\@makefntextORI{}}% + }% + }% + \def\FNH@postfntext{% + \let\FBeverypar@quote\FBeverypar@save + \localleftbox{\FBeveryline@quote}% + }% +}% +\def\FNH@check@{% + \expandafter\FNH@check@a\@makefntext{1.2!3?4,}% + \FNH@@@1.2!3?4,\FNH@@@\relax +}% +\long\def\FNH@check@a #11.2!3?4,#2\FNH@@@#3{% + \ifx\relax#3\expandafter\FNH@checkagain@ + \else + \def\FNH@prefntext{#1}\def\FNH@postfntext{#2}% + \expandafter\FNH@check@b + \fi +}% +\def\FNH@checkagain@{% + \expandafter\FNH@checkagain@a + \detokenize\expandafter{\@makefntext{1.2!3?4,}}\relax\FNH@@@ +}% +\edef\FNH@temp{\noexpand\FNH@checkagain@a ##1\string{1.2!3?4,\string}}% +\expandafter\def\FNH@temp#2#3\FNH@@@{% + \ifx\relax#2% + \def\FNH@prefntext{\@makefntext{}}% + \else\FNH@bad@makefntext@alert + \fi +}% +\def\FNH@check@b #1\relax{% + \expandafter\expandafter\expandafter\FNH@check@c + \expandafter\meaning\expandafter\FNH@prefntext + \meaning\FNH@postfntext1.2!3?4,\FNH@check@c\relax +}% +\def\FNH@check@c #11.2!3?4,#2#3\relax{% + \ifx\FNH@check@c#2\else\FNH@bad@makefntext@alert\fi +}% +% slight reformulation for Sphinx +\def\FNH@bad@makefntext@alert{% + \PackageWarningNoLine{sphinxpackagefootnote}% + {Footnotes will be sub-optimal, sorry. This is due to the document class or^^J + some package modifying macro \string\@makefntext.^^J + You can try to report this incompatibility at^^J + https://github.com/sphinx-doc/sphinx with this info:}% + \typeout{\meaning\@makefntext}% + \let\FNH@prefntext\@empty\let\FNH@postfntext\@empty +}% +% this macro from original footnote.sty is not used anymore by Sphinx +% but for simplicity sake let's just keep it as is +\def\makesavenoteenv{\@ifnextchar[\FNH@msne@ii\FNH@msne@i}%] +\def\FNH@msne@i #1{% + \expandafter\let\csname FNH$#1\expandafter\endcsname %$ + \csname #1\endcsname + \expandafter\let\csname endFNH$#1\expandafter\endcsname %$ + \csname end#1\endcsname + \FNH@msne@ii[#1]{FNH$#1}%$ +}% +\def\FNH@msne@ii[#1]#2{% + \expandafter\edef\csname#1\endcsname{% + \noexpand\savenotes + \expandafter\noexpand\csname#2\endcsname + }% + \expandafter\edef\csname end#1\endcsname{% + \expandafter\noexpand\csname end#2\endcsname + \noexpand\expandafter + \noexpand\spewnotes + \noexpand\if@endpe\noexpand\@endpetrue\noexpand\fi + }% +}% +% +% some extras for Sphinx : +% \sphinxfootnotemark: usable in section titles and silently removed from TOCs. +\def\sphinxfootnotemark [#1]% + {\ifx\thepage\relax\else\sphinxfootref{#1}\fi}% +% \sphinxfootref: +% - \spx@opt@BeforeFootnote is from BeforeFootnote sphinxsetup option +% - \ref: +% the latex.py writer inserts a \phantomsection\label{.} +% whenever +% - the footnote was explicitly numbered in sources, +% - or it was in restrained context and is rendered using footnotetext +% +% These are the two types of footnotes that \sphinxfootnotemark must +% handle. But for explicitly numbered footnotes the same number +% can be found in document. So a secondary part in is updated +% at each novel such footnote to know what is the target from then on +% for \sphinxfootnotemark and already encountered [1], or [2],... +% +% LaTeX package varioref is not supported by hyperref (from its doc: "There +% are too many problems with varioref. Nobody has time to sort them out. +% Therefore this package is now unsupported.") So we will simply use our own +% macros to access the page number of footnote text and decide whether to print +% it. \pagename is internationalized by latex-babel. +\def\spx@thefnmark#1#2{% + % #1=label for reference, #2=page where footnote was printed + \ifx\spx@tempa\spx@tempb + % same page + #1% + \else + \sphinxthefootnotemark{#1}{#2}% + \fi +}% +\def\sphinxfootref@get #1#2#3#4#5\relax{% + \def\sphinxfootref@label{#1}% + \def\sphinxfootref@page {#2}% + \def\sphinxfootref@Href {#4}% +}% +\protected\def\sphinxfootref#1{% #1 always explicit number in Sphinx usage + \spx@opt@BeforeFootnote + \ltx@ifundefined{r@\thesphinxscope.#1}% + {\gdef\@thefnmark{?}\H@@footnotemark}% + {\expandafter\expandafter\expandafter\sphinxfootref@get + \csname r@\thesphinxscope.#1\endcsname\relax + \edef\spx@tempa{\thepage}\edef\spx@tempb{\sphinxfootref@page}% + \protected@xdef\@thefnmark{\spx@thefnmark{\sphinxfootref@label}{\sphinxfootref@page}}% + \let\spx@@makefnmark\@makefnmark + \def\@makefnmark{% + \hyper@linkstart{link}{\sphinxfootref@Href}% + \spx@@makefnmark + \hyper@linkend + }% + \H@@footnotemark + \let\@makefnmark\spx@@makefnmark + }% +}% +\AtBeginDocument{% + % let hyperref less complain + \pdfstringdefDisableCommands{\def\sphinxfootnotemark [#1]{}}% + % to obtain hyperlinked footnotes in longtable environment we must replace + % hyperref's patch of longtable's patch of \@footnotetext by our own + \let\LT@p@ftntext\FNH@hyper@fntext + % this *requires* longtable to be used always wrapped in savenotes environment +}% +\endinput +%% +%% End of file `sphinxpackagefootnote.sty'.