Compare commits

...

44 Commits

Author SHA1 Message Date
f0edfe5b23 feat(report): type checking calls 2026-07-20 00:07:53 +02:00
fd371d1c51 feat(report): add T-Assign rule 2026-07-19 22:18:09 +02:00
d4e603c5b1 feat(report): work on some python expressions 2026-07-19 19:14:22 +02:00
c866a6a1d9 feat(report): work on resolver and python statements 2026-07-19 18:08:50 +02:00
66610fdac9 feat(report): add python ast nodes 2026-07-19 12:55:24 +02:00
7ac1d880d7 feat(report): add implementation sub-chapters 2026-07-19 12:22:09 +02:00
d55c5e325c feat(report): write section about variance inference 2026-07-19 11:59:46 +02:00
11420c690c fix(report): adjust heading level 2026-07-18 22:43:11 +02:00
4340e4dff2 feat(report): add input/output files in architecture diagram 2026-07-18 22:42:53 +02:00
ef2d74e889 feat(report): write Midas typer 2026-07-18 19:06:04 +02:00
49d5d321c8 refactor(report): split types and registry sections 2026-07-18 16:53:01 +02:00
10f9f35496 fix(report): improve AST classes appendix 2026-07-18 16:43:55 +02:00
4cc0846887 feat(report): add section about registry 2026-07-18 16:32:20 +02:00
75f847c213 feat(report): add section about types 2026-07-16 18:19:42 +02:00
7232ef2252 fix(report): register midas language 2026-07-16 18:18:01 +02:00
0a2b40d092 chore: add justfile 2026-07-16 16:18:35 +02:00
a8c63d502e feat(report): write Midas lexer and parser 2026-07-16 12:33:16 +02:00
e6c8689ae8 feat(report): write implementation intro and overview 2026-07-16 10:23:59 +02:00
08f81bf4da feat(report): write theory chapter 2026-07-15 19:04:25 +02:00
cc39119789 fix(report): Pylance -> Pyright 2026-07-15 10:14:23 +02:00
64b8a33c7d refactor(report): move theory to separate chapter 2026-07-15 10:13:11 +02:00
4ec15ee6dd feat(report): write introduction 2026-07-13 19:45:34 +02:00
cfeef63ae2 Merge pull request 'Setup report and executive summary' (#1) from feat/report-setup into main
Reviewed-on: #1
2026-07-13 14:24:56 +00:00
9d80ca7fd4 feat(summary): setup executive summary 2026-07-13 16:07:33 +02:00
2e1ded20f4 feat(report): add chapter files 2026-07-13 15:35:08 +02:00
5cdb22c32c feat(report): add draft plan 2026-07-13 15:08:25 +02:00
2e97ce9f4c feat(report): setup report 2026-07-13 11:43:59 +02:00
c8e8f59eb6 feat(journal): add week 9 2026-07-13 11:42:29 +02:00
d76884fc9c feat(journal): add week 8 2026-07-07 12:30:02 +02:00
5e724c6b40 feat(journal): update end of week 7 2026-06-29 08:55:24 +02:00
15c6ec899e feat(journal): update week 7 2026-06-24 16:03:00 +02:00
95e166a058 feat(admin): update planning with current progress 2026-06-22 11:24:42 +02:00
9620e35838 feat(journal): update end of week 6 2026-06-22 11:15:18 +02:00
9317ce370f feat(journal): update week 6 2026-06-19 14:51:28 +02:00
cc6198951c feat(journal): add week 6 day 1 2026-06-16 09:56:45 +02:00
99248b2ba8 feat(journal): update end of week 5 2026-06-15 10:34:52 +02:00
93a3331a87 feat(journal): update week 5 2026-06-11 09:46:35 +02:00
78ecda082e feat(design): add if-else and base midas syntax 2026-06-11 09:34:51 +02:00
a8a6da5661 feat(design): add statement typing rules 2026-06-09 10:45:30 +02:00
4014f6f4e5 feat(journal): update end of week 4 2026-06-08 11:06:11 +02:00
ec4d2473d3 feat(design): some syntax and typing rules 2026-06-03 15:22:53 +02:00
08dc9dd5e9 feat(presentation): add compiled pdf 2026-06-03 09:52:32 +02:00
d5ed18d9be feat(presentation): tweaks 2026-06-03 09:51:56 +02:00
98f94206ac feat(presentation): add halfway presentation 2026-06-03 00:28:57 +02:00
82 changed files with 33324 additions and 2 deletions

2
.gitignore vendored
View File

@@ -1 +1,3 @@
.vscode .vscode
bibliography.bib.bak
bibliography.bib.sav

View File

@@ -1,6 +1,6 @@
#set text(font: "Source Sans 3") #set text(font: "Source Sans 3")
= General Planning = Initial Planning
#table( #table(
columns: (auto, 1fr), columns: (auto, 1fr),
@@ -16,3 +16,20 @@
[*8*], [*8*],
[*9*], [*9*],
) )
= History
#table(
columns: (auto, 1fr),
align: (center, left + horizon),
table.header[*Week*][*Objectives*],
[*1*], [Kickoff, setup project, start prototyping a syntax],
[*2*], [Syntax prototype, simple parser],
[*3*], [Basic type checker (assignments, functions, operations)],
[*4*], [Diagnostics, type check control flow, refine architecture, subtyping],
[*5*], [Generic types, methods and overloads, simple code generator],
[*6*], [For loops, generate assertions, generate stubs, constraints, variance, type unification],
[*7*], [],
[*8*], [],
[*9*], [],
)

117
assets/icon.svg Normal file
View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="128"
height="128"
viewBox="0 0 128 128"
version="1.1"
id="svg1"
inkscape:export-filename="logo.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:version="1.4.4 (1:1.4.4+202605061436+dcaf3e7d9e)"
sodipodi:docname="logo.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="true"
inkscape:zoom="1.9332778"
inkscape:cx="-8.2760999"
inkscape:cy="112.2446"
inkscape:window-width="2584"
inkscape:window-height="1028"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
id="grid1"
units="px"
originx="0"
originy="0"
spacingx="4"
spacingy="4"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="4"
enabled="true"
visible="true" />
</sodipodi:namedview>
<defs
id="defs1">
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689"
id="linearGradient1478"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.562541,0,0,0.567972,-9.399749,-5.305317)"
x1="26.648937"
y1="20.603781"
x2="135.66525"
y2="114.39767" />
<linearGradient
id="linearGradient4689">
<stop
style="stop-color:#e1be1e;stop-opacity:1;"
offset="0"
id="stop4691" />
<stop
style="stop-color:#ffeb82;stop-opacity:1;"
offset="1"
id="stop4693" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4671"
id="linearGradient1475"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.562541,0,0,0.567972,-9.399749,-5.305317)"
x1="150.96111"
y1="192.35176"
x2="112.03144"
y2="137.27299" />
<linearGradient
id="linearGradient4671">
<stop
style="stop-color:#ffdc21;stop-opacity:1;"
offset="0"
id="stop4673" />
<stop
style="stop-color:#ffeb82;stop-opacity:1;"
offset="1"
id="stop4675" />
</linearGradient>
</defs>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g1"
transform="translate(2.911719,3.414527)">
<path
style="fill:url(#linearGradient1478);fill-opacity:1"
d="m 60.510156,6.3979729 c -4.583653,0.021298 -8.960939,0.4122177 -12.8125,1.09375 C 36.35144,9.4962267 34.291407,13.691825 34.291406,21.429223 v 10.21875 h 26.8125 v 3.40625 h -26.8125 -10.0625 c -7.792459,0 -14.6157592,4.683717 -16.7500002,13.59375 -2.46182,10.212966 -2.5710151,16.586023 0,27.25 1.9059283,7.937852 6.4575432,13.593748 14.2500002,13.59375 h 9.21875 v -12.25 c 0,-8.849902 7.657144,-16.656248 16.75,-16.65625 h 26.78125 c 7.454951,0 13.406253,-6.138164 13.40625,-13.625 v -25.53125 c 0,-7.266339 -6.12998,-12.7247775 -13.40625,-13.9375001 -4.605987,-0.7667253 -9.385097,-1.1150483 -13.96875,-1.09375 z m -14.5,8.2187501 c 2.769547,0 5.03125,2.298646 5.03125,5.125 -2e-6,2.816336 -2.261703,5.09375 -5.03125,5.09375 -2.779476,-1e-6 -5.03125,-2.277415 -5.03125,-5.09375 -1e-6,-2.826353 2.251774,-5.125 5.03125,-5.125 z"
id="path1948" />
<path
style="fill:url(#linearGradient1475);fill-opacity:1"
d="m 91.228906,35.054223 v 11.90625 c 0,9.230755 -7.825895,16.999999 -16.75,17 h -26.78125 c -7.335833,0 -13.406249,6.278483 -13.40625,13.625 v 25.531247 c 0,7.26634 6.318588,11.54032 13.40625,13.625 8.487331,2.49561 16.626237,2.94663 26.78125,0 6.750155,-1.95439 13.406253,-5.88761 13.40625,-13.625 V 92.897973 h -26.78125 v -3.40625 h 26.78125 13.406254 c 7.79246,0 10.69625,-5.435408 13.40624,-13.59375 2.79933,-8.398886 2.68022,-16.475776 0,-27.25 -1.92578,-7.757441 -5.60387,-13.59375 -13.40624,-13.59375 z m -15.0625,64.65625 c 2.779478,3e-6 5.03125,2.277417 5.03125,5.093747 -2e-6,2.82635 -2.251775,5.125 -5.03125,5.125 -2.76955,0 -5.03125,-2.29865 -5.03125,-5.125 2e-6,-2.81633 2.261697,-5.093747 5.03125,-5.093747 z"
id="path1950" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

262
design/calculus_rules.typ Normal file
View File

@@ -0,0 +1,262 @@
#import "@preview/curryst:0.6.0": rule, prooftree, rule-set
#import "@preview/codly:1.3.0": codly-init
#show: codly-init
#let syntax(body) = {
set text(weight: "bold", fill: rgb(100, 50, 0))
body
}
#let mk-box(title, body, ..args) = block(
inset: 1em,
stroke: black,
..args,
)[
=== #title
#body
]
#let blank(r, c) = grid.cell(
rowspan: r,
colspan: c
)[]
#let tab = sym.arrow.r.stop
#let nl = move(dx: -2pt, dy: 2pt, sym.arrow.curve.l)
#let syntax-preamble = doc => {
show tab: set text(fill: gray.darken(20%))
show sym.arrow.curve.l: set text(fill: gray.darken(20%))
set math.cases(gap: 4pt)
show math.equation: set align(left)
doc
}
#let python-syntax = mk-box(width: 100%)[Python Syntax][
#show: syntax-preamble
#grid(
columns: (auto, auto, 1fr, auto),
align: (left, left, left, right).map(a => a + horizon),
column-gutter: .4em,
row-gutter: 1.2em,
$"t"$, $::=$, none, [_terms_],
blank(11, 2),
$"x"$, [_variable_],
$"i"$, [_integer literal_],
$"f"$, [_float literal_],
$"z"$, [_string literal_],
$"True"$, [_constant true_],
$"False"$, [_constant false_],
$"None"$, [_constant none_],
$f("t")$, [_call_],
$"t"_21 #syntax[if] "t"_1 #syntax[else] "t"_22$, [_ternary_],
$"t"_1 "op" "t"_2$, [_operation_],
$"s"; "t"$, [_sequence_],
grid.cell(colspan: 4)[],
$"v"$, $::=$, none, [_values_],
blank(6, 2),
$"i"$, [_integer literal_],
$"f"$, [_float literal_],
$"z"$, [_string literal_],
$"True"$, [_constant true_],
$"False"$, [_constant false_],
$"None"$, [_constant none_],
grid.cell(colspan: 4)[],
$"s"$, $::=$, none, [_statements_],
blank(4, 2),
$"x" = "t"$, [_assignment_],
$"x": "T"$, [_variable declaration_],
$ cases(
#syntax[def] f("x": "T") -> "T": #nl,
#tab "t" #nl,
delim: "["
) $, [_def_],
$ cases(
#syntax[if] "t": #nl,
tab "s" #nl,
#syntax[else]: #nl,
tab "s" #nl,
delim: "["
) $, [_if / else_],
)
]
#let midas-syntax = mk-box(width: 100%)[Midas Syntax][
#show: syntax-preamble
#grid(
columns: (auto, auto, 1fr, auto),
align: (left, left, left, right).map(a => a + horizon),
column-gutter: .4em,
row-gutter: 1.2em,
$"T"$, $::=$, none, [_types_],
blank(5, 2),
$"X"$, [_named type_],
$"T" ["T"]$, [_type application_],
$"T" #syntax[where] "c"$, [_constraint type_],
${attach("p"_i: "T"_i, tr: i in 1..n)}$, [_complex type_],
$(attach("a"_i: "T"_i, tr: i in 1..n)) -> "T"$, [_function type_],
grid.cell(colspan: 4)[],
$"s"$, $::=$, none, [_statements_],
blank(2, 2),
$#syntax[type] "X" = "T"$, [_type definition_],
$#syntax[type] "X"["Y"] = "T"$, [_generic definition_],
)
]
#grid(
columns: (1fr, 1fr),
column-gutter: 1em,
python-syntax,
midas-syntax
)
#pagebreak()
#let abs-typ-rules = (
int: rule($Gamma tack "i": "Int"$, name: [(T-Int)]),
float: rule($Gamma tack "f": "Float"$, name: [(T-Float)]),
str: rule($Gamma tack "z": "Str"$, name: [(T-Str)]),
"true": rule($Gamma tack "True": "Bool"$, name: [(T-True)]),
"false": rule($Gamma tack "False": "Bool"$, name: [(T-False)]),
"none": rule($Gamma tack "None": "None"$, name: [(T-None)]),
var: rule(
$"x": "T" in Gamma$,
$Gamma tack "x": "T"$,
name: [(T-Var)]
),
def: rule(
$Gamma, f: "T"_1 -> "T"_2, "x": "T"_1 tack "t": "T"_2$,
$Gamma tack #syntax[def] f("x": "T"_1) -> "T"_2: "t" space tack.l space Gamma, f: "T"_1 -> "T"_2 $,
name: [(T-Def)]
),
call: rule(
$Gamma tack f: "T"_1 -> "T"_2$,
$Gamma tack "t": "T"_1$,
$Gamma tack f("t"): "T"_2$,
name: [(T-Call)]
),
ternary: rule(
$Gamma tack "t"_1: "Bool"$,
$Gamma tack "t"_21: "T"$,
$Gamma tack "t"_22: "T"$,
$Gamma tack "t"_21 #syntax[if] "t"_1 #syntax[else] "t"_22: "T"$,
name: [(T-Tern)]
),
op: rule(
$Gamma tack "t"_1: "T"_1$,
$Gamma tack "t"_2: "T"_2$,
$"op": "T"_1 -> "T"_2 -> "T"_3 in Gamma$,
$Gamma tack "t"_1 "op" "t"_2: "T"_3$,
name: [(T-Op)]
),
seq: rule(
$Gamma tack "s" tack.l Gamma'$,
$Gamma' tack "t": "T"$,
$Gamma tack "s"; "t": "T"$,
name: [(T-Seq)]
),
annot: rule(
$Gamma tack "x": "T" tack.l Gamma, "x": "T"$,
name: [(T-Annot)]
),
if-else: rule(
$Gamma tack "t": "Bool"$,
$Gamma tack "s"_1 tack.l Gamma'$,
$Gamma tack "s"_2 tack.l Gamma''$,
$Gamma tack #syntax[if] "t": "s"_1 #syntax[else]: "s"_2 tack.l Gamma$,
name: [(T-IfElse)]
)
)
#let py-typ-rules = (
int: ```py 12: int```,
float: ```py 12.34: float```,
str: ```py "foo": str```,
"true": ```py True: bool```,
"false": ```py False: bool```,
"none": ```py None: None```,
var: ```py x```,
def: ```py
def func(a: S) -> T:
return ...: T
```,
call: ```py
def func(a: S) -> T: ...
...
func(a: S): T
```,
ternary: ```py (true if cond else false): T ```,
op: ```py (a + b): T```,
annot: ```py x: T```,
if-else: ```py
if cond:
...
else:
...
```,
)
#let reading-keys = (
def: [
_Gamma_ judges that $#syntax[def] f("x": "T"_1) -> "T"_2: "t"$ adds $f: "T"_1 -> "T"_2$ to the context, iff by adding $f: "T"_1 -> "T"_2$ and $"x": "T"_1$ to _Gamma_, it can judge that $"t": "T"_2$
],
annot: [
_Gamma_ judges that $"x": "T"$ adds $"x": "T"$ to the context
],
if-else: [
_Gamma_ judges that $#syntax[if] "t": "s"_1 #syntax[else]: "s"_2$ produces an the unchanged context $Gamma'$, iff _Gamma_ judges that $"t": "Bool"$, that $"s"_1$ produces the context $Gamma'$, and $"s"_2$ produces the context $Gamma''$. This means that statements in
]
)
#mk-box[Python Typing][
#v(1em)
#stack(dir: ltr, spacing: 1fr)[_*Rule*_][_*Python example*_]
#for (i, (k, abs-rule)) in abs-typ-rules.pairs().enumerate() {
let py-rule = py-typ-rules.at(k, default: none)
let reading-key = reading-keys.at(k, default: none)
let cells = (
prooftree(abs-rule),
py-rule
)
if reading-key != none {
cells.push(
grid.cell(
colspan: 2,
inset: (x: .8em, y: .4em),
stroke: (left: gray.lighten(50%) + 2pt),
)[
#set text(size: .8em)
#show math.equation: box.with(
fill: red.lighten(90%),
outset: (y: .3em, x: 1pt),
)
*Reading key*:\
#reading-key
]
)
}
box(
fill: if calc.even(i) {gray.lighten(95%)} else {},
outset: (x: .5em),
inset: (y: .5em),
align(
horizon,
grid(
columns: (auto, 1fr),
column-gutter: 1em,
row-gutter: .5em,
align: (left + horizon, right + horizon),
..cells,
)
)
)
}
]

4000
halfway-presentation/hei.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -0,0 +1,117 @@
#let translations = (
fr: (
_date-fmt: "[day] $month [year repr:full]",
title: "Midas: mieux typer Python",
subtitle: "Présentation intermédiaire",
short-title: "Midas",
supervisor: "Superviseure",
"context": "Contexte",
problematic: "Problématique",
case-1: [Cas 1 -- Type != sémantique],
case-2: [Cas 2 -- Erreur de type _at runtime_],
goal: "Objectif",
gradual-typing: [Typage graduel (_gradual typing_)],
optional-typing: "Typage optionnel",
static-type-checking: "Vérification statique",
dynamic-checks: "Vérificiations dynamiques",
runtime-assertions: [Assertions _at runtime_],
value-constraints: "Contraintes de valeur",
example: "Exemple",
lat-lon-error: "Invalide, même si float+float est valide",
planning: "Planification",
initial-planning: "Planification initiale",
week: "Semaine",
objectives: "Objectifs",
initial-week1: "Kickoff, setup projet, début de prototype de syntaxe",
initial-week2: [Prototype de syntaxe, _parser_ simple],
initial-week3-6: [Implémentation d'un _type checker_],
initial-week7-9: "Générateur de code, améliorations, rapport",
current-status: "État actuel",
current-week1: "Kickoff, setup projet, début de prototype de syntaxe",
current-week2: [Prototype de syntaxe, _parser_ simple],
current-week3: [_Type checker_ basique(assign., fonctions, opérations)],
current-week4: [Diagnostiques, _control flow_, améliorer l'architecture],
current-week5: "Types génériques, sous-typage",
current-week6: "Contraintes",
current-week7-9: "Générateur de code, améliorations, rapport",
demo: "Démo",
def-custom-types: "Définition de types",
write-program: "Écrire un programme",
valid: "Valide",
invalid: "Invalide",
),
en: (
_date-fmt: "$month [day], [year repr:full]",
title: "Midas: better type checking in Python",
subtitle: "Halfway presentation",
short-title: "Midas",
supervisor: "Supervisor",
"context": "Context",
problematic: "Problematic",
case-1: [Case 1 -- Type != semantic],
case-2: [Case 2 -- Runtime type error],
goal: "Goal",
gradual-typing: "Gradual typing",
optional-typing: "Optional typing",
static-type-checking: "Static type checking",
dynamic-checks: "Dynamic checks",
runtime-assertions: "Runtime assertions",
value-constraints: "Value constraints",
example: "Example",
lat-lon-error: "Invalid, even though float+float is valid",
planning: "Planning",
initial-planning: "Initial planning",
week: "Week",
objectives: "Objectives",
initial-week1: "Kickoff, setup project, start prototyping a syntax",
initial-week2: "Syntax prototype, simple parser",
initial-week3-6: "Implement a type checker",
initial-week7-9: "Code generator, refinements, report",
current-status: "Current status",
current-week1: "Kickoff, setup project, start prototyping a syntax",
current-week2: "Syntax prototype, simple parser",
current-week3: "Basic type checker (assignments, functions, operations)",
current-week4: "Diagnostics, type check control flow, refine architecture",
current-week5: "Generic types, subtyping",
current-week6: "Constraints",
current-week7-9: "Code generator, refinements, report",
demo: "Demo",
def-custom-types: "Defining custom types",
write-program: "Writing a program",
valid: "Valid",
invalid: "Invalid",
)
)
#let months = (
fr: (
"Janvier", "Février", "Mars", "Avril",
"Mai", "Juin", "Juillet", "Août",
"Septembre", "Octobre", "Novembre", "Décembre"
),
en: (
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"
)
)
#let i18n(lang, key) = {
let dict = translations.at(lang, default: (:))
return dict.at(
key,
default: "[" + lang + ":" + key + "]"
)
}
#let i18n-date(lang, date) = {
let month = date.month() - 1
let month-name = months.at(lang, default: ()).at(
month,
default: "[" + lang + ":month[" + str(month) + "]]"
)
let fmt = i18n(lang, "_date-fmt").replace("$month", month-name)
return date.display(fmt)
}

View File

@@ -0,0 +1,988 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="482.222" height="84.6667" viewBox="0 0 482.222 84.6667">
<defs>
<g>
<g id="glyph-0-0">
<path d="M 6.6875 0 L 1.8125 0 L 1.8125 -18.765625 L 6.6875 -18.765625 Z M 6.6875 0 "/>
</g>
<g id="glyph-0-1">
<path d="M 5.96875 -13.640625 L 5.96875 -12.375 C 6.28125 -12.84375 6.796875 -13.21875 7.515625 -13.5 C 8.234375 -13.78125 8.976562 -13.921875 9.75 -13.921875 C 11.613281 -13.921875 12.992188 -13.394531 13.890625 -12.34375 C 14.785156 -11.300781 15.234375 -9.847656 15.234375 -7.984375 L 15.234375 0 L 10.53125 0 L 10.53125 -6.890625 C 10.53125 -7.972656 10.359375 -8.742188 10.015625 -9.203125 C 9.679688 -9.660156 9.066406 -9.890625 8.171875 -9.890625 C 7.503906 -9.890625 6.863281 -9.71875 6.25 -9.375 L 6.25 0 L 1.546875 0 L 1.546875 -13.640625 Z M 5.96875 -13.640625 "/>
</g>
<g id="glyph-0-2">
<path d="M 2.796875 -13.640625 L 2.796875 -14.28125 C 2.796875 -16 3.335938 -17.3125 4.421875 -18.21875 C 5.503906 -19.132812 6.894531 -19.59375 8.59375 -19.59375 C 9.5625 -19.59375 10.410156 -19.519531 11.140625 -19.375 L 11.140625 -15.453125 C 10.640625 -15.546875 10.164062 -15.59375 9.71875 -15.59375 C 8.238281 -15.59375 7.5 -14.941406 7.5 -13.640625 L 11.140625 -13.640625 L 11.140625 -9.859375 L 7.5 -9.859375 L 7.5 0 L 2.796875 0 L 2.796875 -9.859375 L 0.84375 -9.859375 L 0.84375 -13.640625 Z M 2.796875 -13.640625 "/>
</g>
<g id="glyph-0-3">
<path d="M 0.984375 -6.828125 C 0.984375 -8.847656 1.710938 -10.535156 3.171875 -11.890625 C 4.640625 -13.242188 6.457031 -13.921875 8.625 -13.921875 C 10.789062 -13.921875 12.613281 -13.242188 14.09375 -11.890625 C 15.582031 -10.535156 16.328125 -8.847656 16.328125 -6.828125 C 16.328125 -4.816406 15.585938 -3.128906 14.109375 -1.765625 C 12.617188 -0.398438 10.789062 0.28125 8.625 0.28125 C 6.457031 0.28125 4.640625 -0.398438 3.171875 -1.765625 C 1.710938 -3.128906 0.984375 -4.816406 0.984375 -6.828125 Z M 6.53125 -4.640625 C 7.050781 -4.066406 7.75 -3.78125 8.625 -3.78125 C 9.5 -3.78125 10.207031 -4.0625 10.75 -4.625 C 11.289062 -5.195312 11.5625 -5.929688 11.5625 -6.828125 C 11.5625 -7.703125 11.289062 -8.429688 10.75 -9.015625 C 10.207031 -9.597656 9.5 -9.890625 8.625 -9.890625 C 7.769531 -9.890625 7.070312 -9.597656 6.53125 -9.015625 C 6 -8.429688 5.734375 -7.703125 5.734375 -6.828125 C 5.734375 -5.929688 6 -5.203125 6.53125 -4.640625 Z M 6.53125 -4.640625 "/>
</g>
<g id="glyph-0-4">
<path d="M 1.546875 -13.640625 L 5.96875 -13.640625 L 5.96875 -12.234375 C 6.25 -12.734375 6.6875 -13.113281 7.28125 -13.375 C 7.875 -13.644531 8.507812 -13.78125 9.1875 -13.78125 C 9.65625 -13.78125 10.140625 -13.722656 10.640625 -13.609375 L 10.640625 -9.375 C 10.046875 -9.4375 9.457031 -9.46875 8.875 -9.46875 C 7.8125 -9.46875 6.9375 -9.328125 6.25 -9.046875 L 6.25 0 L 1.546875 0 Z M 1.546875 -13.640625 "/>
</g>
<g id="glyph-0-5">
<path d="M 5.96875 -13.640625 L 5.96875 -12.375 C 6.28125 -12.84375 6.796875 -13.21875 7.515625 -13.5 C 8.234375 -13.78125 8.976562 -13.921875 9.75 -13.921875 C 11.707031 -13.921875 13.148438 -13.320312 14.078125 -12.125 C 14.421875 -12.644531 14.988281 -13.070312 15.78125 -13.40625 C 16.570312 -13.75 17.367188 -13.921875 18.171875 -13.921875 C 20.078125 -13.921875 21.5625 -13.382812 22.625 -12.3125 C 23.6875 -11.25 24.21875 -9.804688 24.21875 -7.984375 L 24.21875 0 L 19.515625 0 L 19.515625 -6.890625 C 19.515625 -7.972656 19.347656 -8.742188 19.015625 -9.203125 C 18.679688 -9.660156 18.066406 -9.890625 17.171875 -9.890625 C 16.472656 -9.890625 15.796875 -9.710938 15.140625 -9.359375 C 15.203125 -8.921875 15.234375 -8.460938 15.234375 -7.984375 L 15.234375 0 L 10.53125 0 L 10.53125 -6.890625 C 10.53125 -7.972656 10.359375 -8.742188 10.015625 -9.203125 C 9.679688 -9.660156 9.066406 -9.890625 8.171875 -9.890625 C 7.503906 -9.890625 6.863281 -9.71875 6.25 -9.375 L 6.25 0 L 1.546875 0 L 1.546875 -13.640625 Z M 5.96875 -13.640625 "/>
</g>
<g id="glyph-0-6">
<path d="M 2.828125 -11.90625 C 4.054688 -13.25 5.671875 -13.921875 7.671875 -13.921875 C 9.410156 -13.921875 10.625 -13.472656 11.3125 -12.578125 L 11.3125 -13.640625 L 15.734375 -13.640625 L 15.734375 0 L 11.3125 0 L 11.3125 -1.0625 C 10.601562 -0.164062 9.390625 0.28125 7.671875 0.28125 C 5.671875 0.28125 4.054688 -0.394531 2.828125 -1.75 C 1.597656 -3.101562 0.984375 -4.796875 0.984375 -6.828125 C 0.984375 -8.847656 1.597656 -10.539062 2.828125 -11.90625 Z M 6.546875 -4.625 C 7.085938 -4.039062 7.789062 -3.75 8.65625 -3.75 C 9.457031 -3.75 10.269531 -3.992188 11.09375 -4.484375 L 11.09375 -9.1875 C 10.34375 -9.65625 9.53125 -9.890625 8.65625 -9.890625 C 7.789062 -9.890625 7.085938 -9.597656 6.546875 -9.015625 C 6.003906 -8.429688 5.734375 -7.703125 5.734375 -6.828125 C 5.734375 -5.929688 6.003906 -5.195312 6.546875 -4.625 Z M 6.546875 -4.625 "/>
</g>
<g id="glyph-0-7">
<path d="M 2.796875 -13.640625 L 2.796875 -17.046875 L 7.5 -17.046875 L 7.5 -13.640625 L 11.140625 -13.640625 L 11.140625 -9.859375 L 7.5 -9.859375 L 7.5 -6.078125 C 7.5 -5.273438 7.6875 -4.703125 8.0625 -4.359375 C 8.4375 -4.023438 8.988281 -3.859375 9.71875 -3.859375 C 10.164062 -3.859375 10.640625 -3.90625 11.140625 -4 L 11.140625 -0.078125 C 10.410156 0.0664062 9.5625 0.140625 8.59375 0.140625 C 6.851562 0.140625 5.453125 -0.273438 4.390625 -1.109375 C 3.328125 -1.941406 2.796875 -3.207031 2.796875 -4.90625 L 2.796875 -9.859375 L 0.84375 -9.859375 L 0.84375 -13.640625 Z M 2.796875 -13.640625 "/>
</g>
<g id="glyph-0-8">
<path d="M 1.546875 0 L 1.546875 -13.640625 L 6.25 -13.640625 L 6.25 0 Z M 1.203125 -17.78125 C 1.203125 -18.488281 1.460938 -19.097656 1.984375 -19.609375 C 2.503906 -20.128906 3.140625 -20.390625 3.890625 -20.390625 C 4.640625 -20.390625 5.273438 -20.128906 5.796875 -19.609375 C 6.316406 -19.097656 6.578125 -18.488281 6.578125 -17.78125 C 6.578125 -17.070312 6.316406 -16.460938 5.796875 -15.953125 C 5.273438 -15.429688 4.640625 -15.171875 3.890625 -15.171875 C 3.140625 -15.171875 2.503906 -15.425781 1.984375 -15.9375 C 1.460938 -16.457031 1.203125 -17.070312 1.203125 -17.78125 Z M 1.203125 -17.78125 "/>
</g>
<g id="glyph-0-9">
<path d="M 2.828125 -11.90625 C 4.054688 -13.25 5.671875 -13.921875 7.671875 -13.921875 C 9.390625 -13.921875 10.601562 -13.472656 11.3125 -12.578125 L 11.3125 -13.640625 L 15.734375 -13.640625 L 15.734375 5.59375 L 11.03125 5.59375 L 11.03125 -0.75 C 10.25 -0.0625 9.128906 0.28125 7.671875 0.28125 C 5.671875 0.28125 4.054688 -0.394531 2.828125 -1.75 C 1.597656 -3.101562 0.984375 -4.785156 0.984375 -6.796875 C 0.984375 -8.835938 1.597656 -10.539062 2.828125 -11.90625 Z M 6.546875 -4.625 C 7.085938 -4.039062 7.789062 -3.75 8.65625 -3.75 C 9.53125 -3.75 10.34375 -3.984375 11.09375 -4.453125 L 11.09375 -9.15625 C 10.269531 -9.644531 9.457031 -9.890625 8.65625 -9.890625 C 7.789062 -9.890625 7.085938 -9.597656 6.546875 -9.015625 C 6.003906 -8.429688 5.734375 -7.691406 5.734375 -6.796875 C 5.734375 -5.921875 6.003906 -5.195312 6.546875 -4.625 Z M 6.546875 -4.625 "/>
</g>
<g id="glyph-0-10">
<path d="M 1.40625 -13.640625 L 6.109375 -13.640625 L 6.109375 -6.1875 C 6.109375 -5.382812 6.28125 -4.773438 6.625 -4.359375 C 6.96875 -3.953125 7.578125 -3.75 8.453125 -3.75 C 9.109375 -3.75 9.71875 -3.898438 10.28125 -4.203125 L 10.28125 -13.640625 L 14.984375 -13.640625 L 14.984375 0 L 10.578125 0 L 10.578125 -1.140625 C 10.242188 -0.710938 9.722656 -0.367188 9.015625 -0.109375 C 8.304688 0.148438 7.597656 0.28125 6.890625 0.28125 C 5.023438 0.28125 3.644531 -0.238281 2.75 -1.28125 C 1.851562 -2.332031 1.40625 -3.789062 1.40625 -5.65625 Z M 1.40625 -13.640625 "/>
</g>
<g id="glyph-0-11">
<path d="M 15.625 -6.796875 C 15.625 -6.347656 15.597656 -5.898438 15.546875 -5.453125 L 5.59375 -5.453125 C 6.175781 -4.191406 7.53125 -3.5625 9.65625 -3.5625 C 11.132812 -3.5625 12.609375 -3.820312 14.078125 -4.34375 L 14.078125 -0.59375 C 12.703125 -0.0078125 11.085938 0.28125 9.234375 0.28125 C 6.703125 0.28125 4.691406 -0.359375 3.203125 -1.640625 C 1.722656 -2.929688 0.984375 -4.660156 0.984375 -6.828125 C 0.984375 -8.867188 1.675781 -10.5625 3.0625 -11.90625 C 4.457031 -13.25 6.207031 -13.921875 8.3125 -13.921875 C 10.425781 -13.921875 12.171875 -13.25 13.546875 -11.90625 C 14.929688 -10.5625 15.625 -8.859375 15.625 -6.796875 Z M 8.3125 -10.109375 C 6.875 -10.109375 5.941406 -9.472656 5.515625 -8.203125 L 11.03125 -8.203125 C 10.625 -9.472656 9.71875 -10.109375 8.3125 -10.109375 Z M 8.3125 -10.109375 "/>
</g>
<g id="glyph-0-12">
</g>
<g id="glyph-0-13">
<path d="M 2.4375 -12.65625 C 3.40625 -13.5 4.75 -13.921875 6.46875 -13.921875 C 8.28125 -13.921875 9.894531 -13.65625 11.3125 -13.125 L 11.3125 -9.484375 C 9.632812 -10.015625 8.046875 -10.28125 6.546875 -10.28125 C 5.671875 -10.28125 5.234375 -10.070312 5.234375 -9.65625 C 5.234375 -9.46875 5.34375 -9.320312 5.5625 -9.21875 C 5.789062 -9.125 6.203125 -9.007812 6.796875 -8.875 L 7.984375 -8.625 C 9.472656 -8.300781 10.5625 -7.816406 11.25 -7.171875 C 11.945312 -6.535156 12.296875 -5.617188 12.296875 -4.421875 C 12.296875 -3.023438 11.769531 -1.890625 10.71875 -1.015625 C 9.675781 -0.148438 8.164062 0.28125 6.1875 0.28125 C 4.4375 0.28125 2.820312 -0.0234375 1.34375 -0.640625 L 1.34375 -4.484375 C 3.039062 -3.773438 4.722656 -3.421875 6.390625 -3.421875 C 7.472656 -3.421875 8.015625 -3.660156 8.015625 -4.140625 C 8.015625 -4.347656 7.910156 -4.503906 7.703125 -4.609375 C 7.492188 -4.710938 7.09375 -4.816406 6.5 -4.921875 L 5.1875 -5.203125 C 2.382812 -5.804688 0.984375 -7.191406 0.984375 -9.359375 C 0.984375 -10.710938 1.46875 -11.8125 2.4375 -12.65625 Z M 2.4375 -12.65625 "/>
</g>
<g id="glyph-0-14">
<path d="M 0.140625 -13.640625 L 5.234375 -13.640625 L 8.203125 -6.828125 L 11.203125 -13.640625 L 16.21875 -13.640625 L 7.03125 5.59375 L 2.078125 5.59375 L 5.796875 -1.875 Z M 0.140625 -13.640625 "/>
</g>
<g id="glyph-0-15">
<path d="M 9.21875 -19.40625 L 10.046875 -15.171875 L 6.546875 -15.171875 L 4.3125 -19.40625 Z M 15.625 -6.796875 C 15.625 -6.347656 15.597656 -5.898438 15.546875 -5.453125 L 5.59375 -5.453125 C 6.175781 -4.191406 7.53125 -3.5625 9.65625 -3.5625 C 11.132812 -3.5625 12.609375 -3.820312 14.078125 -4.34375 L 14.078125 -0.59375 C 12.703125 -0.0078125 11.085938 0.28125 9.234375 0.28125 C 6.703125 0.28125 4.691406 -0.359375 3.203125 -1.640625 C 1.722656 -2.929688 0.984375 -4.660156 0.984375 -6.828125 C 0.984375 -8.867188 1.675781 -10.5625 3.0625 -11.90625 C 4.457031 -13.25 6.207031 -13.921875 8.3125 -13.921875 C 10.425781 -13.921875 12.171875 -13.25 13.546875 -11.90625 C 14.929688 -10.5625 15.625 -8.859375 15.625 -6.796875 Z M 8.3125 -10.109375 C 6.875 -10.109375 5.941406 -9.472656 5.515625 -8.203125 L 11.03125 -8.203125 C 10.625 -9.472656 9.71875 -10.109375 8.3125 -10.109375 Z M 8.3125 -10.109375 "/>
</g>
<g id="glyph-0-16">
<path d="M 2.828125 -11.90625 C 4.054688 -13.25 5.671875 -13.921875 7.671875 -13.921875 C 9.128906 -13.921875 10.25 -13.570312 11.03125 -12.875 L 11.03125 -19.3125 L 15.734375 -19.3125 L 15.734375 0 L 11.375 0 L 11.375 -1.140625 C 10.65625 -0.191406 9.421875 0.28125 7.671875 0.28125 C 5.671875 0.28125 4.054688 -0.394531 2.828125 -1.75 C 1.597656 -3.101562 0.984375 -4.796875 0.984375 -6.828125 C 0.984375 -8.847656 1.597656 -10.539062 2.828125 -11.90625 Z M 6.546875 -4.625 C 7.085938 -4.039062 7.789062 -3.75 8.65625 -3.75 C 9.457031 -3.75 10.269531 -3.992188 11.09375 -4.484375 L 11.09375 -9.1875 C 10.34375 -9.65625 9.53125 -9.890625 8.65625 -9.890625 C 7.789062 -9.890625 7.085938 -9.597656 6.546875 -9.015625 C 6.003906 -8.429688 5.734375 -7.703125 5.734375 -6.828125 C 5.734375 -5.929688 6.003906 -5.195312 6.546875 -4.625 Z M 6.546875 -4.625 "/>
</g>
<g id="glyph-0-17">
<path d="M 3.140625 -11.90625 C 4.578125 -13.25 6.40625 -13.921875 8.625 -13.921875 C 10.28125 -13.921875 11.800781 -13.65625 13.1875 -13.125 L 13.1875 -9.046875 C 11.882812 -9.609375 10.644531 -9.890625 9.46875 -9.890625 C 8.269531 -9.890625 7.347656 -9.601562 6.703125 -9.03125 C 6.054688 -8.457031 5.734375 -7.722656 5.734375 -6.828125 C 5.734375 -5.910156 6.054688 -5.171875 6.703125 -4.609375 C 7.347656 -4.054688 8.269531 -3.78125 9.46875 -3.78125 C 10.582031 -3.78125 11.820312 -4.0625 13.1875 -4.625 L 13.1875 -0.5 C 11.800781 0.0195312 10.28125 0.28125 8.625 0.28125 C 6.40625 0.28125 4.578125 -0.394531 3.140625 -1.75 C 1.703125 -3.101562 0.984375 -4.796875 0.984375 -6.828125 C 0.984375 -8.867188 1.703125 -10.5625 3.140625 -11.90625 Z M 3.140625 -11.90625 "/>
</g>
<g id="glyph-0-18">
<path d="M 1.546875 -13.25 C 1.546875 -15.050781 2.179688 -16.488281 3.453125 -17.5625 C 4.734375 -18.644531 6.398438 -19.1875 8.453125 -19.1875 C 10.660156 -19.1875 12.734375 -18.8125 14.671875 -18.0625 L 14.671875 -13.78125 C 12.578125 -14.613281 10.609375 -15.03125 8.765625 -15.03125 C 7.117188 -15.03125 6.296875 -14.582031 6.296875 -13.6875 C 6.296875 -13.238281 6.484375 -12.90625 6.859375 -12.6875 C 7.234375 -12.476562 7.882812 -12.234375 8.8125 -11.953125 L 10.1875 -11.5625 C 12 -11.0625 13.367188 -10.351562 14.296875 -9.4375 C 15.234375 -8.519531 15.703125 -7.332031 15.703125 -5.875 C 15.703125 -3.882812 15.007812 -2.335938 13.625 -1.234375 C 12.25 -0.128906 10.378906 0.421875 8.015625 0.421875 C 5.941406 0.421875 3.929688 0.046875 1.984375 -0.703125 L 1.984375 -5.046875 C 4.097656 -4.203125 6.097656 -3.78125 7.984375 -3.78125 C 8.953125 -3.78125 9.6875 -3.925781 10.1875 -4.21875 C 10.695312 -4.519531 10.953125 -4.929688 10.953125 -5.453125 C 10.953125 -5.941406 10.78125 -6.285156 10.4375 -6.484375 C 10.101562 -6.691406 9.441406 -6.929688 8.453125 -7.203125 L 6.9375 -7.609375 C 3.34375 -8.617188 1.546875 -10.5 1.546875 -13.25 Z M 1.546875 -13.25 "/>
</g>
<g id="glyph-0-19">
<path d="M 3.953125 -16.375 C 5.847656 -18.25 8.367188 -19.1875 11.515625 -19.1875 C 13.878906 -19.1875 15.976562 -18.820312 17.8125 -18.09375 L 17.8125 -13.5 C 15.945312 -14.238281 14.03125 -14.609375 12.0625 -14.609375 C 10.195312 -14.609375 8.738281 -14.125 7.6875 -13.15625 C 6.644531 -12.1875 6.125 -10.925781 6.125 -9.375 C 6.125 -7.832031 6.644531 -6.570312 7.6875 -5.59375 C 8.738281 -4.625 10.195312 -4.140625 12.0625 -4.140625 C 14.03125 -4.140625 15.945312 -4.515625 17.8125 -5.265625 L 17.8125 -0.671875 C 15.976562 0.0546875 13.878906 0.421875 11.515625 0.421875 C 8.367188 0.421875 5.84375 -0.515625 3.9375 -2.390625 C 2.039062 -4.265625 1.09375 -6.59375 1.09375 -9.375 C 1.09375 -12.15625 2.046875 -14.488281 3.953125 -16.375 Z M 3.953125 -16.375 "/>
</g>
</g>
<clipPath id="clip-0">
<path clip-rule="nonzero" d="M 2 44 L 80 44 L 80 81 L 2 81 Z M 2 44 "/>
</clipPath>
<clipPath id="clip-1">
<path clip-rule="nonzero" d="M 20.523438 44.191406 C 10.375 44.191406 2.144531 52.421875 2.144531 62.570312 C 2.144531 72.71875 10.375 80.949219 20.523438 80.949219 L 60.722656 80.949219 C 70.871094 80.949219 79.097656 72.71875 79.097656 62.570312 C 79.097656 52.421875 70.871094 44.191406 60.722656 44.191406 Z M 20.523438 44.191406 "/>
</clipPath>
<linearGradient id="linear-pattern-0" gradientUnits="userSpaceOnUse" x1="0.00000772817" y1="0" x2="1.000005" y2="0" gradientTransform="matrix(-76.952225, 0, 0, -76.952225, 79.098595, 62.570047)">
<stop offset="0" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.015625" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0234375" stop-color="rgb(100%, 100%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.03125" stop-color="rgb(100%, 100%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.0390625" stop-color="rgb(100%, 100%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.046875" stop-color="rgb(100%, 99.607849%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.0546875" stop-color="rgb(100%, 99.607849%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.0625" stop-color="rgb(100%, 99.607849%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.0703125" stop-color="rgb(100%, 99.607849%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.078125" stop-color="rgb(100%, 99.607849%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.0859375" stop-color="rgb(100%, 99.607849%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.09375" stop-color="rgb(100%, 99.607849%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.101562" stop-color="rgb(100%, 99.607849%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.109375" stop-color="rgb(100%, 99.215698%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.117187" stop-color="rgb(100%, 99.215698%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.125" stop-color="rgb(99.607849%, 99.215698%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.132812" stop-color="rgb(99.607849%, 99.215698%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.140625" stop-color="rgb(99.607849%, 99.215698%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.148438" stop-color="rgb(99.607849%, 99.215698%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.15625" stop-color="rgb(99.607849%, 99.215698%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.164062" stop-color="rgb(99.607849%, 99.215698%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.171875" stop-color="rgb(99.607849%, 98.823547%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.179688" stop-color="rgb(99.607849%, 98.823547%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.1875" stop-color="rgb(99.607849%, 98.823547%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.195312" stop-color="rgb(99.607849%, 98.823547%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.203125" stop-color="rgb(99.607849%, 98.823547%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.210937" stop-color="rgb(99.607849%, 98.823547%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.21875" stop-color="rgb(99.607849%, 98.823547%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.226562" stop-color="rgb(99.607849%, 98.823547%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.234375" stop-color="rgb(99.607849%, 98.431396%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.242188" stop-color="rgb(99.607849%, 98.431396%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.25" stop-color="rgb(99.607849%, 98.431396%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.257812" stop-color="rgb(99.607849%, 98.431396%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.265625" stop-color="rgb(99.607849%, 98.431396%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.273438" stop-color="rgb(99.607849%, 98.431396%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.28125" stop-color="rgb(99.607849%, 98.431396%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.289062" stop-color="rgb(99.607849%, 98.431396%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.296875" stop-color="rgb(99.607849%, 98.431396%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.304688" stop-color="rgb(99.607849%, 98.431396%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.3125" stop-color="rgb(99.607849%, 98.431396%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.320312" stop-color="rgb(99.607849%, 98.039246%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.328125" stop-color="rgb(99.607849%, 98.039246%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.335938" stop-color="rgb(99.215698%, 98.039246%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.34375" stop-color="rgb(99.215698%, 98.039246%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.351562" stop-color="rgb(99.215698%, 98.039246%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.359375" stop-color="rgb(99.215698%, 98.039246%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.367188" stop-color="rgb(99.215698%, 98.039246%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.375" stop-color="rgb(99.215698%, 98.039246%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.382812" stop-color="rgb(99.215698%, 97.647095%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.390625" stop-color="rgb(99.215698%, 97.647095%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.398437" stop-color="rgb(99.215698%, 97.647095%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.40625" stop-color="rgb(99.215698%, 97.647095%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.414062" stop-color="rgb(99.215698%, 97.647095%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.421875" stop-color="rgb(99.215698%, 97.647095%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.429688" stop-color="rgb(99.215698%, 97.647095%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.4375" stop-color="rgb(99.215698%, 97.647095%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.445312" stop-color="rgb(99.215698%, 97.254944%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.453125" stop-color="rgb(99.215698%, 97.254944%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.460938" stop-color="rgb(99.215698%, 97.254944%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.46875" stop-color="rgb(99.215698%, 97.254944%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.476562" stop-color="rgb(99.215698%, 97.254944%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.484375" stop-color="rgb(99.215698%, 97.254944%, 80.784607%)" stop-opacity="1"/>
<stop offset="0.492187" stop-color="rgb(98.823547%, 97.254944%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.5" stop-color="rgb(98.823547%, 97.254944%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.507812" stop-color="rgb(98.823547%, 96.862793%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.515625" stop-color="rgb(98.823547%, 96.862793%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.523438" stop-color="rgb(98.823547%, 96.862793%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.53125" stop-color="rgb(98.823547%, 96.862793%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.539062" stop-color="rgb(98.823547%, 96.862793%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.546875" stop-color="rgb(98.823547%, 96.862793%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.554688" stop-color="rgb(98.823547%, 96.862793%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.5625" stop-color="rgb(98.823547%, 96.862793%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.570312" stop-color="rgb(98.823547%, 96.862793%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.578125" stop-color="rgb(98.823547%, 96.862793%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.585938" stop-color="rgb(98.823547%, 96.470642%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.59375" stop-color="rgb(98.823547%, 96.470642%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.601562" stop-color="rgb(98.823547%, 96.470642%, 76.078796%)" stop-opacity="1"/>
<stop offset="0.609375" stop-color="rgb(98.823547%, 96.470642%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.617188" stop-color="rgb(98.431396%, 96.470642%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.625" stop-color="rgb(98.431396%, 96.470642%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.632812" stop-color="rgb(98.431396%, 96.470642%, 74.902344%)" stop-opacity="1"/>
<stop offset="0.640625" stop-color="rgb(98.431396%, 96.470642%, 74.510193%)" stop-opacity="1"/>
<stop offset="0.648438" stop-color="rgb(98.431396%, 96.078491%, 74.118042%)" stop-opacity="1"/>
<stop offset="0.65625" stop-color="rgb(98.431396%, 96.078491%, 73.725891%)" stop-opacity="1"/>
<stop offset="0.664062" stop-color="rgb(98.431396%, 96.078491%, 73.33374%)" stop-opacity="1"/>
<stop offset="0.671875" stop-color="rgb(98.431396%, 96.078491%, 73.33374%)" stop-opacity="1"/>
<stop offset="0.679688" stop-color="rgb(98.431396%, 96.078491%, 72.941589%)" stop-opacity="1"/>
<stop offset="0.6875" stop-color="rgb(98.431396%, 96.078491%, 72.549438%)" stop-opacity="1"/>
<stop offset="0.695312" stop-color="rgb(98.431396%, 96.078491%, 72.157288%)" stop-opacity="1"/>
<stop offset="0.703125" stop-color="rgb(98.431396%, 96.078491%, 71.765137%)" stop-opacity="1"/>
<stop offset="0.710938" stop-color="rgb(98.431396%, 96.078491%, 71.372986%)" stop-opacity="1"/>
<stop offset="0.71875" stop-color="rgb(98.431396%, 96.078491%, 71.372986%)" stop-opacity="1"/>
<stop offset="0.726562" stop-color="rgb(98.431396%, 95.68634%, 70.980835%)" stop-opacity="1"/>
<stop offset="0.734375" stop-color="rgb(98.431396%, 95.68634%, 70.588684%)" stop-opacity="1"/>
<stop offset="0.742188" stop-color="rgb(98.431396%, 95.68634%, 70.196533%)" stop-opacity="1"/>
<stop offset="0.75" stop-color="rgb(98.431396%, 95.68634%, 69.804382%)" stop-opacity="1"/>
<stop offset="0.757812" stop-color="rgb(98.431396%, 95.68634%, 69.412231%)" stop-opacity="1"/>
<stop offset="0.765625" stop-color="rgb(98.431396%, 95.68634%, 69.412231%)" stop-opacity="1"/>
<stop offset="0.773437" stop-color="rgb(98.431396%, 95.68634%, 69.020081%)" stop-opacity="1"/>
<stop offset="0.78125" stop-color="rgb(98.431396%, 95.68634%, 68.62793%)" stop-opacity="1"/>
<stop offset="0.789062" stop-color="rgb(98.431396%, 95.68634%, 68.62793%)" stop-opacity="1"/>
<stop offset="0.796875" stop-color="rgb(98.039246%, 95.68634%, 68.235779%)" stop-opacity="1"/>
<stop offset="0.804688" stop-color="rgb(98.039246%, 95.68634%, 67.843628%)" stop-opacity="1"/>
<stop offset="0.8125" stop-color="rgb(98.039246%, 95.294189%, 67.451477%)" stop-opacity="1"/>
<stop offset="0.820312" stop-color="rgb(98.039246%, 95.294189%, 67.059326%)" stop-opacity="1"/>
<stop offset="0.828125" stop-color="rgb(98.039246%, 95.294189%, 66.667175%)" stop-opacity="1"/>
<stop offset="0.835938" stop-color="rgb(98.039246%, 95.294189%, 66.667175%)" stop-opacity="1"/>
<stop offset="0.84375" stop-color="rgb(98.039246%, 95.294189%, 66.275024%)" stop-opacity="1"/>
<stop offset="0.851562" stop-color="rgb(98.039246%, 95.294189%, 65.882874%)" stop-opacity="1"/>
<stop offset="0.859375" stop-color="rgb(98.039246%, 95.294189%, 65.490723%)" stop-opacity="1"/>
<stop offset="0.867187" stop-color="rgb(98.039246%, 95.294189%, 65.490723%)" stop-opacity="1"/>
<stop offset="0.875" stop-color="rgb(98.039246%, 95.294189%, 65.098572%)" stop-opacity="1"/>
<stop offset="0.882812" stop-color="rgb(98.039246%, 95.294189%, 64.706421%)" stop-opacity="1"/>
<stop offset="0.890625" stop-color="rgb(98.039246%, 94.902039%, 64.31427%)" stop-opacity="1"/>
<stop offset="0.898438" stop-color="rgb(98.039246%, 94.902039%, 64.31427%)" stop-opacity="1"/>
<stop offset="0.90625" stop-color="rgb(98.039246%, 94.902039%, 63.922119%)" stop-opacity="1"/>
<stop offset="0.914062" stop-color="rgb(98.039246%, 94.902039%, 63.529968%)" stop-opacity="1"/>
<stop offset="0.921875" stop-color="rgb(98.039246%, 94.902039%, 63.137817%)" stop-opacity="1"/>
<stop offset="0.9375" stop-color="rgb(98.039246%, 94.902039%, 62.745667%)" stop-opacity="1"/>
<stop offset="0.945312" stop-color="rgb(98.039246%, 94.902039%, 62.745667%)" stop-opacity="1"/>
<stop offset="0.953125" stop-color="rgb(98.039246%, 94.902039%, 62.353516%)" stop-opacity="1"/>
<stop offset="0.960937" stop-color="rgb(98.039246%, 94.902039%, 61.961365%)" stop-opacity="1"/>
<stop offset="0.96875" stop-color="rgb(98.039246%, 94.902039%, 61.569214%)" stop-opacity="1"/>
<stop offset="0.984375" stop-color="rgb(98.039246%, 94.509888%, 61.177063%)" stop-opacity="1"/>
<stop offset="1" stop-color="rgb(98.039246%, 94.509888%, 60.784912%)" stop-opacity="1"/>
</linearGradient>
<clipPath id="clip-2">
<path clip-rule="nonzero" d="M 13 15 L 80 15 L 80 81 L 13 81 Z M 13 15 "/>
</clipPath>
<clipPath id="clip-3">
<path clip-rule="nonzero" d="M 19.300781 21.152344 C 12.125 28.328125 12.125 39.964844 19.300781 47.140625 L 47.726562 75.566406 C 51.316406 79.15625 56.019531 80.949219 60.722656 80.949219 C 65.425781 80.949219 70.128906 79.15625 73.714844 75.566406 C 80.894531 68.386719 80.894531 56.753906 73.714844 49.574219 L 45.292969 21.152344 C 41.703125 17.5625 37 15.769531 32.296875 15.769531 C 27.59375 15.769531 22.890625 17.5625 19.300781 21.152344 "/>
</clipPath>
<linearGradient id="linear-pattern-1" gradientUnits="userSpaceOnUse" x1="-0.115399" y1="0" x2="1.115408" y2="0" gradientTransform="matrix(-54.414318, -54.414318, 54.414318, -54.414318, 73.71669, 75.565292)">
<stop offset="0" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0625" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.09375" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0976562" stop-color="rgb(99.607849%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.101562" stop-color="rgb(99.607849%, 99.607849%, 100%)" stop-opacity="1"/>
<stop offset="0.105469" stop-color="rgb(99.215698%, 99.607849%, 100%)" stop-opacity="1"/>
<stop offset="0.109375" stop-color="rgb(99.215698%, 99.607849%, 100%)" stop-opacity="1"/>
<stop offset="0.113281" stop-color="rgb(98.823547%, 99.215698%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.117188" stop-color="rgb(98.431396%, 99.215698%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.121094" stop-color="rgb(98.431396%, 99.215698%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.125" stop-color="rgb(98.039246%, 99.215698%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.128906" stop-color="rgb(98.039246%, 98.823547%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.132812" stop-color="rgb(97.647095%, 98.823547%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.136719" stop-color="rgb(97.254944%, 98.823547%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.140625" stop-color="rgb(97.254944%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.144531" stop-color="rgb(96.862793%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.148438" stop-color="rgb(96.470642%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.152344" stop-color="rgb(96.078491%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.15625" stop-color="rgb(95.68634%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.160156" stop-color="rgb(95.68634%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.164062" stop-color="rgb(95.294189%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.167969" stop-color="rgb(94.902039%, 98.039246%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.171875" stop-color="rgb(94.902039%, 98.039246%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.175781" stop-color="rgb(94.509888%, 98.039246%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.179688" stop-color="rgb(94.509888%, 97.647095%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.183594" stop-color="rgb(94.117737%, 97.647095%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.1875" stop-color="rgb(93.725586%, 97.647095%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.191406" stop-color="rgb(93.725586%, 97.254944%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.195312" stop-color="rgb(93.333435%, 97.254944%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.199219" stop-color="rgb(93.333435%, 97.254944%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.203125" stop-color="rgb(92.941284%, 97.254944%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.207031" stop-color="rgb(92.549133%, 96.862793%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.210937" stop-color="rgb(92.549133%, 96.862793%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.214844" stop-color="rgb(92.156982%, 96.862793%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.21875" stop-color="rgb(91.764832%, 96.470642%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.222656" stop-color="rgb(91.372681%, 96.470642%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.226563" stop-color="rgb(90.98053%, 96.470642%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.230469" stop-color="rgb(90.98053%, 96.078491%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.234375" stop-color="rgb(90.588379%, 96.078491%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.238281" stop-color="rgb(90.588379%, 96.078491%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.242188" stop-color="rgb(90.196228%, 95.68634%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.246094" stop-color="rgb(89.804077%, 95.68634%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.25" stop-color="rgb(89.804077%, 95.68634%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.253906" stop-color="rgb(89.411926%, 95.68634%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.257812" stop-color="rgb(89.411926%, 95.294189%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.261719" stop-color="rgb(89.019775%, 95.294189%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.265625" stop-color="rgb(88.627625%, 95.294189%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.269531" stop-color="rgb(88.627625%, 94.902039%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.273438" stop-color="rgb(88.235474%, 94.902039%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.277344" stop-color="rgb(88.235474%, 94.902039%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.28125" stop-color="rgb(87.843323%, 94.509888%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.285156" stop-color="rgb(87.451172%, 94.509888%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.289062" stop-color="rgb(87.451172%, 94.509888%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.292969" stop-color="rgb(87.059021%, 94.509888%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.296875" stop-color="rgb(86.66687%, 94.117737%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.300781" stop-color="rgb(86.66687%, 94.117737%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.304688" stop-color="rgb(86.274719%, 94.117737%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.308594" stop-color="rgb(85.882568%, 93.725586%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.3125" stop-color="rgb(85.490417%, 93.725586%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.316406" stop-color="rgb(85.098267%, 93.725586%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.320312" stop-color="rgb(85.098267%, 93.333435%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.324219" stop-color="rgb(84.706116%, 93.333435%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.328125" stop-color="rgb(84.706116%, 93.333435%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.332031" stop-color="rgb(84.313965%, 93.333435%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.335938" stop-color="rgb(83.921814%, 92.941284%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.339844" stop-color="rgb(83.921814%, 92.941284%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.34375" stop-color="rgb(83.529663%, 92.941284%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.347656" stop-color="rgb(83.529663%, 92.549133%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.351562" stop-color="rgb(83.137512%, 92.549133%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.355469" stop-color="rgb(82.745361%, 92.549133%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.359375" stop-color="rgb(82.35321%, 92.156982%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.363281" stop-color="rgb(81.96106%, 92.156982%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.367188" stop-color="rgb(81.96106%, 92.156982%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.371094" stop-color="rgb(81.568909%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.375" stop-color="rgb(81.176758%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.378906" stop-color="rgb(81.176758%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.382812" stop-color="rgb(80.784607%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.386719" stop-color="rgb(80.784607%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.390625" stop-color="rgb(80.392456%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.394531" stop-color="rgb(80.000305%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.398438" stop-color="rgb(80.000305%, 91.372681%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.402344" stop-color="rgb(79.608154%, 91.372681%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.40625" stop-color="rgb(79.608154%, 91.372681%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.410156" stop-color="rgb(79.216003%, 90.98053%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.414062" stop-color="rgb(78.823853%, 90.98053%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.417969" stop-color="rgb(78.431702%, 90.98053%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.421875" stop-color="rgb(78.431702%, 90.98053%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.425781" stop-color="rgb(78.039551%, 90.588379%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.429688" stop-color="rgb(77.6474%, 90.588379%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.433594" stop-color="rgb(77.255249%, 90.588379%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.4375" stop-color="rgb(77.255249%, 90.196228%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.441406" stop-color="rgb(76.863098%, 90.196228%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.445312" stop-color="rgb(76.470947%, 90.196228%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.449219" stop-color="rgb(76.470947%, 89.804077%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.453125" stop-color="rgb(76.078796%, 89.804077%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.457031" stop-color="rgb(75.686646%, 89.804077%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.460938" stop-color="rgb(75.686646%, 89.804077%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.464844" stop-color="rgb(75.294495%, 89.411926%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.46875" stop-color="rgb(74.902344%, 89.411926%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.472656" stop-color="rgb(74.510193%, 89.411926%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.476563" stop-color="rgb(74.510193%, 89.019775%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.480469" stop-color="rgb(74.118042%, 89.019775%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.484375" stop-color="rgb(73.725891%, 89.019775%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.488281" stop-color="rgb(73.33374%, 88.627625%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.492187" stop-color="rgb(72.941589%, 88.627625%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.496094" stop-color="rgb(72.941589%, 88.627625%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.5" stop-color="rgb(72.549438%, 88.235474%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.503906" stop-color="rgb(72.157288%, 88.235474%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.507812" stop-color="rgb(72.157288%, 88.235474%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.511719" stop-color="rgb(71.765137%, 88.235474%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.515625" stop-color="rgb(71.765137%, 87.843323%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.519531" stop-color="rgb(71.372986%, 87.843323%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.523437" stop-color="rgb(70.980835%, 87.843323%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.527344" stop-color="rgb(70.588684%, 87.451172%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.53125" stop-color="rgb(70.196533%, 87.451172%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.535156" stop-color="rgb(70.196533%, 87.451172%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.539062" stop-color="rgb(69.804382%, 87.059021%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.542969" stop-color="rgb(69.412231%, 87.059021%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.546875" stop-color="rgb(69.412231%, 87.059021%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.550781" stop-color="rgb(69.020081%, 87.059021%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.554687" stop-color="rgb(68.62793%, 86.66687%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.558594" stop-color="rgb(68.235779%, 86.66687%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.5625" stop-color="rgb(67.843628%, 86.66687%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.566406" stop-color="rgb(67.843628%, 86.66687%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.570312" stop-color="rgb(67.451477%, 86.66687%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.574219" stop-color="rgb(67.059326%, 86.66687%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.578125" stop-color="rgb(66.667175%, 86.274719%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.582031" stop-color="rgb(66.275024%, 86.274719%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.585937" stop-color="rgb(66.275024%, 86.274719%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.589844" stop-color="rgb(65.882874%, 86.274719%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.59375" stop-color="rgb(65.490723%, 85.882568%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.597656" stop-color="rgb(65.490723%, 85.882568%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.601562" stop-color="rgb(65.098572%, 85.882568%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.605469" stop-color="rgb(64.706421%, 85.490417%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.609375" stop-color="rgb(64.31427%, 85.490417%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.613281" stop-color="rgb(63.922119%, 85.490417%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.617188" stop-color="rgb(63.922119%, 85.098267%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.621094" stop-color="rgb(63.529968%, 85.098267%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.625" stop-color="rgb(63.137817%, 85.098267%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.628906" stop-color="rgb(63.137817%, 85.098267%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.632812" stop-color="rgb(62.745667%, 84.706116%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.636719" stop-color="rgb(62.353516%, 84.706116%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.640625" stop-color="rgb(61.961365%, 84.706116%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.644531" stop-color="rgb(61.961365%, 84.313965%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.648438" stop-color="rgb(61.569214%, 84.313965%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.652344" stop-color="rgb(61.177063%, 84.313965%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.65625" stop-color="rgb(60.784912%, 83.921814%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.660156" stop-color="rgb(60.392761%, 83.921814%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.664063" stop-color="rgb(60.392761%, 83.921814%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.667969" stop-color="rgb(60.00061%, 83.529663%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.671875" stop-color="rgb(59.608459%, 83.529663%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.675781" stop-color="rgb(59.608459%, 83.529663%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.679688" stop-color="rgb(59.216309%, 83.529663%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.683594" stop-color="rgb(58.824158%, 83.137512%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.6875" stop-color="rgb(58.432007%, 83.137512%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.691406" stop-color="rgb(58.039856%, 83.137512%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.695313" stop-color="rgb(58.039856%, 83.137512%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.699219" stop-color="rgb(57.647705%, 83.137512%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.703125" stop-color="rgb(57.255554%, 83.137512%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.707031" stop-color="rgb(56.863403%, 82.745361%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.710938" stop-color="rgb(56.471252%, 82.745361%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.714844" stop-color="rgb(56.471252%, 82.745361%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.71875" stop-color="rgb(56.079102%, 82.745361%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.722656" stop-color="rgb(55.686951%, 82.35321%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.726563" stop-color="rgb(55.686951%, 82.35321%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.730469" stop-color="rgb(55.2948%, 82.35321%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.734375" stop-color="rgb(54.902649%, 81.96106%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.738281" stop-color="rgb(54.510498%, 81.96106%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.742188" stop-color="rgb(54.118347%, 81.96106%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.746094" stop-color="rgb(54.118347%, 81.568909%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.75" stop-color="rgb(53.726196%, 81.568909%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.753906" stop-color="rgb(53.334045%, 81.568909%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.757812" stop-color="rgb(53.334045%, 81.568909%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.761719" stop-color="rgb(52.941895%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.765625" stop-color="rgb(52.549744%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.769531" stop-color="rgb(52.157593%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.773437" stop-color="rgb(52.157593%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.777344" stop-color="rgb(51.765442%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.78125" stop-color="rgb(51.373291%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.785156" stop-color="rgb(50.98114%, 80.784607%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.789062" stop-color="rgb(50.588989%, 80.784607%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.792969" stop-color="rgb(50.588989%, 80.784607%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.796875" stop-color="rgb(50.196838%, 80.392456%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.800781" stop-color="rgb(49.803162%, 80.392456%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.804687" stop-color="rgb(49.803162%, 80.392456%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.808594" stop-color="rgb(49.411011%, 80.392456%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.8125" stop-color="rgb(49.01886%, 80.000305%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.816406" stop-color="rgb(48.626709%, 80.000305%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.820312" stop-color="rgb(48.234558%, 80.000305%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.824219" stop-color="rgb(47.842407%, 80.000305%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.828125" stop-color="rgb(47.450256%, 80.000305%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.832031" stop-color="rgb(47.450256%, 80.000305%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.835937" stop-color="rgb(47.058105%, 79.608154%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.839844" stop-color="rgb(46.665955%, 79.608154%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.84375" stop-color="rgb(46.665955%, 79.608154%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.847656" stop-color="rgb(46.273804%, 79.608154%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.851562" stop-color="rgb(45.881653%, 79.216003%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.855469" stop-color="rgb(45.489502%, 79.216003%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.859375" stop-color="rgb(45.097351%, 79.216003%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.863281" stop-color="rgb(45.097351%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.867188" stop-color="rgb(44.7052%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.871094" stop-color="rgb(44.313049%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.875" stop-color="rgb(43.920898%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.878906" stop-color="rgb(43.528748%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.882812" stop-color="rgb(43.528748%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.886719" stop-color="rgb(43.136597%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.890625" stop-color="rgb(42.744446%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.894531" stop-color="rgb(42.744446%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.898438" stop-color="rgb(42.352295%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.902344" stop-color="rgb(42.352295%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.90625" stop-color="rgb(41.960144%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.9375" stop-color="rgb(41.960144%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="1" stop-color="rgb(41.960144%, 78.431702%, 90.98053%)" stop-opacity="1"/>
</linearGradient>
<clipPath id="clip-4">
<path clip-rule="nonzero" d="M 42 3 L 80 3 L 80 81 L 42 81 Z M 42 3 "/>
</clipPath>
<clipPath id="clip-5">
<path clip-rule="nonzero" d="M 42.34375 22.371094 L 42.34375 62.570312 C 42.34375 72.71875 50.570312 80.949219 60.722656 80.949219 C 70.871094 80.949219 79.097656 72.71875 79.097656 62.570312 L 79.097656 22.371094 C 79.097656 12.222656 70.871094 3.996094 60.722656 3.996094 C 50.570312 3.996094 42.34375 12.222656 42.34375 22.371094 "/>
</clipPath>
<linearGradient id="linear-pattern-2" gradientUnits="userSpaceOnUse" x1="0.00000321492" y1="0" x2="0.999994" y2="0" gradientTransform="matrix(0, -76.95372, 76.95372, 0, 60.721073, 80.947947)">
<stop offset="0" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0078125" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.015625" stop-color="rgb(99.607849%, 99.607849%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.0234375" stop-color="rgb(99.607849%, 99.215698%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.03125" stop-color="rgb(99.215698%, 98.823547%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.0390625" stop-color="rgb(98.823547%, 98.431396%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.046875" stop-color="rgb(98.431396%, 98.039246%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.0546875" stop-color="rgb(98.431396%, 97.647095%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.0625" stop-color="rgb(98.039246%, 97.254944%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.0703125" stop-color="rgb(97.647095%, 96.862793%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.078125" stop-color="rgb(97.254944%, 96.470642%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.0859375" stop-color="rgb(97.254944%, 96.078491%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.09375" stop-color="rgb(96.862793%, 95.68634%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.101562" stop-color="rgb(96.470642%, 95.294189%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.109375" stop-color="rgb(96.078491%, 94.902039%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.117188" stop-color="rgb(96.078491%, 94.509888%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.125" stop-color="rgb(95.68634%, 94.117737%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.132812" stop-color="rgb(95.294189%, 93.725586%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.140625" stop-color="rgb(94.902039%, 93.333435%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.148438" stop-color="rgb(94.902039%, 92.941284%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.15625" stop-color="rgb(94.509888%, 92.549133%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.164062" stop-color="rgb(94.117737%, 92.156982%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.171875" stop-color="rgb(93.725586%, 91.764832%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.179688" stop-color="rgb(93.725586%, 91.372681%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.1875" stop-color="rgb(93.333435%, 90.98053%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.195312" stop-color="rgb(92.941284%, 90.588379%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.203125" stop-color="rgb(92.549133%, 90.196228%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.210937" stop-color="rgb(92.549133%, 89.804077%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.21875" stop-color="rgb(92.156982%, 89.411926%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.226562" stop-color="rgb(91.764832%, 89.019775%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.234375" stop-color="rgb(91.372681%, 88.627625%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.242187" stop-color="rgb(91.372681%, 88.235474%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.25" stop-color="rgb(90.98053%, 87.843323%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.257812" stop-color="rgb(90.98053%, 87.451172%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.265625" stop-color="rgb(90.588379%, 87.451172%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.273438" stop-color="rgb(90.196228%, 87.059021%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.28125" stop-color="rgb(90.196228%, 86.66687%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.289062" stop-color="rgb(89.804077%, 86.274719%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.296875" stop-color="rgb(89.411926%, 85.882568%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.304687" stop-color="rgb(89.019775%, 85.490417%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.3125" stop-color="rgb(89.019775%, 85.098267%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.320312" stop-color="rgb(88.627625%, 84.706116%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.328125" stop-color="rgb(88.627625%, 84.313965%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.335937" stop-color="rgb(88.235474%, 83.921814%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.34375" stop-color="rgb(87.843323%, 83.529663%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.351562" stop-color="rgb(87.451172%, 83.137512%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.359375" stop-color="rgb(87.451172%, 82.745361%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.367188" stop-color="rgb(87.059021%, 82.35321%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.375" stop-color="rgb(87.059021%, 81.96106%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.382812" stop-color="rgb(86.66687%, 81.568909%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.390625" stop-color="rgb(86.274719%, 81.176758%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.398437" stop-color="rgb(85.882568%, 80.784607%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.40625" stop-color="rgb(85.882568%, 80.784607%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.414062" stop-color="rgb(85.490417%, 80.392456%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.421875" stop-color="rgb(85.490417%, 80.000305%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.429688" stop-color="rgb(85.098267%, 79.608154%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.4375" stop-color="rgb(84.706116%, 79.216003%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.445312" stop-color="rgb(84.313965%, 78.823853%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.453125" stop-color="rgb(84.313965%, 78.431702%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.460938" stop-color="rgb(83.921814%, 78.039551%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.46875" stop-color="rgb(83.921814%, 77.6474%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.476562" stop-color="rgb(83.529663%, 77.255249%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.484375" stop-color="rgb(83.529663%, 76.863098%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.492188" stop-color="rgb(83.137512%, 76.470947%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.5" stop-color="rgb(82.745361%, 76.470947%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.507812" stop-color="rgb(82.745361%, 76.078796%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.515625" stop-color="rgb(82.35321%, 76.078796%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.523438" stop-color="rgb(81.96106%, 75.686646%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.53125" stop-color="rgb(81.96106%, 75.294495%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.539062" stop-color="rgb(81.568909%, 74.902344%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.546875" stop-color="rgb(81.568909%, 74.510193%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.554687" stop-color="rgb(81.176758%, 74.118042%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.5625" stop-color="rgb(81.176758%, 73.725891%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.570313" stop-color="rgb(80.784607%, 73.33374%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.578125" stop-color="rgb(80.784607%, 73.33374%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.585938" stop-color="rgb(80.392456%, 72.941589%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.59375" stop-color="rgb(80.000305%, 72.549438%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.601562" stop-color="rgb(79.608154%, 72.157288%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.609375" stop-color="rgb(79.608154%, 71.765137%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.617188" stop-color="rgb(79.216003%, 71.372986%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.625" stop-color="rgb(79.216003%, 70.980835%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.632812" stop-color="rgb(78.823853%, 70.588684%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.640625" stop-color="rgb(78.823853%, 70.588684%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.648437" stop-color="rgb(78.431702%, 70.196533%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.65625" stop-color="rgb(78.431702%, 69.804382%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.664063" stop-color="rgb(78.039551%, 69.412231%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.671875" stop-color="rgb(78.039551%, 69.020081%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.679688" stop-color="rgb(77.6474%, 68.62793%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.6875" stop-color="rgb(77.255249%, 68.62793%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.695312" stop-color="rgb(76.863098%, 68.235779%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.703125" stop-color="rgb(76.863098%, 67.843628%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.710938" stop-color="rgb(76.470947%, 67.451477%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.71875" stop-color="rgb(76.470947%, 67.059326%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.726562" stop-color="rgb(76.078796%, 66.667175%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.734375" stop-color="rgb(76.078796%, 66.667175%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.742188" stop-color="rgb(75.686646%, 66.275024%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.75" stop-color="rgb(75.686646%, 65.882874%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.757813" stop-color="rgb(75.686646%, 65.490723%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.765625" stop-color="rgb(75.294495%, 65.098572%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.773438" stop-color="rgb(75.294495%, 65.098572%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.78125" stop-color="rgb(74.902344%, 64.706421%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.789062" stop-color="rgb(74.902344%, 64.31427%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.796875" stop-color="rgb(74.510193%, 63.922119%, 80.784607%)" stop-opacity="1"/>
<stop offset="0.804688" stop-color="rgb(74.510193%, 63.922119%, 80.784607%)" stop-opacity="1"/>
<stop offset="0.8125" stop-color="rgb(74.118042%, 63.529968%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.820312" stop-color="rgb(74.118042%, 63.137817%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.828125" stop-color="rgb(73.725891%, 62.745667%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.835938" stop-color="rgb(73.33374%, 62.353516%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.84375" stop-color="rgb(72.941589%, 61.961365%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.851563" stop-color="rgb(72.941589%, 61.961365%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.859375" stop-color="rgb(72.549438%, 61.569214%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.867188" stop-color="rgb(72.549438%, 61.177063%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.875" stop-color="rgb(72.157288%, 60.784912%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.890625" stop-color="rgb(71.765137%, 60.392761%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.898437" stop-color="rgb(71.765137%, 60.392761%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.90625" stop-color="rgb(71.765137%, 60.00061%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.914063" stop-color="rgb(71.765137%, 59.608459%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.921875" stop-color="rgb(71.372986%, 59.216309%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.9375" stop-color="rgb(70.980835%, 58.824158%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.945312" stop-color="rgb(70.980835%, 58.824158%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.953125" stop-color="rgb(70.588684%, 58.432007%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.960938" stop-color="rgb(70.588684%, 58.039856%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.96875" stop-color="rgb(70.196533%, 57.647705%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.984375" stop-color="rgb(69.804382%, 57.255554%, 76.863098%)" stop-opacity="1"/>
<stop offset="1" stop-color="rgb(69.804382%, 56.863403%, 76.470947%)" stop-opacity="1"/>
</linearGradient>
<clipPath id="clip-6">
<path clip-rule="nonzero" d="M 42 15 L 108 15 L 108 81 L 42 81 Z M 42 15 "/>
</clipPath>
<clipPath id="clip-7">
<path clip-rule="nonzero" d="M 76.152344 21.152344 L 47.726562 49.574219 C 40.550781 56.75 40.550781 68.386719 47.726562 75.566406 C 51.316406 79.15625 56.019531 80.949219 60.722656 80.949219 C 65.425781 80.949219 70.128906 79.152344 73.714844 75.566406 L 102.140625 47.140625 C 109.316406 39.964844 109.316406 28.328125 102.140625 21.152344 C 98.550781 17.5625 93.847656 15.769531 89.144531 15.769531 C 84.441406 15.769531 79.738281 17.5625 76.152344 21.152344 "/>
</clipPath>
<linearGradient id="linear-pattern-3" gradientUnits="userSpaceOnUse" x1="-0.115406" y1="0" x2="1.115401" y2="0" gradientTransform="matrix(54.414692, -54.414692, 54.414692, 54.414692, 47.726387, 75.56548)">
<stop offset="0" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0625" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.09375" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.101562" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.109375" stop-color="rgb(100%, 99.607849%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.113281" stop-color="rgb(100%, 99.215698%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.117188" stop-color="rgb(100%, 98.823547%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.125" stop-color="rgb(100%, 98.823547%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.132812" stop-color="rgb(100%, 98.431396%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.140625" stop-color="rgb(100%, 98.431396%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.148438" stop-color="rgb(99.607849%, 98.039246%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.152344" stop-color="rgb(99.607849%, 97.647095%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.15625" stop-color="rgb(99.607849%, 97.254944%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.164062" stop-color="rgb(99.607849%, 97.254944%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.171875" stop-color="rgb(99.607849%, 96.862793%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.175781" stop-color="rgb(99.607849%, 96.862793%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.179687" stop-color="rgb(99.607849%, 96.470642%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.1875" stop-color="rgb(99.607849%, 96.470642%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.191406" stop-color="rgb(99.607849%, 96.078491%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.195312" stop-color="rgb(99.607849%, 95.68634%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.203125" stop-color="rgb(99.607849%, 95.68634%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.210938" stop-color="rgb(99.607849%, 95.294189%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.214844" stop-color="rgb(99.607849%, 94.902039%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.21875" stop-color="rgb(99.607849%, 94.902039%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.226562" stop-color="rgb(99.607849%, 94.509888%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.234375" stop-color="rgb(99.215698%, 94.117737%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.242187" stop-color="rgb(99.215698%, 94.117737%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.25" stop-color="rgb(99.215698%, 93.725586%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.253906" stop-color="rgb(99.215698%, 93.333435%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.257812" stop-color="rgb(99.215698%, 93.333435%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.265625" stop-color="rgb(99.215698%, 92.941284%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.273437" stop-color="rgb(99.215698%, 92.549133%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.28125" stop-color="rgb(99.215698%, 92.549133%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.289062" stop-color="rgb(99.215698%, 92.156982%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.292969" stop-color="rgb(99.215698%, 91.764832%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.296875" stop-color="rgb(99.215698%, 91.372681%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.304687" stop-color="rgb(99.215698%, 91.372681%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.3125" stop-color="rgb(98.823547%, 90.98053%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.316406" stop-color="rgb(98.823547%, 90.588379%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.320312" stop-color="rgb(98.823547%, 90.588379%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.324219" stop-color="rgb(98.823547%, 90.196228%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.328125" stop-color="rgb(98.823547%, 90.196228%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.335937" stop-color="rgb(98.823547%, 90.196228%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.34375" stop-color="rgb(98.823547%, 89.804077%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.351562" stop-color="rgb(98.823547%, 89.411926%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.355469" stop-color="rgb(98.823547%, 89.019775%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.359375" stop-color="rgb(98.823547%, 89.019775%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.363281" stop-color="rgb(98.823547%, 88.627625%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.367187" stop-color="rgb(98.823547%, 88.627625%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.375" stop-color="rgb(98.823547%, 88.235474%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.378906" stop-color="rgb(98.823547%, 88.235474%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.382812" stop-color="rgb(98.823547%, 88.235474%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.386719" stop-color="rgb(98.431396%, 87.843323%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.390625" stop-color="rgb(98.431396%, 87.843323%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.394531" stop-color="rgb(98.431396%, 87.451172%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.398438" stop-color="rgb(98.431396%, 87.451172%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.40625" stop-color="rgb(98.431396%, 87.059021%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.414062" stop-color="rgb(98.431396%, 86.66687%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.421875" stop-color="rgb(98.431396%, 86.66687%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.429687" stop-color="rgb(98.431396%, 86.274719%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.433594" stop-color="rgb(98.431396%, 85.882568%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.4375" stop-color="rgb(98.431396%, 85.882568%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.445312" stop-color="rgb(98.431396%, 85.490417%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.453125" stop-color="rgb(98.039246%, 85.098267%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.457031" stop-color="rgb(98.039246%, 85.098267%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.460937" stop-color="rgb(98.039246%, 84.706116%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.464844" stop-color="rgb(98.039246%, 84.313965%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.46875" stop-color="rgb(98.039246%, 84.313965%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.476562" stop-color="rgb(98.039246%, 84.313965%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.484375" stop-color="rgb(98.039246%, 83.921814%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.488281" stop-color="rgb(98.039246%, 83.529663%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.492188" stop-color="rgb(98.039246%, 83.529663%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.496094" stop-color="rgb(98.039246%, 83.529663%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.5" stop-color="rgb(98.039246%, 83.137512%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.503906" stop-color="rgb(98.039246%, 82.745361%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.507812" stop-color="rgb(98.039246%, 82.745361%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.515625" stop-color="rgb(98.039246%, 82.745361%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.523438" stop-color="rgb(98.039246%, 82.35321%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.53125" stop-color="rgb(97.647095%, 81.96106%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.535156" stop-color="rgb(97.647095%, 81.96106%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.539063" stop-color="rgb(97.647095%, 81.568909%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.542969" stop-color="rgb(97.647095%, 81.176758%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.546875" stop-color="rgb(97.647095%, 81.176758%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.554688" stop-color="rgb(97.647095%, 81.176758%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.5625" stop-color="rgb(97.647095%, 80.784607%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.570312" stop-color="rgb(97.647095%, 80.392456%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.574219" stop-color="rgb(97.647095%, 80.000305%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.578125" stop-color="rgb(97.647095%, 80.000305%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.582031" stop-color="rgb(97.647095%, 79.608154%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.585938" stop-color="rgb(97.647095%, 79.608154%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.59375" stop-color="rgb(97.647095%, 79.608154%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.601562" stop-color="rgb(97.254944%, 79.216003%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.605469" stop-color="rgb(97.254944%, 78.823853%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.609375" stop-color="rgb(97.254944%, 78.431702%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.617187" stop-color="rgb(97.254944%, 78.431702%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.625" stop-color="rgb(97.254944%, 78.039551%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.632813" stop-color="rgb(97.254944%, 78.039551%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.636719" stop-color="rgb(97.254944%, 77.6474%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.640625" stop-color="rgb(97.254944%, 77.255249%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.644531" stop-color="rgb(97.254944%, 77.255249%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.648438" stop-color="rgb(97.254944%, 76.863098%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.65625" stop-color="rgb(97.254944%, 76.863098%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.664062" stop-color="rgb(96.862793%, 76.470947%, 80.784607%)" stop-opacity="1"/>
<stop offset="0.671875" stop-color="rgb(96.862793%, 76.078796%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.675781" stop-color="rgb(96.862793%, 76.078796%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.679688" stop-color="rgb(96.862793%, 75.686646%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.683594" stop-color="rgb(96.862793%, 75.686646%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.6875" stop-color="rgb(96.862793%, 75.294495%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.695312" stop-color="rgb(96.862793%, 75.294495%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.703125" stop-color="rgb(96.862793%, 74.902344%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.710937" stop-color="rgb(96.862793%, 74.510193%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.71875" stop-color="rgb(96.862793%, 74.510193%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.726562" stop-color="rgb(96.862793%, 74.118042%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.730469" stop-color="rgb(96.862793%, 73.725891%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.734375" stop-color="rgb(96.470642%, 73.725891%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.742188" stop-color="rgb(96.470642%, 73.33374%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.75" stop-color="rgb(96.470642%, 72.941589%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.757812" stop-color="rgb(96.470642%, 72.941589%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.765625" stop-color="rgb(96.470642%, 72.549438%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.769531" stop-color="rgb(96.470642%, 72.157288%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.773438" stop-color="rgb(96.470642%, 72.157288%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.78125" stop-color="rgb(96.470642%, 71.765137%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.789063" stop-color="rgb(96.470642%, 71.372986%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.796875" stop-color="rgb(96.470642%, 71.372986%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.804688" stop-color="rgb(96.470642%, 70.980835%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.8125" stop-color="rgb(96.470642%, 70.980835%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.820312" stop-color="rgb(96.078491%, 70.588684%, 76.078796%)" stop-opacity="1"/>
<stop offset="0.828125" stop-color="rgb(96.078491%, 70.196533%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.832031" stop-color="rgb(96.078491%, 69.804382%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.835938" stop-color="rgb(96.078491%, 69.804382%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.839844" stop-color="rgb(96.078491%, 69.412231%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.84375" stop-color="rgb(96.078491%, 69.412231%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.851562" stop-color="rgb(96.078491%, 69.412231%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.859375" stop-color="rgb(96.078491%, 69.020081%, 74.902344%)" stop-opacity="1"/>
<stop offset="0.867187" stop-color="rgb(96.078491%, 68.62793%, 74.510193%)" stop-opacity="1"/>
<stop offset="0.875" stop-color="rgb(96.078491%, 68.62793%, 74.510193%)" stop-opacity="1"/>
<stop offset="0.882813" stop-color="rgb(96.078491%, 68.235779%, 74.118042%)" stop-opacity="1"/>
<stop offset="0.890625" stop-color="rgb(96.078491%, 68.235779%, 74.118042%)" stop-opacity="1"/>
<stop offset="0.898438" stop-color="rgb(96.078491%, 67.843628%, 74.118042%)" stop-opacity="1"/>
<stop offset="0.90625" stop-color="rgb(95.68634%, 67.451477%, 73.725891%)" stop-opacity="1"/>
<stop offset="0.9375" stop-color="rgb(95.68634%, 67.451477%, 73.725891%)" stop-opacity="1"/>
<stop offset="1" stop-color="rgb(95.68634%, 67.451477%, 73.725891%)" stop-opacity="1"/>
</linearGradient>
<clipPath id="clip-8">
<path clip-rule="nonzero" d="M 42 44 L 120 44 L 120 81 L 42 81 Z M 42 44 "/>
</clipPath>
<clipPath id="clip-9">
<path clip-rule="nonzero" d="M 60.722656 44.191406 C 50.570312 44.191406 42.34375 52.421875 42.34375 62.570312 C 42.34375 72.71875 50.570312 80.949219 60.722656 80.949219 L 100.917969 80.949219 C 111.066406 80.949219 119.296875 72.71875 119.296875 62.570312 C 119.296875 52.421875 111.066406 44.191406 100.917969 44.191406 Z M 60.722656 44.191406 "/>
</clipPath>
<linearGradient id="linear-pattern-4" gradientUnits="userSpaceOnUse" x1="-0.00000221172" y1="0" x2="1.000001" y2="0" gradientTransform="matrix(76.95372, 0, 0, 76.95372, 42.34317, 62.570047)">
<stop offset="0" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0078125" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.015625" stop-color="rgb(99.607849%, 99.607849%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.0234375" stop-color="rgb(99.215698%, 99.607849%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.03125" stop-color="rgb(98.823547%, 99.215698%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.0390625" stop-color="rgb(98.431396%, 99.215698%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.046875" stop-color="rgb(98.039246%, 98.823547%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.0546875" stop-color="rgb(97.647095%, 98.823547%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.0625" stop-color="rgb(97.254944%, 98.431396%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.0703125" stop-color="rgb(96.862793%, 98.431396%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.078125" stop-color="rgb(96.470642%, 98.039246%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.0859375" stop-color="rgb(96.078491%, 98.039246%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.09375" stop-color="rgb(95.68634%, 98.039246%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.101562" stop-color="rgb(95.68634%, 98.039246%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.109375" stop-color="rgb(95.294189%, 97.647095%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.117187" stop-color="rgb(94.902039%, 97.647095%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.125" stop-color="rgb(94.509888%, 97.254944%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.132812" stop-color="rgb(94.117737%, 97.254944%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.140625" stop-color="rgb(93.725586%, 96.862793%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.148438" stop-color="rgb(93.333435%, 96.862793%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.15625" stop-color="rgb(92.941284%, 96.470642%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.164062" stop-color="rgb(92.549133%, 96.470642%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.171875" stop-color="rgb(92.156982%, 96.078491%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.179688" stop-color="rgb(91.764832%, 96.078491%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.1875" stop-color="rgb(91.372681%, 95.68634%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.195312" stop-color="rgb(90.98053%, 95.68634%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.203125" stop-color="rgb(90.588379%, 95.294189%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.210938" stop-color="rgb(90.196228%, 95.294189%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.21875" stop-color="rgb(89.804077%, 94.902039%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.226562" stop-color="rgb(89.411926%, 94.902039%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.234375" stop-color="rgb(89.019775%, 94.509888%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.242188" stop-color="rgb(88.627625%, 94.509888%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.25" stop-color="rgb(88.235474%, 94.117737%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.257812" stop-color="rgb(87.843323%, 94.117737%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.265625" stop-color="rgb(87.451172%, 94.117737%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.273438" stop-color="rgb(87.059021%, 93.725586%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.28125" stop-color="rgb(86.66687%, 93.725586%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.289062" stop-color="rgb(86.274719%, 93.333435%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.296875" stop-color="rgb(85.882568%, 93.333435%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.304687" stop-color="rgb(85.490417%, 92.941284%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.3125" stop-color="rgb(85.098267%, 92.941284%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.320312" stop-color="rgb(84.706116%, 92.549133%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.328125" stop-color="rgb(84.313965%, 92.549133%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.335937" stop-color="rgb(83.921814%, 92.156982%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.34375" stop-color="rgb(83.529663%, 92.156982%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.351562" stop-color="rgb(83.137512%, 92.156982%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.359375" stop-color="rgb(82.745361%, 92.156982%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.367187" stop-color="rgb(82.35321%, 91.764832%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.375" stop-color="rgb(81.96106%, 91.764832%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.382812" stop-color="rgb(81.568909%, 91.372681%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.390625" stop-color="rgb(81.176758%, 91.372681%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.398437" stop-color="rgb(80.784607%, 90.98053%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.40625" stop-color="rgb(80.392456%, 90.98053%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.414062" stop-color="rgb(80.000305%, 90.588379%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.421875" stop-color="rgb(79.608154%, 90.588379%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.429687" stop-color="rgb(79.216003%, 90.196228%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.4375" stop-color="rgb(78.823853%, 90.196228%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.445312" stop-color="rgb(78.431702%, 89.804077%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.453125" stop-color="rgb(78.039551%, 89.804077%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.460937" stop-color="rgb(77.6474%, 89.411926%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.46875" stop-color="rgb(77.255249%, 89.411926%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.476562" stop-color="rgb(76.863098%, 89.019775%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.484375" stop-color="rgb(76.470947%, 89.019775%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.492187" stop-color="rgb(76.078796%, 88.627625%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.5" stop-color="rgb(75.686646%, 88.627625%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.507812" stop-color="rgb(75.686646%, 88.627625%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.515625" stop-color="rgb(75.294495%, 88.627625%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.523437" stop-color="rgb(74.902344%, 88.235474%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.527344" stop-color="rgb(74.118042%, 88.235474%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.53125" stop-color="rgb(74.118042%, 88.235474%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.535156" stop-color="rgb(73.725891%, 87.843323%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.539062" stop-color="rgb(73.33374%, 87.843323%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.542969" stop-color="rgb(73.33374%, 87.843323%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.546875" stop-color="rgb(72.941589%, 87.843323%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.554687" stop-color="rgb(72.941589%, 87.451172%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.5625" stop-color="rgb(72.549438%, 87.451172%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.570312" stop-color="rgb(72.157288%, 87.059021%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.578125" stop-color="rgb(71.765137%, 87.059021%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.585937" stop-color="rgb(71.372986%, 86.66687%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.59375" stop-color="rgb(70.980835%, 86.66687%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.601562" stop-color="rgb(70.588684%, 86.274719%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.609375" stop-color="rgb(70.196533%, 86.274719%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.617187" stop-color="rgb(69.804382%, 85.882568%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.625" stop-color="rgb(69.412231%, 85.882568%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.632812" stop-color="rgb(69.020081%, 85.490417%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.636719" stop-color="rgb(68.62793%, 85.490417%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.640625" stop-color="rgb(68.235779%, 85.490417%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.644531" stop-color="rgb(67.843628%, 85.098267%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.648437" stop-color="rgb(67.451477%, 85.098267%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.652344" stop-color="rgb(67.451477%, 85.098267%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.65625" stop-color="rgb(67.059326%, 85.098267%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.664062" stop-color="rgb(67.059326%, 84.706116%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.671875" stop-color="rgb(66.667175%, 84.706116%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.679687" stop-color="rgb(66.275024%, 84.313965%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.6875" stop-color="rgb(65.882874%, 84.313965%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.695312" stop-color="rgb(65.490723%, 84.313965%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.703125" stop-color="rgb(65.098572%, 84.313965%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.710937" stop-color="rgb(64.706421%, 83.921814%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.71875" stop-color="rgb(64.31427%, 83.921814%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.726562" stop-color="rgb(63.922119%, 83.529663%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.734375" stop-color="rgb(63.529968%, 83.529663%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.742187" stop-color="rgb(63.137817%, 83.137512%, 80.784607%)" stop-opacity="1"/>
<stop offset="0.746094" stop-color="rgb(62.745667%, 83.137512%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.75" stop-color="rgb(62.353516%, 83.137512%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.753906" stop-color="rgb(62.353516%, 83.137512%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.757812" stop-color="rgb(61.961365%, 82.745361%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.761719" stop-color="rgb(61.569214%, 82.745361%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.765625" stop-color="rgb(61.569214%, 82.745361%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.773437" stop-color="rgb(61.177063%, 82.745361%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.78125" stop-color="rgb(60.784912%, 82.35321%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.789062" stop-color="rgb(60.392761%, 82.35321%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.796875" stop-color="rgb(60.00061%, 82.35321%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.804687" stop-color="rgb(59.608459%, 82.35321%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.8125" stop-color="rgb(59.216309%, 81.96106%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.820312" stop-color="rgb(58.824158%, 81.96106%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.828125" stop-color="rgb(58.432007%, 81.568909%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.835937" stop-color="rgb(58.039856%, 81.568909%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.84375" stop-color="rgb(57.647705%, 81.176758%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.851562" stop-color="rgb(57.255554%, 81.176758%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.859375" stop-color="rgb(56.863403%, 80.784607%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.867187" stop-color="rgb(56.471252%, 80.784607%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.875" stop-color="rgb(56.079102%, 80.784607%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.882812" stop-color="rgb(55.686951%, 80.784607%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.890625" stop-color="rgb(55.2948%, 80.392456%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.898437" stop-color="rgb(54.902649%, 80.392456%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.90625" stop-color="rgb(54.510498%, 80.000305%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.914062" stop-color="rgb(54.118347%, 80.000305%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.921875" stop-color="rgb(53.726196%, 79.608154%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.929687" stop-color="rgb(53.334045%, 79.608154%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.9375" stop-color="rgb(52.941895%, 79.608154%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.945312" stop-color="rgb(52.549744%, 79.608154%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.953125" stop-color="rgb(52.157593%, 79.216003%, 76.078796%)" stop-opacity="1"/>
<stop offset="0.960937" stop-color="rgb(51.765442%, 79.216003%, 76.078796%)" stop-opacity="1"/>
<stop offset="0.96875" stop-color="rgb(51.373291%, 78.823853%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.976562" stop-color="rgb(51.373291%, 78.823853%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.984375" stop-color="rgb(50.98114%, 78.823853%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.992187" stop-color="rgb(50.588989%, 78.823853%, 75.686646%)" stop-opacity="1"/>
<stop offset="1" stop-color="rgb(50.196838%, 78.431702%, 75.294495%)" stop-opacity="1"/>
</linearGradient>
</defs>
<g clip-path="url(#clip-0)">
<g clip-path="url(#clip-1)">
<path fill-rule="nonzero" fill="url(#linear-pattern-0)" d="M 79.097656 80.949219 L 79.097656 44.191406 L 2.144531 44.191406 L 2.144531 80.949219 Z M 79.097656 80.949219 "/>
</g>
</g>
<g clip-path="url(#clip-2)">
<g clip-path="url(#clip-3)">
<path fill-rule="nonzero" fill="url(#linear-pattern-1)" d="M 46.507812 115.332031 L 113.484375 48.359375 L 46.507812 -18.617188 L -20.464844 48.359375 Z M 46.507812 115.332031 "/>
</g>
</g>
<g clip-path="url(#clip-4)">
<g clip-path="url(#clip-5)">
<path fill-rule="nonzero" fill="url(#linear-pattern-2)" d="M 42.34375 80.949219 L 79.097656 80.949219 L 79.097656 3.996094 L 42.34375 3.996094 Z M 42.34375 80.949219 "/>
</g>
</g>
<g clip-path="url(#clip-6)">
<g clip-path="url(#clip-7)">
<path fill-rule="nonzero" fill="url(#linear-pattern-3)" d="M 7.960938 48.359375 L 74.933594 115.332031 L 141.90625 48.359375 L 74.933594 -18.617188 Z M 7.960938 48.359375 "/>
</g>
</g>
<g clip-path="url(#clip-8)">
<g clip-path="url(#clip-9)">
<path fill-rule="nonzero" fill="url(#linear-pattern-4)" d="M 42.34375 44.191406 L 42.34375 80.949219 L 119.296875 80.949219 L 119.296875 44.191406 Z M 42.34375 44.191406 "/>
</g>
</g>
<path fill-rule="nonzero" fill="rgb(100%, 100%, 100%)" fill-opacity="1" d="M 79.097656 62.570312 C 79.097656 72.71875 70.871094 80.949219 60.722656 80.949219 C 50.570312 80.949219 42.34375 72.71875 42.34375 62.570312 C 42.34375 52.421875 50.570312 44.191406 60.722656 44.191406 C 70.871094 44.191406 79.097656 52.421875 79.097656 62.570312 "/>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-0" x="133.1255" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-1" x="141.8111" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-2" x="158.2975" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-3" x="170.0435" y="39.8591"/>
<use xlink:href="#glyph-0-4" x="187.3475" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-5" x="198.5587" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-6" x="224.2543" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-7" x="241.4435" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-8" x="253.7943" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-9" x="261.5951" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-10" x="279.0391" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-11" x="295.5983" y="39.8591"/>
<use xlink:href="#glyph-0-12" x="312.1183" y="39.8591"/>
<use xlink:href="#glyph-0-11" x="316.5983" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-7" x="332.8551" y="39.8591"/>
<use xlink:href="#glyph-0-12" x="344.9791" y="39.8591"/>
<use xlink:href="#glyph-0-13" x="349.4591" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-14" x="362.3475" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-13" x="378.3775" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-7" x="391.1511" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-15" x="403.2219" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-5" x="419.8231" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-11" x="445.4655" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-13" x="462.0303" y="39.8591"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-16" x="133.1255" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-11" x="150.4547" y="66.8511"/>
<use xlink:href="#glyph-0-12" x="166.9747" y="66.8511"/>
<use xlink:href="#glyph-0-17" x="171.4547" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-3" x="185.8383" y="66.8511"/>
<use xlink:href="#glyph-0-5" x="203.1423" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-5" x="228.9331" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-10" x="254.6539" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-1" x="271.2971" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-8" x="288.0467" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-17" x="295.7887" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-6" x="310.2927" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-7" x="327.4847" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-8" x="339.8327" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-3" x="347.5747" y="66.8511"/>
<use xlink:href="#glyph-0-1" x="364.8787" y="66.8511"/>
<use xlink:href="#glyph-0-12" x="381.5107" y="66.8511"/>
<use xlink:href="#glyph-0-12" x="385.9907" y="66.8511"/>
<use xlink:href="#glyph-0-0" x="390.4707" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-18" x="399.0331" y="66.8511"/>
</g>
<g fill="rgb(21.960449%, 21.960449%, 21.960449%)" fill-opacity="1">
<use xlink:href="#glyph-0-19" x="415.7099" y="66.8511"/>
</g>
<path fill-rule="nonzero" fill="rgb(86.66687%, 0%, 41.175842%)" fill-opacity="1" d="M 453.445312 65.542969 C 453.445312 66.425781 454.160156 67.140625 455.039062 67.140625 L 472.71875 67.140625 C 473.597656 67.140625 474.3125 66.425781 474.3125 65.542969 L 474.3125 47.867188 C 474.3125 46.984375 473.597656 46.273438 472.71875 46.273438 L 455.039062 46.273438 C 454.160156 46.273438 453.445312 46.984375 453.445312 47.867188 Z M 453.445312 65.542969 "/>
<path fill-rule="nonzero" fill="rgb(100%, 100%, 100%)" fill-opacity="1" d="M 465.027344 52.910156 L 462.621094 52.910156 C 462.5 54.304688 462.382812 55.492188 462.273438 56.386719 C 462.160156 57.277344 462.054688 57.957031 461.953125 58.597656 C 461.84375 59.242188 461.738281 59.824219 461.628906 60.351562 C 461.535156 60.765625 461.40625 61.085938 461.226562 61.316406 C 461.050781 61.550781 460.796875 61.710938 460.460938 61.800781 C 460.175781 61.867188 459.902344 61.816406 459.625 61.632812 C 459.351562 61.453125 459.191406 61.238281 459.128906 60.988281 C 459.089844 60.800781 459.078125 60.644531 459.101562 60.515625 C 459.117188 60.386719 459.15625 60.265625 459.214844 60.15625 C 459.269531 60.046875 459.332031 59.945312 459.40625 59.851562 C 459.46875 59.761719 459.542969 59.671875 459.617188 59.582031 C 459.644531 59.554688 459.761719 59.414062 459.984375 59.15625 C 460.203125 58.898438 460.363281 58.664062 460.476562 58.453125 C 460.585938 58.242188 460.828125 57.773438 460.949219 57.195312 C 461.070312 56.617188 461.320312 54.632812 461.316406 52.910156 L 460.300781 52.910156 C 460.015625 52.910156 459.734375 53.003906 459.472656 53.140625 C 459.21875 53.273438 458.992188 53.5 458.890625 53.632812 C 458.78125 53.765625 458.503906 54.210938 458.441406 54.296875 C 458.375 54.382812 458.242188 54.582031 458.144531 54.550781 C 458.035156 54.515625 458.058594 54.394531 458.074219 54.296875 C 458.09375 54.199219 458.292969 53.699219 458.441406 53.324219 C 458.589844 52.945312 458.792969 52.578125 459.046875 52.226562 C 459.246094 51.925781 459.519531 51.710938 459.859375 51.496094 C 460.203125 51.273438 460.597656 51.164062 461.050781 51.164062 L 468.429688 51.164062 C 468.5625 51.164062 469.253906 51.21875 469.253906 52.03125 C 469.253906 52.839844 468.515625 52.910156 468.429688 52.910156 L 466.335938 52.910156 C 466.160156 54.570312 466.074219 56.28125 466.074219 57.964844 C 466.074219 58.269531 466.125 58.570312 466.230469 58.859375 C 466.335938 59.152344 466.464844 59.375 466.617188 59.523438 C 466.816406 59.707031 467.050781 59.824219 467.332031 59.875 C 467.617188 59.925781 467.902344 59.839844 468.191406 59.609375 C 468.351562 59.484375 468.46875 59.34375 468.542969 59.1875 C 468.617188 59.023438 468.660156 58.871094 468.683594 58.726562 C 468.703125 58.578125 468.738281 58.371094 468.742188 58.320312 C 468.746094 58.273438 468.738281 58.089844 468.945312 58.074219 C 469.152344 58.058594 469.171875 58.242188 469.191406 58.441406 C 469.210938 58.640625 469.101562 59.382812 468.9375 59.84375 C 468.769531 60.308594 468.570312 60.679688 468.339844 60.957031 C 468.109375 61.242188 467.886719 61.445312 467.664062 61.566406 C 467.410156 61.71875 467.117188 61.8125 466.785156 61.84375 C 466.449219 61.878906 466.140625 61.796875 465.867188 61.613281 C 465.40625 61.277344 465.054688 60.753906 464.824219 60.039062 C 464.683594 59.621094 464.617188 59.070312 464.597656 58.386719 C 464.578125 57.703125 464.601562 57.035156 464.664062 56.382812 Z M 465.027344 52.910156 "/>
</svg>

After

Width:  |  Height:  |  Size: 96 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 172.11 113.06"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:url(#Dégradé_sans_nom_5);}.cls-3{fill:url(#Dégradé_sans_nom_7);}.cls-4{fill:url(#Dégradé_sans_nom_8);}.cls-5{fill:url(#Dégradé_sans_nom_9);}.cls-6{fill:url(#Dégradé_sans_nom_6);}</style><linearGradient id="Dégradé_sans_nom_6" x1="113.05" y1="86.06" x2="0" y2="86.06" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset=".28" stop-color="#fcfae1"/><stop offset=".76" stop-color="#f8f3b1"/><stop offset="1" stop-color="#f7f19f"/></linearGradient><linearGradient id="Dégradé_sans_nom_5" x1="105.15" y1="105.15" x2="25.2" y2="25.21" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset=".38" stop-color="#cee6f4"/><stop offset=".79" stop-color="#9ecfea"/><stop offset="1" stop-color="#8cc6e6"/></linearGradient><linearGradient id="Dégradé_sans_nom_7" x1="86.06" y1="113.06" x2="86.06" y2="0" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset=".36" stop-color="#dbd2e5"/><stop offset=".79" stop-color="#b6a2ca"/><stop offset="1" stop-color="#a890c0"/></linearGradient><linearGradient id="Dégradé_sans_nom_8" x1="66.96" y1="105.15" x2="146.91" y2="25.21" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset=".19" stop-color="#f8edf0"/><stop offset=".73" stop-color="#e8bdc9"/><stop offset="1" stop-color="#e2abba"/></linearGradient><linearGradient id="Dégradé_sans_nom_9" x1="59.06" y1="86.06" x2="172.11" y2="86.06" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset=".32" stop-color="#daeae8"/><stop offset=".77" stop-color="#aad1ca"/><stop offset="1" stop-color="#98c7bf"/></linearGradient></defs><path class="cls-6" d="M86.06,113.06H27c-14.91,0-27-12.09-27-27s12.09-27,27-27h59.06c14.91,0,27,12.09,27,27s-12.09,27-27,27Z"/><path class="cls-2" d="M86.06,113.06c-6.91,0-13.82-2.64-19.09-7.91L25.2,63.39c-10.54-10.54-10.54-27.64,0-38.18,10.54-10.54,27.64-10.54,38.18,0l41.76,41.76c10.54,10.54,10.54,27.64,0,38.18-5.27,5.27-12.18,7.91-19.09,7.91Z"/><path class="cls-3" d="M86.06,113.06c-14.91,0-27-12.09-27-27V27c0-14.91,12.09-27,27-27s27,12.09,27,27v59.06c0,14.91-12.09,27-27,27Z"/><path class="cls-4" d="M86.06,113.06c-6.91,0-13.82-2.64-19.09-7.91-10.54-10.54-10.54-27.64,0-38.18L108.72,25.21c10.54-10.54,27.64-10.54,38.18,0,10.54,10.54,10.54,27.64,0,38.18l-41.76,41.76c-5.27,5.27-12.18,7.91-19.09,7.91Z"/><path class="cls-5" d="M145.11,113.06h-59.06c-14.91,0-27-12.09-27-27s12.09-27,27-27h59.06c14.91,0,27,12.09,27,27s-12.09,27-27,27Z"/><circle class="cls-1" cx="86.06" cy="86.06" r="27"/></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,988 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="482.222" height="84.6667" viewBox="0 0 482.222 84.6667">
<defs>
<g>
<g id="glyph-0-0">
<path d="M 6.6875 0 L 1.8125 0 L 1.8125 -18.765625 L 6.6875 -18.765625 Z M 6.6875 0 "/>
</g>
<g id="glyph-0-1">
<path d="M 5.96875 -13.640625 L 5.96875 -12.375 C 6.28125 -12.84375 6.796875 -13.21875 7.515625 -13.5 C 8.234375 -13.78125 8.976562 -13.921875 9.75 -13.921875 C 11.613281 -13.921875 12.992188 -13.394531 13.890625 -12.34375 C 14.785156 -11.300781 15.234375 -9.847656 15.234375 -7.984375 L 15.234375 0 L 10.53125 0 L 10.53125 -6.890625 C 10.53125 -7.972656 10.359375 -8.742188 10.015625 -9.203125 C 9.679688 -9.660156 9.066406 -9.890625 8.171875 -9.890625 C 7.503906 -9.890625 6.863281 -9.71875 6.25 -9.375 L 6.25 0 L 1.546875 0 L 1.546875 -13.640625 Z M 5.96875 -13.640625 "/>
</g>
<g id="glyph-0-2">
<path d="M 2.796875 -13.640625 L 2.796875 -14.28125 C 2.796875 -16 3.335938 -17.3125 4.421875 -18.21875 C 5.503906 -19.132812 6.894531 -19.59375 8.59375 -19.59375 C 9.5625 -19.59375 10.410156 -19.519531 11.140625 -19.375 L 11.140625 -15.453125 C 10.640625 -15.546875 10.164062 -15.59375 9.71875 -15.59375 C 8.238281 -15.59375 7.5 -14.941406 7.5 -13.640625 L 11.140625 -13.640625 L 11.140625 -9.859375 L 7.5 -9.859375 L 7.5 0 L 2.796875 0 L 2.796875 -9.859375 L 0.84375 -9.859375 L 0.84375 -13.640625 Z M 2.796875 -13.640625 "/>
</g>
<g id="glyph-0-3">
<path d="M 0.984375 -6.828125 C 0.984375 -8.847656 1.710938 -10.535156 3.171875 -11.890625 C 4.640625 -13.242188 6.457031 -13.921875 8.625 -13.921875 C 10.789062 -13.921875 12.613281 -13.242188 14.09375 -11.890625 C 15.582031 -10.535156 16.328125 -8.847656 16.328125 -6.828125 C 16.328125 -4.816406 15.585938 -3.128906 14.109375 -1.765625 C 12.617188 -0.398438 10.789062 0.28125 8.625 0.28125 C 6.457031 0.28125 4.640625 -0.398438 3.171875 -1.765625 C 1.710938 -3.128906 0.984375 -4.816406 0.984375 -6.828125 Z M 6.53125 -4.640625 C 7.050781 -4.066406 7.75 -3.78125 8.625 -3.78125 C 9.5 -3.78125 10.207031 -4.0625 10.75 -4.625 C 11.289062 -5.195312 11.5625 -5.929688 11.5625 -6.828125 C 11.5625 -7.703125 11.289062 -8.429688 10.75 -9.015625 C 10.207031 -9.597656 9.5 -9.890625 8.625 -9.890625 C 7.769531 -9.890625 7.070312 -9.597656 6.53125 -9.015625 C 6 -8.429688 5.734375 -7.703125 5.734375 -6.828125 C 5.734375 -5.929688 6 -5.203125 6.53125 -4.640625 Z M 6.53125 -4.640625 "/>
</g>
<g id="glyph-0-4">
<path d="M 1.546875 -13.640625 L 5.96875 -13.640625 L 5.96875 -12.234375 C 6.25 -12.734375 6.6875 -13.113281 7.28125 -13.375 C 7.875 -13.644531 8.507812 -13.78125 9.1875 -13.78125 C 9.65625 -13.78125 10.140625 -13.722656 10.640625 -13.609375 L 10.640625 -9.375 C 10.046875 -9.4375 9.457031 -9.46875 8.875 -9.46875 C 7.8125 -9.46875 6.9375 -9.328125 6.25 -9.046875 L 6.25 0 L 1.546875 0 Z M 1.546875 -13.640625 "/>
</g>
<g id="glyph-0-5">
<path d="M 5.96875 -13.640625 L 5.96875 -12.375 C 6.28125 -12.84375 6.796875 -13.21875 7.515625 -13.5 C 8.234375 -13.78125 8.976562 -13.921875 9.75 -13.921875 C 11.707031 -13.921875 13.148438 -13.320312 14.078125 -12.125 C 14.421875 -12.644531 14.988281 -13.070312 15.78125 -13.40625 C 16.570312 -13.75 17.367188 -13.921875 18.171875 -13.921875 C 20.078125 -13.921875 21.5625 -13.382812 22.625 -12.3125 C 23.6875 -11.25 24.21875 -9.804688 24.21875 -7.984375 L 24.21875 0 L 19.515625 0 L 19.515625 -6.890625 C 19.515625 -7.972656 19.347656 -8.742188 19.015625 -9.203125 C 18.679688 -9.660156 18.066406 -9.890625 17.171875 -9.890625 C 16.472656 -9.890625 15.796875 -9.710938 15.140625 -9.359375 C 15.203125 -8.921875 15.234375 -8.460938 15.234375 -7.984375 L 15.234375 0 L 10.53125 0 L 10.53125 -6.890625 C 10.53125 -7.972656 10.359375 -8.742188 10.015625 -9.203125 C 9.679688 -9.660156 9.066406 -9.890625 8.171875 -9.890625 C 7.503906 -9.890625 6.863281 -9.71875 6.25 -9.375 L 6.25 0 L 1.546875 0 L 1.546875 -13.640625 Z M 5.96875 -13.640625 "/>
</g>
<g id="glyph-0-6">
<path d="M 2.828125 -11.90625 C 4.054688 -13.25 5.671875 -13.921875 7.671875 -13.921875 C 9.410156 -13.921875 10.625 -13.472656 11.3125 -12.578125 L 11.3125 -13.640625 L 15.734375 -13.640625 L 15.734375 0 L 11.3125 0 L 11.3125 -1.0625 C 10.601562 -0.164062 9.390625 0.28125 7.671875 0.28125 C 5.671875 0.28125 4.054688 -0.394531 2.828125 -1.75 C 1.597656 -3.101562 0.984375 -4.796875 0.984375 -6.828125 C 0.984375 -8.847656 1.597656 -10.539062 2.828125 -11.90625 Z M 6.546875 -4.625 C 7.085938 -4.039062 7.789062 -3.75 8.65625 -3.75 C 9.457031 -3.75 10.269531 -3.992188 11.09375 -4.484375 L 11.09375 -9.1875 C 10.34375 -9.65625 9.53125 -9.890625 8.65625 -9.890625 C 7.789062 -9.890625 7.085938 -9.597656 6.546875 -9.015625 C 6.003906 -8.429688 5.734375 -7.703125 5.734375 -6.828125 C 5.734375 -5.929688 6.003906 -5.195312 6.546875 -4.625 Z M 6.546875 -4.625 "/>
</g>
<g id="glyph-0-7">
<path d="M 2.796875 -13.640625 L 2.796875 -17.046875 L 7.5 -17.046875 L 7.5 -13.640625 L 11.140625 -13.640625 L 11.140625 -9.859375 L 7.5 -9.859375 L 7.5 -6.078125 C 7.5 -5.273438 7.6875 -4.703125 8.0625 -4.359375 C 8.4375 -4.023438 8.988281 -3.859375 9.71875 -3.859375 C 10.164062 -3.859375 10.640625 -3.90625 11.140625 -4 L 11.140625 -0.078125 C 10.410156 0.0664062 9.5625 0.140625 8.59375 0.140625 C 6.851562 0.140625 5.453125 -0.273438 4.390625 -1.109375 C 3.328125 -1.941406 2.796875 -3.207031 2.796875 -4.90625 L 2.796875 -9.859375 L 0.84375 -9.859375 L 0.84375 -13.640625 Z M 2.796875 -13.640625 "/>
</g>
<g id="glyph-0-8">
<path d="M 1.546875 0 L 1.546875 -13.640625 L 6.25 -13.640625 L 6.25 0 Z M 1.203125 -17.78125 C 1.203125 -18.488281 1.460938 -19.097656 1.984375 -19.609375 C 2.503906 -20.128906 3.140625 -20.390625 3.890625 -20.390625 C 4.640625 -20.390625 5.273438 -20.128906 5.796875 -19.609375 C 6.316406 -19.097656 6.578125 -18.488281 6.578125 -17.78125 C 6.578125 -17.070312 6.316406 -16.460938 5.796875 -15.953125 C 5.273438 -15.429688 4.640625 -15.171875 3.890625 -15.171875 C 3.140625 -15.171875 2.503906 -15.425781 1.984375 -15.9375 C 1.460938 -16.457031 1.203125 -17.070312 1.203125 -17.78125 Z M 1.203125 -17.78125 "/>
</g>
<g id="glyph-0-9">
<path d="M 2.828125 -11.90625 C 4.054688 -13.25 5.671875 -13.921875 7.671875 -13.921875 C 9.390625 -13.921875 10.601562 -13.472656 11.3125 -12.578125 L 11.3125 -13.640625 L 15.734375 -13.640625 L 15.734375 5.59375 L 11.03125 5.59375 L 11.03125 -0.75 C 10.25 -0.0625 9.128906 0.28125 7.671875 0.28125 C 5.671875 0.28125 4.054688 -0.394531 2.828125 -1.75 C 1.597656 -3.101562 0.984375 -4.785156 0.984375 -6.796875 C 0.984375 -8.835938 1.597656 -10.539062 2.828125 -11.90625 Z M 6.546875 -4.625 C 7.085938 -4.039062 7.789062 -3.75 8.65625 -3.75 C 9.53125 -3.75 10.34375 -3.984375 11.09375 -4.453125 L 11.09375 -9.15625 C 10.269531 -9.644531 9.457031 -9.890625 8.65625 -9.890625 C 7.789062 -9.890625 7.085938 -9.597656 6.546875 -9.015625 C 6.003906 -8.429688 5.734375 -7.691406 5.734375 -6.796875 C 5.734375 -5.921875 6.003906 -5.195312 6.546875 -4.625 Z M 6.546875 -4.625 "/>
</g>
<g id="glyph-0-10">
<path d="M 1.40625 -13.640625 L 6.109375 -13.640625 L 6.109375 -6.1875 C 6.109375 -5.382812 6.28125 -4.773438 6.625 -4.359375 C 6.96875 -3.953125 7.578125 -3.75 8.453125 -3.75 C 9.109375 -3.75 9.71875 -3.898438 10.28125 -4.203125 L 10.28125 -13.640625 L 14.984375 -13.640625 L 14.984375 0 L 10.578125 0 L 10.578125 -1.140625 C 10.242188 -0.710938 9.722656 -0.367188 9.015625 -0.109375 C 8.304688 0.148438 7.597656 0.28125 6.890625 0.28125 C 5.023438 0.28125 3.644531 -0.238281 2.75 -1.28125 C 1.851562 -2.332031 1.40625 -3.789062 1.40625 -5.65625 Z M 1.40625 -13.640625 "/>
</g>
<g id="glyph-0-11">
<path d="M 15.625 -6.796875 C 15.625 -6.347656 15.597656 -5.898438 15.546875 -5.453125 L 5.59375 -5.453125 C 6.175781 -4.191406 7.53125 -3.5625 9.65625 -3.5625 C 11.132812 -3.5625 12.609375 -3.820312 14.078125 -4.34375 L 14.078125 -0.59375 C 12.703125 -0.0078125 11.085938 0.28125 9.234375 0.28125 C 6.703125 0.28125 4.691406 -0.359375 3.203125 -1.640625 C 1.722656 -2.929688 0.984375 -4.660156 0.984375 -6.828125 C 0.984375 -8.867188 1.675781 -10.5625 3.0625 -11.90625 C 4.457031 -13.25 6.207031 -13.921875 8.3125 -13.921875 C 10.425781 -13.921875 12.171875 -13.25 13.546875 -11.90625 C 14.929688 -10.5625 15.625 -8.859375 15.625 -6.796875 Z M 8.3125 -10.109375 C 6.875 -10.109375 5.941406 -9.472656 5.515625 -8.203125 L 11.03125 -8.203125 C 10.625 -9.472656 9.71875 -10.109375 8.3125 -10.109375 Z M 8.3125 -10.109375 "/>
</g>
<g id="glyph-0-12">
</g>
<g id="glyph-0-13">
<path d="M 2.4375 -12.65625 C 3.40625 -13.5 4.75 -13.921875 6.46875 -13.921875 C 8.28125 -13.921875 9.894531 -13.65625 11.3125 -13.125 L 11.3125 -9.484375 C 9.632812 -10.015625 8.046875 -10.28125 6.546875 -10.28125 C 5.671875 -10.28125 5.234375 -10.070312 5.234375 -9.65625 C 5.234375 -9.46875 5.34375 -9.320312 5.5625 -9.21875 C 5.789062 -9.125 6.203125 -9.007812 6.796875 -8.875 L 7.984375 -8.625 C 9.472656 -8.300781 10.5625 -7.816406 11.25 -7.171875 C 11.945312 -6.535156 12.296875 -5.617188 12.296875 -4.421875 C 12.296875 -3.023438 11.769531 -1.890625 10.71875 -1.015625 C 9.675781 -0.148438 8.164062 0.28125 6.1875 0.28125 C 4.4375 0.28125 2.820312 -0.0234375 1.34375 -0.640625 L 1.34375 -4.484375 C 3.039062 -3.773438 4.722656 -3.421875 6.390625 -3.421875 C 7.472656 -3.421875 8.015625 -3.660156 8.015625 -4.140625 C 8.015625 -4.347656 7.910156 -4.503906 7.703125 -4.609375 C 7.492188 -4.710938 7.09375 -4.816406 6.5 -4.921875 L 5.1875 -5.203125 C 2.382812 -5.804688 0.984375 -7.191406 0.984375 -9.359375 C 0.984375 -10.710938 1.46875 -11.8125 2.4375 -12.65625 Z M 2.4375 -12.65625 "/>
</g>
<g id="glyph-0-14">
<path d="M 0.140625 -13.640625 L 5.234375 -13.640625 L 8.203125 -6.828125 L 11.203125 -13.640625 L 16.21875 -13.640625 L 7.03125 5.59375 L 2.078125 5.59375 L 5.796875 -1.875 Z M 0.140625 -13.640625 "/>
</g>
<g id="glyph-0-15">
<path d="M 9.21875 -19.40625 L 10.046875 -15.171875 L 6.546875 -15.171875 L 4.3125 -19.40625 Z M 15.625 -6.796875 C 15.625 -6.347656 15.597656 -5.898438 15.546875 -5.453125 L 5.59375 -5.453125 C 6.175781 -4.191406 7.53125 -3.5625 9.65625 -3.5625 C 11.132812 -3.5625 12.609375 -3.820312 14.078125 -4.34375 L 14.078125 -0.59375 C 12.703125 -0.0078125 11.085938 0.28125 9.234375 0.28125 C 6.703125 0.28125 4.691406 -0.359375 3.203125 -1.640625 C 1.722656 -2.929688 0.984375 -4.660156 0.984375 -6.828125 C 0.984375 -8.867188 1.675781 -10.5625 3.0625 -11.90625 C 4.457031 -13.25 6.207031 -13.921875 8.3125 -13.921875 C 10.425781 -13.921875 12.171875 -13.25 13.546875 -11.90625 C 14.929688 -10.5625 15.625 -8.859375 15.625 -6.796875 Z M 8.3125 -10.109375 C 6.875 -10.109375 5.941406 -9.472656 5.515625 -8.203125 L 11.03125 -8.203125 C 10.625 -9.472656 9.71875 -10.109375 8.3125 -10.109375 Z M 8.3125 -10.109375 "/>
</g>
<g id="glyph-0-16">
<path d="M 2.828125 -11.90625 C 4.054688 -13.25 5.671875 -13.921875 7.671875 -13.921875 C 9.128906 -13.921875 10.25 -13.570312 11.03125 -12.875 L 11.03125 -19.3125 L 15.734375 -19.3125 L 15.734375 0 L 11.375 0 L 11.375 -1.140625 C 10.65625 -0.191406 9.421875 0.28125 7.671875 0.28125 C 5.671875 0.28125 4.054688 -0.394531 2.828125 -1.75 C 1.597656 -3.101562 0.984375 -4.796875 0.984375 -6.828125 C 0.984375 -8.847656 1.597656 -10.539062 2.828125 -11.90625 Z M 6.546875 -4.625 C 7.085938 -4.039062 7.789062 -3.75 8.65625 -3.75 C 9.457031 -3.75 10.269531 -3.992188 11.09375 -4.484375 L 11.09375 -9.1875 C 10.34375 -9.65625 9.53125 -9.890625 8.65625 -9.890625 C 7.789062 -9.890625 7.085938 -9.597656 6.546875 -9.015625 C 6.003906 -8.429688 5.734375 -7.703125 5.734375 -6.828125 C 5.734375 -5.929688 6.003906 -5.195312 6.546875 -4.625 Z M 6.546875 -4.625 "/>
</g>
<g id="glyph-0-17">
<path d="M 3.140625 -11.90625 C 4.578125 -13.25 6.40625 -13.921875 8.625 -13.921875 C 10.28125 -13.921875 11.800781 -13.65625 13.1875 -13.125 L 13.1875 -9.046875 C 11.882812 -9.609375 10.644531 -9.890625 9.46875 -9.890625 C 8.269531 -9.890625 7.347656 -9.601562 6.703125 -9.03125 C 6.054688 -8.457031 5.734375 -7.722656 5.734375 -6.828125 C 5.734375 -5.910156 6.054688 -5.171875 6.703125 -4.609375 C 7.347656 -4.054688 8.269531 -3.78125 9.46875 -3.78125 C 10.582031 -3.78125 11.820312 -4.0625 13.1875 -4.625 L 13.1875 -0.5 C 11.800781 0.0195312 10.28125 0.28125 8.625 0.28125 C 6.40625 0.28125 4.578125 -0.394531 3.140625 -1.75 C 1.703125 -3.101562 0.984375 -4.796875 0.984375 -6.828125 C 0.984375 -8.867188 1.703125 -10.5625 3.140625 -11.90625 Z M 3.140625 -11.90625 "/>
</g>
<g id="glyph-0-18">
<path d="M 1.546875 -13.25 C 1.546875 -15.050781 2.179688 -16.488281 3.453125 -17.5625 C 4.734375 -18.644531 6.398438 -19.1875 8.453125 -19.1875 C 10.660156 -19.1875 12.734375 -18.8125 14.671875 -18.0625 L 14.671875 -13.78125 C 12.578125 -14.613281 10.609375 -15.03125 8.765625 -15.03125 C 7.117188 -15.03125 6.296875 -14.582031 6.296875 -13.6875 C 6.296875 -13.238281 6.484375 -12.90625 6.859375 -12.6875 C 7.234375 -12.476562 7.882812 -12.234375 8.8125 -11.953125 L 10.1875 -11.5625 C 12 -11.0625 13.367188 -10.351562 14.296875 -9.4375 C 15.234375 -8.519531 15.703125 -7.332031 15.703125 -5.875 C 15.703125 -3.882812 15.007812 -2.335938 13.625 -1.234375 C 12.25 -0.128906 10.378906 0.421875 8.015625 0.421875 C 5.941406 0.421875 3.929688 0.046875 1.984375 -0.703125 L 1.984375 -5.046875 C 4.097656 -4.203125 6.097656 -3.78125 7.984375 -3.78125 C 8.953125 -3.78125 9.6875 -3.925781 10.1875 -4.21875 C 10.695312 -4.519531 10.953125 -4.929688 10.953125 -5.453125 C 10.953125 -5.941406 10.78125 -6.285156 10.4375 -6.484375 C 10.101562 -6.691406 9.441406 -6.929688 8.453125 -7.203125 L 6.9375 -7.609375 C 3.34375 -8.617188 1.546875 -10.5 1.546875 -13.25 Z M 1.546875 -13.25 "/>
</g>
<g id="glyph-0-19">
<path d="M 3.953125 -16.375 C 5.847656 -18.25 8.367188 -19.1875 11.515625 -19.1875 C 13.878906 -19.1875 15.976562 -18.820312 17.8125 -18.09375 L 17.8125 -13.5 C 15.945312 -14.238281 14.03125 -14.609375 12.0625 -14.609375 C 10.195312 -14.609375 8.738281 -14.125 7.6875 -13.15625 C 6.644531 -12.1875 6.125 -10.925781 6.125 -9.375 C 6.125 -7.832031 6.644531 -6.570312 7.6875 -5.59375 C 8.738281 -4.625 10.195312 -4.140625 12.0625 -4.140625 C 14.03125 -4.140625 15.945312 -4.515625 17.8125 -5.265625 L 17.8125 -0.671875 C 15.976562 0.0546875 13.878906 0.421875 11.515625 0.421875 C 8.367188 0.421875 5.84375 -0.515625 3.9375 -2.390625 C 2.039062 -4.265625 1.09375 -6.59375 1.09375 -9.375 C 1.09375 -12.15625 2.046875 -14.488281 3.953125 -16.375 Z M 3.953125 -16.375 "/>
</g>
</g>
<clipPath id="clip-0">
<path clip-rule="nonzero" d="M 2 44 L 80 44 L 80 81 L 2 81 Z M 2 44 "/>
</clipPath>
<clipPath id="clip-1">
<path clip-rule="nonzero" d="M 20.523438 44.191406 C 10.375 44.191406 2.144531 52.421875 2.144531 62.570312 C 2.144531 72.71875 10.375 80.949219 20.523438 80.949219 L 60.722656 80.949219 C 70.871094 80.949219 79.097656 72.71875 79.097656 62.570312 C 79.097656 52.421875 70.871094 44.191406 60.722656 44.191406 Z M 20.523438 44.191406 "/>
</clipPath>
<linearGradient id="linear-pattern-0" gradientUnits="userSpaceOnUse" x1="0.00000772817" y1="0" x2="1.000005" y2="0" gradientTransform="matrix(-76.952225, 0, 0, -76.952225, 79.098595, 62.570047)">
<stop offset="0" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.015625" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0234375" stop-color="rgb(100%, 100%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.03125" stop-color="rgb(100%, 100%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.0390625" stop-color="rgb(100%, 100%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.046875" stop-color="rgb(100%, 99.607849%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.0546875" stop-color="rgb(100%, 99.607849%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.0625" stop-color="rgb(100%, 99.607849%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.0703125" stop-color="rgb(100%, 99.607849%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.078125" stop-color="rgb(100%, 99.607849%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.0859375" stop-color="rgb(100%, 99.607849%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.09375" stop-color="rgb(100%, 99.607849%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.101562" stop-color="rgb(100%, 99.607849%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.109375" stop-color="rgb(100%, 99.215698%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.117187" stop-color="rgb(100%, 99.215698%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.125" stop-color="rgb(99.607849%, 99.215698%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.132812" stop-color="rgb(99.607849%, 99.215698%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.140625" stop-color="rgb(99.607849%, 99.215698%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.148438" stop-color="rgb(99.607849%, 99.215698%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.15625" stop-color="rgb(99.607849%, 99.215698%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.164062" stop-color="rgb(99.607849%, 99.215698%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.171875" stop-color="rgb(99.607849%, 98.823547%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.179688" stop-color="rgb(99.607849%, 98.823547%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.1875" stop-color="rgb(99.607849%, 98.823547%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.195312" stop-color="rgb(99.607849%, 98.823547%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.203125" stop-color="rgb(99.607849%, 98.823547%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.210937" stop-color="rgb(99.607849%, 98.823547%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.21875" stop-color="rgb(99.607849%, 98.823547%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.226562" stop-color="rgb(99.607849%, 98.823547%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.234375" stop-color="rgb(99.607849%, 98.431396%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.242188" stop-color="rgb(99.607849%, 98.431396%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.25" stop-color="rgb(99.607849%, 98.431396%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.257812" stop-color="rgb(99.607849%, 98.431396%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.265625" stop-color="rgb(99.607849%, 98.431396%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.273438" stop-color="rgb(99.607849%, 98.431396%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.28125" stop-color="rgb(99.607849%, 98.431396%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.289062" stop-color="rgb(99.607849%, 98.431396%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.296875" stop-color="rgb(99.607849%, 98.431396%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.304688" stop-color="rgb(99.607849%, 98.431396%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.3125" stop-color="rgb(99.607849%, 98.431396%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.320312" stop-color="rgb(99.607849%, 98.039246%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.328125" stop-color="rgb(99.607849%, 98.039246%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.335938" stop-color="rgb(99.215698%, 98.039246%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.34375" stop-color="rgb(99.215698%, 98.039246%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.351562" stop-color="rgb(99.215698%, 98.039246%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.359375" stop-color="rgb(99.215698%, 98.039246%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.367188" stop-color="rgb(99.215698%, 98.039246%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.375" stop-color="rgb(99.215698%, 98.039246%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.382812" stop-color="rgb(99.215698%, 97.647095%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.390625" stop-color="rgb(99.215698%, 97.647095%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.398437" stop-color="rgb(99.215698%, 97.647095%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.40625" stop-color="rgb(99.215698%, 97.647095%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.414062" stop-color="rgb(99.215698%, 97.647095%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.421875" stop-color="rgb(99.215698%, 97.647095%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.429688" stop-color="rgb(99.215698%, 97.647095%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.4375" stop-color="rgb(99.215698%, 97.647095%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.445312" stop-color="rgb(99.215698%, 97.254944%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.453125" stop-color="rgb(99.215698%, 97.254944%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.460938" stop-color="rgb(99.215698%, 97.254944%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.46875" stop-color="rgb(99.215698%, 97.254944%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.476562" stop-color="rgb(99.215698%, 97.254944%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.484375" stop-color="rgb(99.215698%, 97.254944%, 80.784607%)" stop-opacity="1"/>
<stop offset="0.492187" stop-color="rgb(98.823547%, 97.254944%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.5" stop-color="rgb(98.823547%, 97.254944%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.507812" stop-color="rgb(98.823547%, 96.862793%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.515625" stop-color="rgb(98.823547%, 96.862793%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.523438" stop-color="rgb(98.823547%, 96.862793%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.53125" stop-color="rgb(98.823547%, 96.862793%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.539062" stop-color="rgb(98.823547%, 96.862793%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.546875" stop-color="rgb(98.823547%, 96.862793%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.554688" stop-color="rgb(98.823547%, 96.862793%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.5625" stop-color="rgb(98.823547%, 96.862793%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.570312" stop-color="rgb(98.823547%, 96.862793%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.578125" stop-color="rgb(98.823547%, 96.862793%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.585938" stop-color="rgb(98.823547%, 96.470642%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.59375" stop-color="rgb(98.823547%, 96.470642%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.601562" stop-color="rgb(98.823547%, 96.470642%, 76.078796%)" stop-opacity="1"/>
<stop offset="0.609375" stop-color="rgb(98.823547%, 96.470642%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.617188" stop-color="rgb(98.431396%, 96.470642%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.625" stop-color="rgb(98.431396%, 96.470642%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.632812" stop-color="rgb(98.431396%, 96.470642%, 74.902344%)" stop-opacity="1"/>
<stop offset="0.640625" stop-color="rgb(98.431396%, 96.470642%, 74.510193%)" stop-opacity="1"/>
<stop offset="0.648438" stop-color="rgb(98.431396%, 96.078491%, 74.118042%)" stop-opacity="1"/>
<stop offset="0.65625" stop-color="rgb(98.431396%, 96.078491%, 73.725891%)" stop-opacity="1"/>
<stop offset="0.664062" stop-color="rgb(98.431396%, 96.078491%, 73.33374%)" stop-opacity="1"/>
<stop offset="0.671875" stop-color="rgb(98.431396%, 96.078491%, 73.33374%)" stop-opacity="1"/>
<stop offset="0.679688" stop-color="rgb(98.431396%, 96.078491%, 72.941589%)" stop-opacity="1"/>
<stop offset="0.6875" stop-color="rgb(98.431396%, 96.078491%, 72.549438%)" stop-opacity="1"/>
<stop offset="0.695312" stop-color="rgb(98.431396%, 96.078491%, 72.157288%)" stop-opacity="1"/>
<stop offset="0.703125" stop-color="rgb(98.431396%, 96.078491%, 71.765137%)" stop-opacity="1"/>
<stop offset="0.710938" stop-color="rgb(98.431396%, 96.078491%, 71.372986%)" stop-opacity="1"/>
<stop offset="0.71875" stop-color="rgb(98.431396%, 96.078491%, 71.372986%)" stop-opacity="1"/>
<stop offset="0.726562" stop-color="rgb(98.431396%, 95.68634%, 70.980835%)" stop-opacity="1"/>
<stop offset="0.734375" stop-color="rgb(98.431396%, 95.68634%, 70.588684%)" stop-opacity="1"/>
<stop offset="0.742188" stop-color="rgb(98.431396%, 95.68634%, 70.196533%)" stop-opacity="1"/>
<stop offset="0.75" stop-color="rgb(98.431396%, 95.68634%, 69.804382%)" stop-opacity="1"/>
<stop offset="0.757812" stop-color="rgb(98.431396%, 95.68634%, 69.412231%)" stop-opacity="1"/>
<stop offset="0.765625" stop-color="rgb(98.431396%, 95.68634%, 69.412231%)" stop-opacity="1"/>
<stop offset="0.773437" stop-color="rgb(98.431396%, 95.68634%, 69.020081%)" stop-opacity="1"/>
<stop offset="0.78125" stop-color="rgb(98.431396%, 95.68634%, 68.62793%)" stop-opacity="1"/>
<stop offset="0.789062" stop-color="rgb(98.431396%, 95.68634%, 68.62793%)" stop-opacity="1"/>
<stop offset="0.796875" stop-color="rgb(98.039246%, 95.68634%, 68.235779%)" stop-opacity="1"/>
<stop offset="0.804688" stop-color="rgb(98.039246%, 95.68634%, 67.843628%)" stop-opacity="1"/>
<stop offset="0.8125" stop-color="rgb(98.039246%, 95.294189%, 67.451477%)" stop-opacity="1"/>
<stop offset="0.820312" stop-color="rgb(98.039246%, 95.294189%, 67.059326%)" stop-opacity="1"/>
<stop offset="0.828125" stop-color="rgb(98.039246%, 95.294189%, 66.667175%)" stop-opacity="1"/>
<stop offset="0.835938" stop-color="rgb(98.039246%, 95.294189%, 66.667175%)" stop-opacity="1"/>
<stop offset="0.84375" stop-color="rgb(98.039246%, 95.294189%, 66.275024%)" stop-opacity="1"/>
<stop offset="0.851562" stop-color="rgb(98.039246%, 95.294189%, 65.882874%)" stop-opacity="1"/>
<stop offset="0.859375" stop-color="rgb(98.039246%, 95.294189%, 65.490723%)" stop-opacity="1"/>
<stop offset="0.867187" stop-color="rgb(98.039246%, 95.294189%, 65.490723%)" stop-opacity="1"/>
<stop offset="0.875" stop-color="rgb(98.039246%, 95.294189%, 65.098572%)" stop-opacity="1"/>
<stop offset="0.882812" stop-color="rgb(98.039246%, 95.294189%, 64.706421%)" stop-opacity="1"/>
<stop offset="0.890625" stop-color="rgb(98.039246%, 94.902039%, 64.31427%)" stop-opacity="1"/>
<stop offset="0.898438" stop-color="rgb(98.039246%, 94.902039%, 64.31427%)" stop-opacity="1"/>
<stop offset="0.90625" stop-color="rgb(98.039246%, 94.902039%, 63.922119%)" stop-opacity="1"/>
<stop offset="0.914062" stop-color="rgb(98.039246%, 94.902039%, 63.529968%)" stop-opacity="1"/>
<stop offset="0.921875" stop-color="rgb(98.039246%, 94.902039%, 63.137817%)" stop-opacity="1"/>
<stop offset="0.9375" stop-color="rgb(98.039246%, 94.902039%, 62.745667%)" stop-opacity="1"/>
<stop offset="0.945312" stop-color="rgb(98.039246%, 94.902039%, 62.745667%)" stop-opacity="1"/>
<stop offset="0.953125" stop-color="rgb(98.039246%, 94.902039%, 62.353516%)" stop-opacity="1"/>
<stop offset="0.960937" stop-color="rgb(98.039246%, 94.902039%, 61.961365%)" stop-opacity="1"/>
<stop offset="0.96875" stop-color="rgb(98.039246%, 94.902039%, 61.569214%)" stop-opacity="1"/>
<stop offset="0.984375" stop-color="rgb(98.039246%, 94.509888%, 61.177063%)" stop-opacity="1"/>
<stop offset="1" stop-color="rgb(98.039246%, 94.509888%, 60.784912%)" stop-opacity="1"/>
</linearGradient>
<clipPath id="clip-2">
<path clip-rule="nonzero" d="M 13 15 L 80 15 L 80 81 L 13 81 Z M 13 15 "/>
</clipPath>
<clipPath id="clip-3">
<path clip-rule="nonzero" d="M 19.300781 21.152344 C 12.125 28.328125 12.125 39.964844 19.300781 47.140625 L 47.726562 75.566406 C 51.316406 79.15625 56.019531 80.949219 60.722656 80.949219 C 65.425781 80.949219 70.128906 79.15625 73.714844 75.566406 C 80.894531 68.386719 80.894531 56.753906 73.714844 49.574219 L 45.292969 21.152344 C 41.703125 17.5625 37 15.769531 32.296875 15.769531 C 27.59375 15.769531 22.890625 17.5625 19.300781 21.152344 "/>
</clipPath>
<linearGradient id="linear-pattern-1" gradientUnits="userSpaceOnUse" x1="-0.115399" y1="0" x2="1.115408" y2="0" gradientTransform="matrix(-54.414318, -54.414318, 54.414318, -54.414318, 73.71669, 75.565292)">
<stop offset="0" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0625" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.09375" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0976562" stop-color="rgb(99.607849%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.101562" stop-color="rgb(99.607849%, 99.607849%, 100%)" stop-opacity="1"/>
<stop offset="0.105469" stop-color="rgb(99.215698%, 99.607849%, 100%)" stop-opacity="1"/>
<stop offset="0.109375" stop-color="rgb(99.215698%, 99.607849%, 100%)" stop-opacity="1"/>
<stop offset="0.113281" stop-color="rgb(98.823547%, 99.215698%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.117188" stop-color="rgb(98.431396%, 99.215698%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.121094" stop-color="rgb(98.431396%, 99.215698%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.125" stop-color="rgb(98.039246%, 99.215698%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.128906" stop-color="rgb(98.039246%, 98.823547%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.132812" stop-color="rgb(97.647095%, 98.823547%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.136719" stop-color="rgb(97.254944%, 98.823547%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.140625" stop-color="rgb(97.254944%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.144531" stop-color="rgb(96.862793%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.148438" stop-color="rgb(96.470642%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.152344" stop-color="rgb(96.078491%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.15625" stop-color="rgb(95.68634%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.160156" stop-color="rgb(95.68634%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.164062" stop-color="rgb(95.294189%, 98.431396%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.167969" stop-color="rgb(94.902039%, 98.039246%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.171875" stop-color="rgb(94.902039%, 98.039246%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.175781" stop-color="rgb(94.509888%, 98.039246%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.179688" stop-color="rgb(94.509888%, 97.647095%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.183594" stop-color="rgb(94.117737%, 97.647095%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.1875" stop-color="rgb(93.725586%, 97.647095%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.191406" stop-color="rgb(93.725586%, 97.254944%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.195312" stop-color="rgb(93.333435%, 97.254944%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.199219" stop-color="rgb(93.333435%, 97.254944%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.203125" stop-color="rgb(92.941284%, 97.254944%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.207031" stop-color="rgb(92.549133%, 96.862793%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.210937" stop-color="rgb(92.549133%, 96.862793%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.214844" stop-color="rgb(92.156982%, 96.862793%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.21875" stop-color="rgb(91.764832%, 96.470642%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.222656" stop-color="rgb(91.372681%, 96.470642%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.226563" stop-color="rgb(90.98053%, 96.470642%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.230469" stop-color="rgb(90.98053%, 96.078491%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.234375" stop-color="rgb(90.588379%, 96.078491%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.238281" stop-color="rgb(90.588379%, 96.078491%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.242188" stop-color="rgb(90.196228%, 95.68634%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.246094" stop-color="rgb(89.804077%, 95.68634%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.25" stop-color="rgb(89.804077%, 95.68634%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.253906" stop-color="rgb(89.411926%, 95.68634%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.257812" stop-color="rgb(89.411926%, 95.294189%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.261719" stop-color="rgb(89.019775%, 95.294189%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.265625" stop-color="rgb(88.627625%, 95.294189%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.269531" stop-color="rgb(88.627625%, 94.902039%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.273438" stop-color="rgb(88.235474%, 94.902039%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.277344" stop-color="rgb(88.235474%, 94.902039%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.28125" stop-color="rgb(87.843323%, 94.509888%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.285156" stop-color="rgb(87.451172%, 94.509888%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.289062" stop-color="rgb(87.451172%, 94.509888%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.292969" stop-color="rgb(87.059021%, 94.509888%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.296875" stop-color="rgb(86.66687%, 94.117737%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.300781" stop-color="rgb(86.66687%, 94.117737%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.304688" stop-color="rgb(86.274719%, 94.117737%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.308594" stop-color="rgb(85.882568%, 93.725586%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.3125" stop-color="rgb(85.490417%, 93.725586%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.316406" stop-color="rgb(85.098267%, 93.725586%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.320312" stop-color="rgb(85.098267%, 93.333435%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.324219" stop-color="rgb(84.706116%, 93.333435%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.328125" stop-color="rgb(84.706116%, 93.333435%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.332031" stop-color="rgb(84.313965%, 93.333435%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.335938" stop-color="rgb(83.921814%, 92.941284%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.339844" stop-color="rgb(83.921814%, 92.941284%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.34375" stop-color="rgb(83.529663%, 92.941284%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.347656" stop-color="rgb(83.529663%, 92.549133%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.351562" stop-color="rgb(83.137512%, 92.549133%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.355469" stop-color="rgb(82.745361%, 92.549133%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.359375" stop-color="rgb(82.35321%, 92.156982%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.363281" stop-color="rgb(81.96106%, 92.156982%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.367188" stop-color="rgb(81.96106%, 92.156982%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.371094" stop-color="rgb(81.568909%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.375" stop-color="rgb(81.176758%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.378906" stop-color="rgb(81.176758%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.382812" stop-color="rgb(80.784607%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.386719" stop-color="rgb(80.784607%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.390625" stop-color="rgb(80.392456%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.394531" stop-color="rgb(80.000305%, 91.764832%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.398438" stop-color="rgb(80.000305%, 91.372681%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.402344" stop-color="rgb(79.608154%, 91.372681%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.40625" stop-color="rgb(79.608154%, 91.372681%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.410156" stop-color="rgb(79.216003%, 90.98053%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.414062" stop-color="rgb(78.823853%, 90.98053%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.417969" stop-color="rgb(78.431702%, 90.98053%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.421875" stop-color="rgb(78.431702%, 90.98053%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.425781" stop-color="rgb(78.039551%, 90.588379%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.429688" stop-color="rgb(77.6474%, 90.588379%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.433594" stop-color="rgb(77.255249%, 90.588379%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.4375" stop-color="rgb(77.255249%, 90.196228%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.441406" stop-color="rgb(76.863098%, 90.196228%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.445312" stop-color="rgb(76.470947%, 90.196228%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.449219" stop-color="rgb(76.470947%, 89.804077%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.453125" stop-color="rgb(76.078796%, 89.804077%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.457031" stop-color="rgb(75.686646%, 89.804077%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.460938" stop-color="rgb(75.686646%, 89.804077%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.464844" stop-color="rgb(75.294495%, 89.411926%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.46875" stop-color="rgb(74.902344%, 89.411926%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.472656" stop-color="rgb(74.510193%, 89.411926%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.476563" stop-color="rgb(74.510193%, 89.019775%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.480469" stop-color="rgb(74.118042%, 89.019775%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.484375" stop-color="rgb(73.725891%, 89.019775%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.488281" stop-color="rgb(73.33374%, 88.627625%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.492187" stop-color="rgb(72.941589%, 88.627625%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.496094" stop-color="rgb(72.941589%, 88.627625%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.5" stop-color="rgb(72.549438%, 88.235474%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.503906" stop-color="rgb(72.157288%, 88.235474%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.507812" stop-color="rgb(72.157288%, 88.235474%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.511719" stop-color="rgb(71.765137%, 88.235474%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.515625" stop-color="rgb(71.765137%, 87.843323%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.519531" stop-color="rgb(71.372986%, 87.843323%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.523437" stop-color="rgb(70.980835%, 87.843323%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.527344" stop-color="rgb(70.588684%, 87.451172%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.53125" stop-color="rgb(70.196533%, 87.451172%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.535156" stop-color="rgb(70.196533%, 87.451172%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.539062" stop-color="rgb(69.804382%, 87.059021%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.542969" stop-color="rgb(69.412231%, 87.059021%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.546875" stop-color="rgb(69.412231%, 87.059021%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.550781" stop-color="rgb(69.020081%, 87.059021%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.554687" stop-color="rgb(68.62793%, 86.66687%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.558594" stop-color="rgb(68.235779%, 86.66687%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.5625" stop-color="rgb(67.843628%, 86.66687%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.566406" stop-color="rgb(67.843628%, 86.66687%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.570312" stop-color="rgb(67.451477%, 86.66687%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.574219" stop-color="rgb(67.059326%, 86.66687%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.578125" stop-color="rgb(66.667175%, 86.274719%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.582031" stop-color="rgb(66.275024%, 86.274719%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.585937" stop-color="rgb(66.275024%, 86.274719%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.589844" stop-color="rgb(65.882874%, 86.274719%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.59375" stop-color="rgb(65.490723%, 85.882568%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.597656" stop-color="rgb(65.490723%, 85.882568%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.601562" stop-color="rgb(65.098572%, 85.882568%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.605469" stop-color="rgb(64.706421%, 85.490417%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.609375" stop-color="rgb(64.31427%, 85.490417%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.613281" stop-color="rgb(63.922119%, 85.490417%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.617188" stop-color="rgb(63.922119%, 85.098267%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.621094" stop-color="rgb(63.529968%, 85.098267%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.625" stop-color="rgb(63.137817%, 85.098267%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.628906" stop-color="rgb(63.137817%, 85.098267%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.632812" stop-color="rgb(62.745667%, 84.706116%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.636719" stop-color="rgb(62.353516%, 84.706116%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.640625" stop-color="rgb(61.961365%, 84.706116%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.644531" stop-color="rgb(61.961365%, 84.313965%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.648438" stop-color="rgb(61.569214%, 84.313965%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.652344" stop-color="rgb(61.177063%, 84.313965%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.65625" stop-color="rgb(60.784912%, 83.921814%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.660156" stop-color="rgb(60.392761%, 83.921814%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.664063" stop-color="rgb(60.392761%, 83.921814%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.667969" stop-color="rgb(60.00061%, 83.529663%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.671875" stop-color="rgb(59.608459%, 83.529663%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.675781" stop-color="rgb(59.608459%, 83.529663%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.679688" stop-color="rgb(59.216309%, 83.529663%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.683594" stop-color="rgb(58.824158%, 83.137512%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.6875" stop-color="rgb(58.432007%, 83.137512%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.691406" stop-color="rgb(58.039856%, 83.137512%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.695313" stop-color="rgb(58.039856%, 83.137512%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.699219" stop-color="rgb(57.647705%, 83.137512%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.703125" stop-color="rgb(57.255554%, 83.137512%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.707031" stop-color="rgb(56.863403%, 82.745361%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.710938" stop-color="rgb(56.471252%, 82.745361%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.714844" stop-color="rgb(56.471252%, 82.745361%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.71875" stop-color="rgb(56.079102%, 82.745361%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.722656" stop-color="rgb(55.686951%, 82.35321%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.726563" stop-color="rgb(55.686951%, 82.35321%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.730469" stop-color="rgb(55.2948%, 82.35321%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.734375" stop-color="rgb(54.902649%, 81.96106%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.738281" stop-color="rgb(54.510498%, 81.96106%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.742188" stop-color="rgb(54.118347%, 81.96106%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.746094" stop-color="rgb(54.118347%, 81.568909%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.75" stop-color="rgb(53.726196%, 81.568909%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.753906" stop-color="rgb(53.334045%, 81.568909%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.757812" stop-color="rgb(53.334045%, 81.568909%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.761719" stop-color="rgb(52.941895%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.765625" stop-color="rgb(52.549744%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.769531" stop-color="rgb(52.157593%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.773437" stop-color="rgb(52.157593%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.777344" stop-color="rgb(51.765442%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.78125" stop-color="rgb(51.373291%, 81.176758%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.785156" stop-color="rgb(50.98114%, 80.784607%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.789062" stop-color="rgb(50.588989%, 80.784607%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.792969" stop-color="rgb(50.588989%, 80.784607%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.796875" stop-color="rgb(50.196838%, 80.392456%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.800781" stop-color="rgb(49.803162%, 80.392456%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.804687" stop-color="rgb(49.803162%, 80.392456%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.808594" stop-color="rgb(49.411011%, 80.392456%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.8125" stop-color="rgb(49.01886%, 80.000305%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.816406" stop-color="rgb(48.626709%, 80.000305%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.820312" stop-color="rgb(48.234558%, 80.000305%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.824219" stop-color="rgb(47.842407%, 80.000305%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.828125" stop-color="rgb(47.450256%, 80.000305%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.832031" stop-color="rgb(47.450256%, 80.000305%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.835937" stop-color="rgb(47.058105%, 79.608154%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.839844" stop-color="rgb(46.665955%, 79.608154%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.84375" stop-color="rgb(46.665955%, 79.608154%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.847656" stop-color="rgb(46.273804%, 79.608154%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.851562" stop-color="rgb(45.881653%, 79.216003%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.855469" stop-color="rgb(45.489502%, 79.216003%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.859375" stop-color="rgb(45.097351%, 79.216003%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.863281" stop-color="rgb(45.097351%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.867188" stop-color="rgb(44.7052%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.871094" stop-color="rgb(44.313049%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.875" stop-color="rgb(43.920898%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.878906" stop-color="rgb(43.528748%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.882812" stop-color="rgb(43.528748%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.886719" stop-color="rgb(43.136597%, 78.823853%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.890625" stop-color="rgb(42.744446%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.894531" stop-color="rgb(42.744446%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.898438" stop-color="rgb(42.352295%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.902344" stop-color="rgb(42.352295%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.90625" stop-color="rgb(41.960144%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.9375" stop-color="rgb(41.960144%, 78.431702%, 90.98053%)" stop-opacity="1"/>
<stop offset="1" stop-color="rgb(41.960144%, 78.431702%, 90.98053%)" stop-opacity="1"/>
</linearGradient>
<clipPath id="clip-4">
<path clip-rule="nonzero" d="M 42 3 L 80 3 L 80 81 L 42 81 Z M 42 3 "/>
</clipPath>
<clipPath id="clip-5">
<path clip-rule="nonzero" d="M 42.34375 22.371094 L 42.34375 62.570312 C 42.34375 72.71875 50.570312 80.949219 60.722656 80.949219 C 70.871094 80.949219 79.097656 72.71875 79.097656 62.570312 L 79.097656 22.371094 C 79.097656 12.222656 70.871094 3.996094 60.722656 3.996094 C 50.570312 3.996094 42.34375 12.222656 42.34375 22.371094 "/>
</clipPath>
<linearGradient id="linear-pattern-2" gradientUnits="userSpaceOnUse" x1="0.00000321492" y1="0" x2="0.999994" y2="0" gradientTransform="matrix(0, -76.95372, 76.95372, 0, 60.721073, 80.947947)">
<stop offset="0" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0078125" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.015625" stop-color="rgb(99.607849%, 99.607849%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.0234375" stop-color="rgb(99.607849%, 99.215698%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.03125" stop-color="rgb(99.215698%, 98.823547%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.0390625" stop-color="rgb(98.823547%, 98.431396%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.046875" stop-color="rgb(98.431396%, 98.039246%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.0546875" stop-color="rgb(98.431396%, 97.647095%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.0625" stop-color="rgb(98.039246%, 97.254944%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.0703125" stop-color="rgb(97.647095%, 96.862793%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.078125" stop-color="rgb(97.254944%, 96.470642%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.0859375" stop-color="rgb(97.254944%, 96.078491%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.09375" stop-color="rgb(96.862793%, 95.68634%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.101562" stop-color="rgb(96.470642%, 95.294189%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.109375" stop-color="rgb(96.078491%, 94.902039%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.117188" stop-color="rgb(96.078491%, 94.509888%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.125" stop-color="rgb(95.68634%, 94.117737%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.132812" stop-color="rgb(95.294189%, 93.725586%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.140625" stop-color="rgb(94.902039%, 93.333435%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.148438" stop-color="rgb(94.902039%, 92.941284%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.15625" stop-color="rgb(94.509888%, 92.549133%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.164062" stop-color="rgb(94.117737%, 92.156982%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.171875" stop-color="rgb(93.725586%, 91.764832%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.179688" stop-color="rgb(93.725586%, 91.372681%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.1875" stop-color="rgb(93.333435%, 90.98053%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.195312" stop-color="rgb(92.941284%, 90.588379%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.203125" stop-color="rgb(92.549133%, 90.196228%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.210937" stop-color="rgb(92.549133%, 89.804077%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.21875" stop-color="rgb(92.156982%, 89.411926%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.226562" stop-color="rgb(91.764832%, 89.019775%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.234375" stop-color="rgb(91.372681%, 88.627625%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.242187" stop-color="rgb(91.372681%, 88.235474%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.25" stop-color="rgb(90.98053%, 87.843323%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.257812" stop-color="rgb(90.98053%, 87.451172%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.265625" stop-color="rgb(90.588379%, 87.451172%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.273438" stop-color="rgb(90.196228%, 87.059021%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.28125" stop-color="rgb(90.196228%, 86.66687%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.289062" stop-color="rgb(89.804077%, 86.274719%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.296875" stop-color="rgb(89.411926%, 85.882568%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.304687" stop-color="rgb(89.019775%, 85.490417%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.3125" stop-color="rgb(89.019775%, 85.098267%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.320312" stop-color="rgb(88.627625%, 84.706116%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.328125" stop-color="rgb(88.627625%, 84.313965%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.335937" stop-color="rgb(88.235474%, 83.921814%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.34375" stop-color="rgb(87.843323%, 83.529663%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.351562" stop-color="rgb(87.451172%, 83.137512%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.359375" stop-color="rgb(87.451172%, 82.745361%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.367188" stop-color="rgb(87.059021%, 82.35321%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.375" stop-color="rgb(87.059021%, 81.96106%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.382812" stop-color="rgb(86.66687%, 81.568909%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.390625" stop-color="rgb(86.274719%, 81.176758%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.398437" stop-color="rgb(85.882568%, 80.784607%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.40625" stop-color="rgb(85.882568%, 80.784607%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.414062" stop-color="rgb(85.490417%, 80.392456%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.421875" stop-color="rgb(85.490417%, 80.000305%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.429688" stop-color="rgb(85.098267%, 79.608154%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.4375" stop-color="rgb(84.706116%, 79.216003%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.445312" stop-color="rgb(84.313965%, 78.823853%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.453125" stop-color="rgb(84.313965%, 78.431702%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.460938" stop-color="rgb(83.921814%, 78.039551%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.46875" stop-color="rgb(83.921814%, 77.6474%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.476562" stop-color="rgb(83.529663%, 77.255249%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.484375" stop-color="rgb(83.529663%, 76.863098%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.492188" stop-color="rgb(83.137512%, 76.470947%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.5" stop-color="rgb(82.745361%, 76.470947%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.507812" stop-color="rgb(82.745361%, 76.078796%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.515625" stop-color="rgb(82.35321%, 76.078796%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.523438" stop-color="rgb(81.96106%, 75.686646%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.53125" stop-color="rgb(81.96106%, 75.294495%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.539062" stop-color="rgb(81.568909%, 74.902344%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.546875" stop-color="rgb(81.568909%, 74.510193%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.554687" stop-color="rgb(81.176758%, 74.118042%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.5625" stop-color="rgb(81.176758%, 73.725891%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.570313" stop-color="rgb(80.784607%, 73.33374%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.578125" stop-color="rgb(80.784607%, 73.33374%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.585938" stop-color="rgb(80.392456%, 72.941589%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.59375" stop-color="rgb(80.000305%, 72.549438%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.601562" stop-color="rgb(79.608154%, 72.157288%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.609375" stop-color="rgb(79.608154%, 71.765137%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.617188" stop-color="rgb(79.216003%, 71.372986%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.625" stop-color="rgb(79.216003%, 70.980835%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.632812" stop-color="rgb(78.823853%, 70.588684%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.640625" stop-color="rgb(78.823853%, 70.588684%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.648437" stop-color="rgb(78.431702%, 70.196533%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.65625" stop-color="rgb(78.431702%, 69.804382%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.664063" stop-color="rgb(78.039551%, 69.412231%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.671875" stop-color="rgb(78.039551%, 69.020081%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.679688" stop-color="rgb(77.6474%, 68.62793%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.6875" stop-color="rgb(77.255249%, 68.62793%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.695312" stop-color="rgb(76.863098%, 68.235779%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.703125" stop-color="rgb(76.863098%, 67.843628%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.710938" stop-color="rgb(76.470947%, 67.451477%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.71875" stop-color="rgb(76.470947%, 67.059326%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.726562" stop-color="rgb(76.078796%, 66.667175%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.734375" stop-color="rgb(76.078796%, 66.667175%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.742188" stop-color="rgb(75.686646%, 66.275024%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.75" stop-color="rgb(75.686646%, 65.882874%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.757813" stop-color="rgb(75.686646%, 65.490723%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.765625" stop-color="rgb(75.294495%, 65.098572%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.773438" stop-color="rgb(75.294495%, 65.098572%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.78125" stop-color="rgb(74.902344%, 64.706421%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.789062" stop-color="rgb(74.902344%, 64.31427%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.796875" stop-color="rgb(74.510193%, 63.922119%, 80.784607%)" stop-opacity="1"/>
<stop offset="0.804688" stop-color="rgb(74.510193%, 63.922119%, 80.784607%)" stop-opacity="1"/>
<stop offset="0.8125" stop-color="rgb(74.118042%, 63.529968%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.820312" stop-color="rgb(74.118042%, 63.137817%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.828125" stop-color="rgb(73.725891%, 62.745667%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.835938" stop-color="rgb(73.33374%, 62.353516%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.84375" stop-color="rgb(72.941589%, 61.961365%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.851563" stop-color="rgb(72.941589%, 61.961365%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.859375" stop-color="rgb(72.549438%, 61.569214%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.867188" stop-color="rgb(72.549438%, 61.177063%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.875" stop-color="rgb(72.157288%, 60.784912%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.890625" stop-color="rgb(71.765137%, 60.392761%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.898437" stop-color="rgb(71.765137%, 60.392761%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.90625" stop-color="rgb(71.765137%, 60.00061%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.914063" stop-color="rgb(71.765137%, 59.608459%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.921875" stop-color="rgb(71.372986%, 59.216309%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.9375" stop-color="rgb(70.980835%, 58.824158%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.945312" stop-color="rgb(70.980835%, 58.824158%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.953125" stop-color="rgb(70.588684%, 58.432007%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.960938" stop-color="rgb(70.588684%, 58.039856%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.96875" stop-color="rgb(70.196533%, 57.647705%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.984375" stop-color="rgb(69.804382%, 57.255554%, 76.863098%)" stop-opacity="1"/>
<stop offset="1" stop-color="rgb(69.804382%, 56.863403%, 76.470947%)" stop-opacity="1"/>
</linearGradient>
<clipPath id="clip-6">
<path clip-rule="nonzero" d="M 42 15 L 108 15 L 108 81 L 42 81 Z M 42 15 "/>
</clipPath>
<clipPath id="clip-7">
<path clip-rule="nonzero" d="M 76.152344 21.152344 L 47.726562 49.574219 C 40.550781 56.75 40.550781 68.386719 47.726562 75.566406 C 51.316406 79.15625 56.019531 80.949219 60.722656 80.949219 C 65.425781 80.949219 70.128906 79.152344 73.714844 75.566406 L 102.140625 47.140625 C 109.316406 39.964844 109.316406 28.328125 102.140625 21.152344 C 98.550781 17.5625 93.847656 15.769531 89.144531 15.769531 C 84.441406 15.769531 79.738281 17.5625 76.152344 21.152344 "/>
</clipPath>
<linearGradient id="linear-pattern-3" gradientUnits="userSpaceOnUse" x1="-0.115406" y1="0" x2="1.115401" y2="0" gradientTransform="matrix(54.414692, -54.414692, 54.414692, 54.414692, 47.726387, 75.56548)">
<stop offset="0" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0625" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.09375" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.101562" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.109375" stop-color="rgb(100%, 99.607849%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.113281" stop-color="rgb(100%, 99.215698%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.117188" stop-color="rgb(100%, 98.823547%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.125" stop-color="rgb(100%, 98.823547%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.132812" stop-color="rgb(100%, 98.431396%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.140625" stop-color="rgb(100%, 98.431396%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.148438" stop-color="rgb(99.607849%, 98.039246%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.152344" stop-color="rgb(99.607849%, 97.647095%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.15625" stop-color="rgb(99.607849%, 97.254944%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.164062" stop-color="rgb(99.607849%, 97.254944%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.171875" stop-color="rgb(99.607849%, 96.862793%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.175781" stop-color="rgb(99.607849%, 96.862793%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.179687" stop-color="rgb(99.607849%, 96.470642%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.1875" stop-color="rgb(99.607849%, 96.470642%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.191406" stop-color="rgb(99.607849%, 96.078491%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.195312" stop-color="rgb(99.607849%, 95.68634%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.203125" stop-color="rgb(99.607849%, 95.68634%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.210938" stop-color="rgb(99.607849%, 95.294189%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.214844" stop-color="rgb(99.607849%, 94.902039%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.21875" stop-color="rgb(99.607849%, 94.902039%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.226562" stop-color="rgb(99.607849%, 94.509888%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.234375" stop-color="rgb(99.215698%, 94.117737%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.242187" stop-color="rgb(99.215698%, 94.117737%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.25" stop-color="rgb(99.215698%, 93.725586%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.253906" stop-color="rgb(99.215698%, 93.333435%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.257812" stop-color="rgb(99.215698%, 93.333435%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.265625" stop-color="rgb(99.215698%, 92.941284%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.273437" stop-color="rgb(99.215698%, 92.549133%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.28125" stop-color="rgb(99.215698%, 92.549133%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.289062" stop-color="rgb(99.215698%, 92.156982%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.292969" stop-color="rgb(99.215698%, 91.764832%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.296875" stop-color="rgb(99.215698%, 91.372681%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.304687" stop-color="rgb(99.215698%, 91.372681%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.3125" stop-color="rgb(98.823547%, 90.98053%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.316406" stop-color="rgb(98.823547%, 90.588379%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.320312" stop-color="rgb(98.823547%, 90.588379%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.324219" stop-color="rgb(98.823547%, 90.196228%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.328125" stop-color="rgb(98.823547%, 90.196228%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.335937" stop-color="rgb(98.823547%, 90.196228%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.34375" stop-color="rgb(98.823547%, 89.804077%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.351562" stop-color="rgb(98.823547%, 89.411926%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.355469" stop-color="rgb(98.823547%, 89.019775%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.359375" stop-color="rgb(98.823547%, 89.019775%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.363281" stop-color="rgb(98.823547%, 88.627625%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.367187" stop-color="rgb(98.823547%, 88.627625%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.375" stop-color="rgb(98.823547%, 88.235474%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.378906" stop-color="rgb(98.823547%, 88.235474%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.382812" stop-color="rgb(98.823547%, 88.235474%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.386719" stop-color="rgb(98.431396%, 87.843323%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.390625" stop-color="rgb(98.431396%, 87.843323%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.394531" stop-color="rgb(98.431396%, 87.451172%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.398438" stop-color="rgb(98.431396%, 87.451172%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.40625" stop-color="rgb(98.431396%, 87.059021%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.414062" stop-color="rgb(98.431396%, 86.66687%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.421875" stop-color="rgb(98.431396%, 86.66687%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.429687" stop-color="rgb(98.431396%, 86.274719%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.433594" stop-color="rgb(98.431396%, 85.882568%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.4375" stop-color="rgb(98.431396%, 85.882568%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.445312" stop-color="rgb(98.431396%, 85.490417%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.453125" stop-color="rgb(98.039246%, 85.098267%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.457031" stop-color="rgb(98.039246%, 85.098267%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.460937" stop-color="rgb(98.039246%, 84.706116%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.464844" stop-color="rgb(98.039246%, 84.313965%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.46875" stop-color="rgb(98.039246%, 84.313965%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.476562" stop-color="rgb(98.039246%, 84.313965%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.484375" stop-color="rgb(98.039246%, 83.921814%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.488281" stop-color="rgb(98.039246%, 83.529663%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.492188" stop-color="rgb(98.039246%, 83.529663%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.496094" stop-color="rgb(98.039246%, 83.529663%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.5" stop-color="rgb(98.039246%, 83.137512%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.503906" stop-color="rgb(98.039246%, 82.745361%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.507812" stop-color="rgb(98.039246%, 82.745361%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.515625" stop-color="rgb(98.039246%, 82.745361%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.523438" stop-color="rgb(98.039246%, 82.35321%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.53125" stop-color="rgb(97.647095%, 81.96106%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.535156" stop-color="rgb(97.647095%, 81.96106%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.539063" stop-color="rgb(97.647095%, 81.568909%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.542969" stop-color="rgb(97.647095%, 81.176758%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.546875" stop-color="rgb(97.647095%, 81.176758%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.554688" stop-color="rgb(97.647095%, 81.176758%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.5625" stop-color="rgb(97.647095%, 80.784607%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.570312" stop-color="rgb(97.647095%, 80.392456%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.574219" stop-color="rgb(97.647095%, 80.000305%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.578125" stop-color="rgb(97.647095%, 80.000305%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.582031" stop-color="rgb(97.647095%, 79.608154%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.585938" stop-color="rgb(97.647095%, 79.608154%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.59375" stop-color="rgb(97.647095%, 79.608154%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.601562" stop-color="rgb(97.254944%, 79.216003%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.605469" stop-color="rgb(97.254944%, 78.823853%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.609375" stop-color="rgb(97.254944%, 78.431702%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.617187" stop-color="rgb(97.254944%, 78.431702%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.625" stop-color="rgb(97.254944%, 78.039551%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.632813" stop-color="rgb(97.254944%, 78.039551%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.636719" stop-color="rgb(97.254944%, 77.6474%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.640625" stop-color="rgb(97.254944%, 77.255249%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.644531" stop-color="rgb(97.254944%, 77.255249%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.648438" stop-color="rgb(97.254944%, 76.863098%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.65625" stop-color="rgb(97.254944%, 76.863098%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.664062" stop-color="rgb(96.862793%, 76.470947%, 80.784607%)" stop-opacity="1"/>
<stop offset="0.671875" stop-color="rgb(96.862793%, 76.078796%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.675781" stop-color="rgb(96.862793%, 76.078796%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.679688" stop-color="rgb(96.862793%, 75.686646%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.683594" stop-color="rgb(96.862793%, 75.686646%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.6875" stop-color="rgb(96.862793%, 75.294495%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.695312" stop-color="rgb(96.862793%, 75.294495%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.703125" stop-color="rgb(96.862793%, 74.902344%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.710937" stop-color="rgb(96.862793%, 74.510193%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.71875" stop-color="rgb(96.862793%, 74.510193%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.726562" stop-color="rgb(96.862793%, 74.118042%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.730469" stop-color="rgb(96.862793%, 73.725891%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.734375" stop-color="rgb(96.470642%, 73.725891%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.742188" stop-color="rgb(96.470642%, 73.33374%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.75" stop-color="rgb(96.470642%, 72.941589%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.757812" stop-color="rgb(96.470642%, 72.941589%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.765625" stop-color="rgb(96.470642%, 72.549438%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.769531" stop-color="rgb(96.470642%, 72.157288%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.773438" stop-color="rgb(96.470642%, 72.157288%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.78125" stop-color="rgb(96.470642%, 71.765137%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.789063" stop-color="rgb(96.470642%, 71.372986%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.796875" stop-color="rgb(96.470642%, 71.372986%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.804688" stop-color="rgb(96.470642%, 70.980835%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.8125" stop-color="rgb(96.470642%, 70.980835%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.820312" stop-color="rgb(96.078491%, 70.588684%, 76.078796%)" stop-opacity="1"/>
<stop offset="0.828125" stop-color="rgb(96.078491%, 70.196533%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.832031" stop-color="rgb(96.078491%, 69.804382%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.835938" stop-color="rgb(96.078491%, 69.804382%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.839844" stop-color="rgb(96.078491%, 69.412231%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.84375" stop-color="rgb(96.078491%, 69.412231%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.851562" stop-color="rgb(96.078491%, 69.412231%, 75.294495%)" stop-opacity="1"/>
<stop offset="0.859375" stop-color="rgb(96.078491%, 69.020081%, 74.902344%)" stop-opacity="1"/>
<stop offset="0.867187" stop-color="rgb(96.078491%, 68.62793%, 74.510193%)" stop-opacity="1"/>
<stop offset="0.875" stop-color="rgb(96.078491%, 68.62793%, 74.510193%)" stop-opacity="1"/>
<stop offset="0.882813" stop-color="rgb(96.078491%, 68.235779%, 74.118042%)" stop-opacity="1"/>
<stop offset="0.890625" stop-color="rgb(96.078491%, 68.235779%, 74.118042%)" stop-opacity="1"/>
<stop offset="0.898438" stop-color="rgb(96.078491%, 67.843628%, 74.118042%)" stop-opacity="1"/>
<stop offset="0.90625" stop-color="rgb(95.68634%, 67.451477%, 73.725891%)" stop-opacity="1"/>
<stop offset="0.9375" stop-color="rgb(95.68634%, 67.451477%, 73.725891%)" stop-opacity="1"/>
<stop offset="1" stop-color="rgb(95.68634%, 67.451477%, 73.725891%)" stop-opacity="1"/>
</linearGradient>
<clipPath id="clip-8">
<path clip-rule="nonzero" d="M 42 44 L 120 44 L 120 81 L 42 81 Z M 42 44 "/>
</clipPath>
<clipPath id="clip-9">
<path clip-rule="nonzero" d="M 60.722656 44.191406 C 50.570312 44.191406 42.34375 52.421875 42.34375 62.570312 C 42.34375 72.71875 50.570312 80.949219 60.722656 80.949219 L 100.917969 80.949219 C 111.066406 80.949219 119.296875 72.71875 119.296875 62.570312 C 119.296875 52.421875 111.066406 44.191406 100.917969 44.191406 Z M 60.722656 44.191406 "/>
</clipPath>
<linearGradient id="linear-pattern-4" gradientUnits="userSpaceOnUse" x1="-0.00000221172" y1="0" x2="1.000001" y2="0" gradientTransform="matrix(76.95372, 0, 0, 76.95372, 42.34317, 62.570047)">
<stop offset="0" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.0078125" stop-color="rgb(100%, 100%, 100%)" stop-opacity="1"/>
<stop offset="0.015625" stop-color="rgb(99.607849%, 99.607849%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.0234375" stop-color="rgb(99.215698%, 99.607849%, 99.607849%)" stop-opacity="1"/>
<stop offset="0.03125" stop-color="rgb(98.823547%, 99.215698%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.0390625" stop-color="rgb(98.431396%, 99.215698%, 99.215698%)" stop-opacity="1"/>
<stop offset="0.046875" stop-color="rgb(98.039246%, 98.823547%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.0546875" stop-color="rgb(97.647095%, 98.823547%, 98.823547%)" stop-opacity="1"/>
<stop offset="0.0625" stop-color="rgb(97.254944%, 98.431396%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.0703125" stop-color="rgb(96.862793%, 98.431396%, 98.431396%)" stop-opacity="1"/>
<stop offset="0.078125" stop-color="rgb(96.470642%, 98.039246%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.0859375" stop-color="rgb(96.078491%, 98.039246%, 98.039246%)" stop-opacity="1"/>
<stop offset="0.09375" stop-color="rgb(95.68634%, 98.039246%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.101562" stop-color="rgb(95.68634%, 98.039246%, 97.647095%)" stop-opacity="1"/>
<stop offset="0.109375" stop-color="rgb(95.294189%, 97.647095%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.117187" stop-color="rgb(94.902039%, 97.647095%, 97.254944%)" stop-opacity="1"/>
<stop offset="0.125" stop-color="rgb(94.509888%, 97.254944%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.132812" stop-color="rgb(94.117737%, 97.254944%, 96.862793%)" stop-opacity="1"/>
<stop offset="0.140625" stop-color="rgb(93.725586%, 96.862793%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.148438" stop-color="rgb(93.333435%, 96.862793%, 96.470642%)" stop-opacity="1"/>
<stop offset="0.15625" stop-color="rgb(92.941284%, 96.470642%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.164062" stop-color="rgb(92.549133%, 96.470642%, 96.078491%)" stop-opacity="1"/>
<stop offset="0.171875" stop-color="rgb(92.156982%, 96.078491%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.179688" stop-color="rgb(91.764832%, 96.078491%, 95.68634%)" stop-opacity="1"/>
<stop offset="0.1875" stop-color="rgb(91.372681%, 95.68634%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.195312" stop-color="rgb(90.98053%, 95.68634%, 95.294189%)" stop-opacity="1"/>
<stop offset="0.203125" stop-color="rgb(90.588379%, 95.294189%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.210938" stop-color="rgb(90.196228%, 95.294189%, 94.902039%)" stop-opacity="1"/>
<stop offset="0.21875" stop-color="rgb(89.804077%, 94.902039%, 94.509888%)" stop-opacity="1"/>
<stop offset="0.226562" stop-color="rgb(89.411926%, 94.902039%, 94.117737%)" stop-opacity="1"/>
<stop offset="0.234375" stop-color="rgb(89.019775%, 94.509888%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.242188" stop-color="rgb(88.627625%, 94.509888%, 93.725586%)" stop-opacity="1"/>
<stop offset="0.25" stop-color="rgb(88.235474%, 94.117737%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.257812" stop-color="rgb(87.843323%, 94.117737%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.265625" stop-color="rgb(87.451172%, 94.117737%, 93.333435%)" stop-opacity="1"/>
<stop offset="0.273438" stop-color="rgb(87.059021%, 93.725586%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.28125" stop-color="rgb(86.66687%, 93.725586%, 92.941284%)" stop-opacity="1"/>
<stop offset="0.289062" stop-color="rgb(86.274719%, 93.333435%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.296875" stop-color="rgb(85.882568%, 93.333435%, 92.549133%)" stop-opacity="1"/>
<stop offset="0.304687" stop-color="rgb(85.490417%, 92.941284%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.3125" stop-color="rgb(85.098267%, 92.941284%, 92.156982%)" stop-opacity="1"/>
<stop offset="0.320312" stop-color="rgb(84.706116%, 92.549133%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.328125" stop-color="rgb(84.313965%, 92.549133%, 91.764832%)" stop-opacity="1"/>
<stop offset="0.335937" stop-color="rgb(83.921814%, 92.156982%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.34375" stop-color="rgb(83.529663%, 92.156982%, 91.372681%)" stop-opacity="1"/>
<stop offset="0.351562" stop-color="rgb(83.137512%, 92.156982%, 90.98053%)" stop-opacity="1"/>
<stop offset="0.359375" stop-color="rgb(82.745361%, 92.156982%, 90.588379%)" stop-opacity="1"/>
<stop offset="0.367187" stop-color="rgb(82.35321%, 91.764832%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.375" stop-color="rgb(81.96106%, 91.764832%, 90.196228%)" stop-opacity="1"/>
<stop offset="0.382812" stop-color="rgb(81.568909%, 91.372681%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.390625" stop-color="rgb(81.176758%, 91.372681%, 89.804077%)" stop-opacity="1"/>
<stop offset="0.398437" stop-color="rgb(80.784607%, 90.98053%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.40625" stop-color="rgb(80.392456%, 90.98053%, 89.411926%)" stop-opacity="1"/>
<stop offset="0.414062" stop-color="rgb(80.000305%, 90.588379%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.421875" stop-color="rgb(79.608154%, 90.588379%, 89.019775%)" stop-opacity="1"/>
<stop offset="0.429687" stop-color="rgb(79.216003%, 90.196228%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.4375" stop-color="rgb(78.823853%, 90.196228%, 88.627625%)" stop-opacity="1"/>
<stop offset="0.445312" stop-color="rgb(78.431702%, 89.804077%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.453125" stop-color="rgb(78.039551%, 89.804077%, 88.235474%)" stop-opacity="1"/>
<stop offset="0.460937" stop-color="rgb(77.6474%, 89.411926%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.46875" stop-color="rgb(77.255249%, 89.411926%, 87.843323%)" stop-opacity="1"/>
<stop offset="0.476562" stop-color="rgb(76.863098%, 89.019775%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.484375" stop-color="rgb(76.470947%, 89.019775%, 87.451172%)" stop-opacity="1"/>
<stop offset="0.492187" stop-color="rgb(76.078796%, 88.627625%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.5" stop-color="rgb(75.686646%, 88.627625%, 87.059021%)" stop-opacity="1"/>
<stop offset="0.507812" stop-color="rgb(75.686646%, 88.627625%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.515625" stop-color="rgb(75.294495%, 88.627625%, 86.66687%)" stop-opacity="1"/>
<stop offset="0.523437" stop-color="rgb(74.902344%, 88.235474%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.527344" stop-color="rgb(74.118042%, 88.235474%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.53125" stop-color="rgb(74.118042%, 88.235474%, 86.274719%)" stop-opacity="1"/>
<stop offset="0.535156" stop-color="rgb(73.725891%, 87.843323%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.539062" stop-color="rgb(73.33374%, 87.843323%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.542969" stop-color="rgb(73.33374%, 87.843323%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.546875" stop-color="rgb(72.941589%, 87.843323%, 85.882568%)" stop-opacity="1"/>
<stop offset="0.554687" stop-color="rgb(72.941589%, 87.451172%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.5625" stop-color="rgb(72.549438%, 87.451172%, 85.490417%)" stop-opacity="1"/>
<stop offset="0.570312" stop-color="rgb(72.157288%, 87.059021%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.578125" stop-color="rgb(71.765137%, 87.059021%, 85.098267%)" stop-opacity="1"/>
<stop offset="0.585937" stop-color="rgb(71.372986%, 86.66687%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.59375" stop-color="rgb(70.980835%, 86.66687%, 84.706116%)" stop-opacity="1"/>
<stop offset="0.601562" stop-color="rgb(70.588684%, 86.274719%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.609375" stop-color="rgb(70.196533%, 86.274719%, 84.313965%)" stop-opacity="1"/>
<stop offset="0.617187" stop-color="rgb(69.804382%, 85.882568%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.625" stop-color="rgb(69.412231%, 85.882568%, 83.921814%)" stop-opacity="1"/>
<stop offset="0.632812" stop-color="rgb(69.020081%, 85.490417%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.636719" stop-color="rgb(68.62793%, 85.490417%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.640625" stop-color="rgb(68.235779%, 85.490417%, 83.529663%)" stop-opacity="1"/>
<stop offset="0.644531" stop-color="rgb(67.843628%, 85.098267%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.648437" stop-color="rgb(67.451477%, 85.098267%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.652344" stop-color="rgb(67.451477%, 85.098267%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.65625" stop-color="rgb(67.059326%, 85.098267%, 83.137512%)" stop-opacity="1"/>
<stop offset="0.664062" stop-color="rgb(67.059326%, 84.706116%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.671875" stop-color="rgb(66.667175%, 84.706116%, 82.745361%)" stop-opacity="1"/>
<stop offset="0.679687" stop-color="rgb(66.275024%, 84.313965%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.6875" stop-color="rgb(65.882874%, 84.313965%, 82.35321%)" stop-opacity="1"/>
<stop offset="0.695312" stop-color="rgb(65.490723%, 84.313965%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.703125" stop-color="rgb(65.098572%, 84.313965%, 81.96106%)" stop-opacity="1"/>
<stop offset="0.710937" stop-color="rgb(64.706421%, 83.921814%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.71875" stop-color="rgb(64.31427%, 83.921814%, 81.568909%)" stop-opacity="1"/>
<stop offset="0.726562" stop-color="rgb(63.922119%, 83.529663%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.734375" stop-color="rgb(63.529968%, 83.529663%, 81.176758%)" stop-opacity="1"/>
<stop offset="0.742187" stop-color="rgb(63.137817%, 83.137512%, 80.784607%)" stop-opacity="1"/>
<stop offset="0.746094" stop-color="rgb(62.745667%, 83.137512%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.75" stop-color="rgb(62.353516%, 83.137512%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.753906" stop-color="rgb(62.353516%, 83.137512%, 80.392456%)" stop-opacity="1"/>
<stop offset="0.757812" stop-color="rgb(61.961365%, 82.745361%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.761719" stop-color="rgb(61.569214%, 82.745361%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.765625" stop-color="rgb(61.569214%, 82.745361%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.773437" stop-color="rgb(61.177063%, 82.745361%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.78125" stop-color="rgb(60.784912%, 82.35321%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.789062" stop-color="rgb(60.392761%, 82.35321%, 80.000305%)" stop-opacity="1"/>
<stop offset="0.796875" stop-color="rgb(60.00061%, 82.35321%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.804687" stop-color="rgb(59.608459%, 82.35321%, 79.608154%)" stop-opacity="1"/>
<stop offset="0.8125" stop-color="rgb(59.216309%, 81.96106%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.820312" stop-color="rgb(58.824158%, 81.96106%, 79.216003%)" stop-opacity="1"/>
<stop offset="0.828125" stop-color="rgb(58.432007%, 81.568909%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.835937" stop-color="rgb(58.039856%, 81.568909%, 78.823853%)" stop-opacity="1"/>
<stop offset="0.84375" stop-color="rgb(57.647705%, 81.176758%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.851562" stop-color="rgb(57.255554%, 81.176758%, 78.431702%)" stop-opacity="1"/>
<stop offset="0.859375" stop-color="rgb(56.863403%, 80.784607%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.867187" stop-color="rgb(56.471252%, 80.784607%, 78.039551%)" stop-opacity="1"/>
<stop offset="0.875" stop-color="rgb(56.079102%, 80.784607%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.882812" stop-color="rgb(55.686951%, 80.784607%, 77.6474%)" stop-opacity="1"/>
<stop offset="0.890625" stop-color="rgb(55.2948%, 80.392456%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.898437" stop-color="rgb(54.902649%, 80.392456%, 77.255249%)" stop-opacity="1"/>
<stop offset="0.90625" stop-color="rgb(54.510498%, 80.000305%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.914062" stop-color="rgb(54.118347%, 80.000305%, 76.863098%)" stop-opacity="1"/>
<stop offset="0.921875" stop-color="rgb(53.726196%, 79.608154%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.929687" stop-color="rgb(53.334045%, 79.608154%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.9375" stop-color="rgb(52.941895%, 79.608154%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.945312" stop-color="rgb(52.549744%, 79.608154%, 76.470947%)" stop-opacity="1"/>
<stop offset="0.953125" stop-color="rgb(52.157593%, 79.216003%, 76.078796%)" stop-opacity="1"/>
<stop offset="0.960937" stop-color="rgb(51.765442%, 79.216003%, 76.078796%)" stop-opacity="1"/>
<stop offset="0.96875" stop-color="rgb(51.373291%, 78.823853%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.976562" stop-color="rgb(51.373291%, 78.823853%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.984375" stop-color="rgb(50.98114%, 78.823853%, 75.686646%)" stop-opacity="1"/>
<stop offset="0.992187" stop-color="rgb(50.588989%, 78.823853%, 75.686646%)" stop-opacity="1"/>
<stop offset="1" stop-color="rgb(50.196838%, 78.431702%, 75.294495%)" stop-opacity="1"/>
</linearGradient>
</defs>
<g clip-path="url(#clip-0)">
<g clip-path="url(#clip-1)">
<path fill-rule="nonzero" fill="url(#linear-pattern-0)" d="M 79.097656 80.949219 L 79.097656 44.191406 L 2.144531 44.191406 L 2.144531 80.949219 Z M 79.097656 80.949219 "/>
</g>
</g>
<g clip-path="url(#clip-2)">
<g clip-path="url(#clip-3)">
<path fill-rule="nonzero" fill="url(#linear-pattern-1)" d="M 46.507812 115.332031 L 113.484375 48.359375 L 46.507812 -18.617188 L -20.464844 48.359375 Z M 46.507812 115.332031 "/>
</g>
</g>
<g clip-path="url(#clip-4)">
<g clip-path="url(#clip-5)">
<path fill-rule="nonzero" fill="url(#linear-pattern-2)" d="M 42.34375 80.949219 L 79.097656 80.949219 L 79.097656 3.996094 L 42.34375 3.996094 Z M 42.34375 80.949219 "/>
</g>
</g>
<g clip-path="url(#clip-6)">
<g clip-path="url(#clip-7)">
<path fill-rule="nonzero" fill="url(#linear-pattern-3)" d="M 7.960938 48.359375 L 74.933594 115.332031 L 141.90625 48.359375 L 74.933594 -18.617188 Z M 7.960938 48.359375 "/>
</g>
</g>
<g clip-path="url(#clip-8)">
<g clip-path="url(#clip-9)">
<path fill-rule="nonzero" fill="url(#linear-pattern-4)" d="M 42.34375 44.191406 L 42.34375 80.949219 L 119.296875 80.949219 L 119.296875 44.191406 Z M 42.34375 44.191406 "/>
</g>
</g>
<path fill-rule="nonzero" fill="rgb(100%, 100%, 100%)" fill-opacity="1" d="M 79.097656 62.570312 C 79.097656 72.71875 70.871094 80.949219 60.722656 80.949219 C 50.570312 80.949219 42.34375 72.71875 42.34375 62.570312 C 42.34375 52.421875 50.570312 44.191406 60.722656 44.191406 C 70.871094 44.191406 79.097656 52.421875 79.097656 62.570312 "/>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-0" x="133.1255" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-1" x="141.8111" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-2" x="158.2975" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-3" x="170.0435" y="39.8591"/>
<use xlink:href="#glyph-0-4" x="187.3475" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-5" x="198.5587" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-6" x="224.2543" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-7" x="241.4435" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-8" x="253.7943" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-9" x="261.5951" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-10" x="279.0391" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-11" x="295.5983" y="39.8591"/>
<use xlink:href="#glyph-0-12" x="312.1183" y="39.8591"/>
<use xlink:href="#glyph-0-11" x="316.5983" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-7" x="332.8551" y="39.8591"/>
<use xlink:href="#glyph-0-12" x="344.9791" y="39.8591"/>
<use xlink:href="#glyph-0-13" x="349.4591" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-14" x="362.3475" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-13" x="378.3775" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-7" x="391.1511" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-15" x="403.2219" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-5" x="419.8231" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-11" x="445.4655" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-13" x="462.0303" y="39.8591"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-16" x="133.1255" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-11" x="150.4547" y="66.8511"/>
<use xlink:href="#glyph-0-12" x="166.9747" y="66.8511"/>
<use xlink:href="#glyph-0-17" x="171.4547" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-3" x="185.8383" y="66.8511"/>
<use xlink:href="#glyph-0-5" x="203.1423" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-5" x="228.9331" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-10" x="254.6539" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-1" x="271.2971" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-8" x="288.0467" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-17" x="295.7887" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-6" x="310.2927" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-7" x="327.4847" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-8" x="339.8327" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-3" x="347.5747" y="66.8511"/>
<use xlink:href="#glyph-0-1" x="364.8787" y="66.8511"/>
<use xlink:href="#glyph-0-12" x="381.5107" y="66.8511"/>
<use xlink:href="#glyph-0-12" x="385.9907" y="66.8511"/>
<use xlink:href="#glyph-0-0" x="390.4707" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-18" x="399.0331" y="66.8511"/>
</g>
<g fill="rgb(100%, 100%, 100%)" fill-opacity="1">
<use xlink:href="#glyph-0-19" x="415.7099" y="66.8511"/>
</g>
<path fill-rule="nonzero" fill="rgb(86.66687%, 0%, 41.175842%)" fill-opacity="1" d="M 453.445312 65.542969 C 453.445312 66.425781 454.160156 67.140625 455.039062 67.140625 L 472.71875 67.140625 C 473.597656 67.140625 474.3125 66.425781 474.3125 65.542969 L 474.3125 47.867188 C 474.3125 46.984375 473.597656 46.273438 472.71875 46.273438 L 455.039062 46.273438 C 454.160156 46.273438 453.445312 46.984375 453.445312 47.867188 Z M 453.445312 65.542969 "/>
<path fill-rule="nonzero" fill="rgb(100%, 100%, 100%)" fill-opacity="1" d="M 465.027344 52.910156 L 462.621094 52.910156 C 462.5 54.304688 462.382812 55.492188 462.273438 56.386719 C 462.160156 57.277344 462.054688 57.957031 461.953125 58.597656 C 461.84375 59.242188 461.738281 59.824219 461.628906 60.351562 C 461.535156 60.765625 461.40625 61.085938 461.226562 61.316406 C 461.050781 61.550781 460.796875 61.710938 460.460938 61.800781 C 460.175781 61.867188 459.902344 61.816406 459.625 61.632812 C 459.351562 61.453125 459.191406 61.238281 459.128906 60.988281 C 459.089844 60.800781 459.078125 60.644531 459.101562 60.515625 C 459.117188 60.386719 459.15625 60.265625 459.214844 60.15625 C 459.269531 60.046875 459.332031 59.945312 459.40625 59.851562 C 459.46875 59.761719 459.542969 59.671875 459.617188 59.582031 C 459.644531 59.554688 459.761719 59.414062 459.984375 59.15625 C 460.203125 58.898438 460.363281 58.664062 460.476562 58.453125 C 460.585938 58.242188 460.828125 57.773438 460.949219 57.195312 C 461.070312 56.617188 461.320312 54.632812 461.316406 52.910156 L 460.300781 52.910156 C 460.015625 52.910156 459.734375 53.003906 459.472656 53.140625 C 459.21875 53.273438 458.992188 53.5 458.890625 53.632812 C 458.78125 53.765625 458.503906 54.210938 458.441406 54.296875 C 458.375 54.382812 458.242188 54.582031 458.144531 54.550781 C 458.035156 54.515625 458.058594 54.394531 458.074219 54.296875 C 458.09375 54.199219 458.292969 53.699219 458.441406 53.324219 C 458.589844 52.945312 458.792969 52.578125 459.046875 52.226562 C 459.246094 51.925781 459.519531 51.710938 459.859375 51.496094 C 460.203125 51.273438 460.597656 51.164062 461.050781 51.164062 L 468.429688 51.164062 C 468.5625 51.164062 469.253906 51.21875 469.253906 52.03125 C 469.253906 52.839844 468.515625 52.910156 468.429688 52.910156 L 466.335938 52.910156 C 466.160156 54.570312 466.074219 56.28125 466.074219 57.964844 C 466.074219 58.269531 466.125 58.570312 466.230469 58.859375 C 466.335938 59.152344 466.464844 59.375 466.617188 59.523438 C 466.816406 59.707031 467.050781 59.824219 467.332031 59.875 C 467.617188 59.925781 467.902344 59.839844 468.191406 59.609375 C 468.351562 59.484375 468.46875 59.34375 468.542969 59.1875 C 468.617188 59.023438 468.660156 58.871094 468.683594 58.726562 C 468.703125 58.578125 468.738281 58.371094 468.742188 58.320312 C 468.746094 58.273438 468.738281 58.089844 468.945312 58.074219 C 469.152344 58.058594 469.171875 58.242188 469.191406 58.441406 C 469.210938 58.640625 469.101562 59.382812 468.9375 59.84375 C 468.769531 60.308594 468.570312 60.679688 468.339844 60.957031 C 468.109375 61.242188 467.886719 61.445312 467.664062 61.566406 C 467.410156 61.71875 467.117188 61.8125 466.785156 61.84375 C 466.449219 61.878906 466.140625 61.796875 465.867188 61.613281 C 465.40625 61.277344 465.054688 60.753906 464.824219 60.039062 C 464.683594 59.621094 464.617188 59.070312 464.597656 58.386719 C 464.578125 57.703125 464.601562 57.035156 464.664062 56.382812 Z M 465.027344 52.910156 "/>
</svg>

After

Width:  |  Height:  |  Size: 96 KiB

16606
halfway-presentation/main.pdf Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,259 @@
#import "@preview/touying:0.7.3": *
#import "@preview/touying-unistra-pristine:1.4.3": *
#import "@preview/codly:1.3.0": codly, codly-init
#import "@preview/codly-languages:0.1.10": codly-languages
#import "@preview/cetz:0.5.2": canvas, draw
#import "langs.typ": i18n, i18n-date
#import "utils.typ": title-slide
#let langs = (
fr: ("fr", "ch"),
en: ("en", "gb")
)
#let (lang, region) = langs.en
#let i18n = i18n.with(lang)
#let i18n-date = i18n-date.with(lang)
#show raw.where(lang: "midas"): set raw(syntaxes: "midas.sublime-syntax")
#show: codly-init
#codly(languages: codly-languages + (
midas: (
name: "Midas",
color: rgb("#000000"),
icon: box(
image(
"midas.svg",
height: 130%,
fit: "contain",
),
),
)
))
#let regexp = regex(`\[\[(.*?)\]\]`.text)
#show raw: it => {
show regexp: m => {
let key = m.text.slice(2, -2)
return i18n(key)
}
it
}
#pdfpc.config(
duration-minutes: 15,
start-time: datetime(hour: 9, minute: 30, second: 0),
end-time: datetime(hour: 9, minute: 45, second: 0),
last-minutes: 2,
note-font-size: 12,
disable-markdown: false
)
#set text(lang: lang, region: region)
#show: unistra-theme.with(
aspect-ratio: "16-9",
config-common(
enable-pdfpc: true
),
config-info(
title: i18n("title"),
subtitle: i18n("subtitle"),
short-title: i18n("short-title"),
author: [Louis Heredero],
date: i18n-date(datetime(day: 3, month: 6, year: 2026)),
institution: [ISC \@ HEI Sion],
logo: stack(
dir: ltr,
spacing: 1em,
image("logo_symbol.svg", height: 100%),
image("hei.svg", height: 80%),
),
),
config-store(
font: "Source Sans 3",
),
)
#title-slide(
logo: image("logo_white.svg", height: 3em),
extra-body: place(
bottom + right,
dx: -2em,
dy: -2em
)[
#text(
fill: white,
weight: "bold"
)[#i18n("supervisor"): Dr D. Racordon]
]
)
#focus-slide(
theme: "pink",
show-counter: false,
)[
#i18n("context")
]
== #i18n("context")
==== #i18n("case-1")
#[
#set text(size: .8em)
```python
df = pd.read_csv(...)
value = df["distance"] / df["time"]
...
value += df["age"]
```
]
#pause
==== #i18n("case-2")
#[
#set text(size: .8em)
```sh
louis@powerful-server:$ ./start.sh
99%|██████████| 5410/5432 [90:10:06<22:33, 60.00s/it]
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
```
]
== #i18n("goal")
- #i18n("gradual-typing")
- #i18n("optional-typing")
- #i18n("static-type-checking")
- #i18n("dynamic-checks")
- #i18n("runtime-assertions")
- #i18n("value-constraints")
#let wah = place(
right + horizon,
dx: (
-.4em // inset
-100% // width
),
box(
inset: .4em,
text(
fill: std.red,
weight: "bold",
$->$
)
)
)
== #i18n("example")
#[
#set text(size: .8em)
```python
df: Frame[
verified: bool,
birth_date: date,
height: float & (0 < _ < 250),
name: Optional[str],
home: GeoCoordinate,
] = pd.read_csv(...)
lat = df["home"].lat
lon = df["home"].lon
invalid = lat + lon # [[lat-lon-error]]
```
]
#focus-slide(
theme: "yellow",
show-counter: false
)[#i18n("planning")]
== #i18n("initial-planning")
#table(
columns: (auto, 1fr),
align: (center, left + horizon),
inset: (x: .4em, y: .25em),
table.header[*#i18n("week")*][*#i18n("objectives")*],
[*1*], i18n("initial-week1"),
[*2*], i18n("initial-week2"),
[*3*], table.cell(rowspan: 4, i18n("initial-week3-6")),
[*4*#wah],
[*5*],
[*6*],
[*7*], table.cell(rowspan: 3, i18n("initial-week7-9")),
[*8*],
[*9*],
)
== #i18n("current-status")
#table(
columns: (auto, 1fr),
align: (center, left + horizon),
inset: (x: .4em, y: .25em),
table.header[*#i18n("week")*][*#i18n("objectives")*],
[*1*], i18n("current-week1"),
[*2*], i18n("current-week2"),
[*3*], i18n("current-week3"),
[*4*#wah], i18n("current-week4"),
[*5*], i18n("current-week5"),
[*6*], i18n("current-week6"),
[*7*], table.cell(rowspan: 3, i18n("current-week7-9")),
[*8*],
[*9*],
)
#focus-slide(
theme: "neon",
show-counter: false
)[#i18n("demo")]
== #i18n("demo")
=== #i18n("def-custom-types")
#[
#set text(size: .8em)
```midas
type Meter = float
type Second = float
type MeterPerSecond = float
extend Meter {
op __add__(Meter) -> Meter
op __truediv__(Second) -> MeterPerSecond
}
extend Second {
op __add__(Second) -> Second
}
```
]
---
=== #i18n("write-program")
#[
#set text(size: .8em)
```python
distance: Meter = 123.45
time: Second = 6.7
time += time # [[valid]]
speed = distance / time # speed: MeterPerSecond
speed += time # [[invalid]]
```
]
#focus-slide(
theme: "mandarine",
show-counter: false,
)[
Questions ?
]

View File

@@ -0,0 +1,15 @@
---
name: Midas
file_extensions: [midas]
scope: source.midas
contexts:
main:
- match: \b(type|extend|op|predicate)\b
scope: keyword.control.midas
- match: //
scope: punctuation.definition.comment.midas
push:
- meta_scope: comment.line.midas
- match: $
pop: true

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="128"
height="128"
viewBox="0 0 128 128"
version="1.1"
id="svg1"
inkscape:export-filename="logo.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:version="1.4.4 (1:1.4.4+202605061436+dcaf3e7d9e)"
sodipodi:docname="logo.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="true"
inkscape:zoom="1.9332778"
inkscape:cx="-8.2760999"
inkscape:cy="112.2446"
inkscape:window-width="2584"
inkscape:window-height="1028"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
id="grid1"
units="px"
originx="0"
originy="0"
spacingx="4"
spacingy="4"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="4"
enabled="true"
visible="true" />
</sodipodi:namedview>
<defs
id="defs1">
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689"
id="linearGradient1478"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.562541,0,0,0.567972,-9.399749,-5.305317)"
x1="26.648937"
y1="20.603781"
x2="135.66525"
y2="114.39767" />
<linearGradient
id="linearGradient4689">
<stop
style="stop-color:#e1be1e;stop-opacity:1;"
offset="0"
id="stop4691" />
<stop
style="stop-color:#ffeb82;stop-opacity:1;"
offset="1"
id="stop4693" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4671"
id="linearGradient1475"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.562541,0,0,0.567972,-9.399749,-5.305317)"
x1="150.96111"
y1="192.35176"
x2="112.03144"
y2="137.27299" />
<linearGradient
id="linearGradient4671">
<stop
style="stop-color:#ffdc21;stop-opacity:1;"
offset="0"
id="stop4673" />
<stop
style="stop-color:#ffeb82;stop-opacity:1;"
offset="1"
id="stop4675" />
</linearGradient>
</defs>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g1"
transform="translate(2.911719,3.414527)">
<path
style="fill:url(#linearGradient1478);fill-opacity:1"
d="m 60.510156,6.3979729 c -4.583653,0.021298 -8.960939,0.4122177 -12.8125,1.09375 C 36.35144,9.4962267 34.291407,13.691825 34.291406,21.429223 v 10.21875 h 26.8125 v 3.40625 h -26.8125 -10.0625 c -7.792459,0 -14.6157592,4.683717 -16.7500002,13.59375 -2.46182,10.212966 -2.5710151,16.586023 0,27.25 1.9059283,7.937852 6.4575432,13.593748 14.2500002,13.59375 h 9.21875 v -12.25 c 0,-8.849902 7.657144,-16.656248 16.75,-16.65625 h 26.78125 c 7.454951,0 13.406253,-6.138164 13.40625,-13.625 v -25.53125 c 0,-7.266339 -6.12998,-12.7247775 -13.40625,-13.9375001 -4.605987,-0.7667253 -9.385097,-1.1150483 -13.96875,-1.09375 z m -14.5,8.2187501 c 2.769547,0 5.03125,2.298646 5.03125,5.125 -2e-6,2.816336 -2.261703,5.09375 -5.03125,5.09375 -2.779476,-1e-6 -5.03125,-2.277415 -5.03125,-5.09375 -1e-6,-2.826353 2.251774,-5.125 5.03125,-5.125 z"
id="path1948" />
<path
style="fill:url(#linearGradient1475);fill-opacity:1"
d="m 91.228906,35.054223 v 11.90625 c 0,9.230755 -7.825895,16.999999 -16.75,17 h -26.78125 c -7.335833,0 -13.406249,6.278483 -13.40625,13.625 v 25.531247 c 0,7.26634 6.318588,11.54032 13.40625,13.625 8.487331,2.49561 16.626237,2.94663 26.78125,0 6.750155,-1.95439 13.406253,-5.88761 13.40625,-13.625 V 92.897973 h -26.78125 v -3.40625 h 26.78125 13.406254 c 7.79246,0 10.69625,-5.435408 13.40624,-13.59375 2.79933,-8.398886 2.68022,-16.475776 0,-27.25 -1.92578,-7.757441 -5.60387,-13.59375 -13.40624,-13.59375 z m -15.0625,64.65625 c 2.779478,3e-6 5.03125,2.277417 5.03125,5.093747 -2e-6,2.82635 -2.251775,5.125 -5.03125,5.125 -2.76955,0 -5.03125,-2.29865 -5.03125,-5.125 2e-6,-2.81633 2.261697,-5.093747 5.03125,-5.093747 z"
id="path1950" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,100 @@
#import "@preview/touying:0.6.2": *
#import "@preview/touying-unistra-pristine:1.4.3": *
// Redefine to allow extra-body
#let title-slide(
title: "",
subtitle: "",
logo: "",
logos: (),
hide: (),
extra-body: [],
..args,
) = touying-slide-wrapper(self => {
let info = self.info + args.named()
let nb-logos = logos.len()
if logo != "" and nb-logos > 0 {
panic("'logo' and 'logos' cannot be set at the same time.")
}
let logo-body = none
if nb-logos == 0 {
logo-body = logo
} else {
logo-body = grid(
columns: if nb-logos > 0 {
nb-logos
} else {
1
},
..(logos).map(logo => logo),
)
}
let body = {
set text(fill: white)
set block(inset: 0mm, outset: 0mm, spacing: 0em)
set align(top + left)
_gradientize(
self,
block(
fill: none,
width: 100%,
height: 100%,
inset: (left: 2em, top: 1em),
grid(
columns: 1fr,
rows: (6em, 6em, 4em, 4em),
logo-body,
_cell([
#text(size: 2em, weight: "bold", if (title != "") {
title
} else {
info.title
})
#linebreak()
#text(size: 1.7em, weight: "regular", if (subtitle != "") {
subtitle
} else {
info.subtitle
})
]),
_cell([
#if ((none, "").all(x => x != info.subtitle)) {
linebreak()
}
#set text(size: 1.5em, fill: self.colors.white)
#text(weight: "bold", info.author)
#if "email" in info {
linebreak()
text(info.email, size: 0.8em)
}
]),
if "date" not in hide {
_cell([
#set text(fill: self.colors.white.transparentize(25%))
#utils.display-info-date(self)
])
},
),
),
c1: self.colors.nblue.E,
c2: self.colors.cyan.E,
)
}
self = utils.merge-dicts(
self,
config-common(freeze-slide-counter: true),
config-page(margin: 0em),
config-common(subslide-preamble: none),
)
touying-slide(
self: self,
body + extra-body,
)
})

View File

@@ -14,3 +14,26 @@
- Read TAPL (22) - Read TAPL (22)
- Rework abstract types - Rework abstract types
- Generalize syntax (more modularity for generics, unions, constraints, etc.) - Generalize syntax (more modularity for generics, unions, constraints, etc.)
- Weekly meeting
#day(3)
- Halfway presentations
- Define formal syntax and typing rules
#day(5)
- Work on formal rules
- Update syntax definition (EBNF + railroad diagrams)
- Add usage documentation
- Implement subtyping
#day(6)
- Implement subtyping
#day(7)
- Implement subtyping
- Implement attribute reference and assignments
- Improve diagnostics in CLI

44
journal/week5.typ Normal file
View File

@@ -0,0 +1,44 @@
#import "template.typ": week, day
#show: week.with(num: 5)
#day(1)
- Implement generics
- Refactor type checker
- Create demo program
#day(2)
- Define formal calculus rules
- Add type params to extend block
#day(3)
- Rework extend block for methods
- Goal: allow defining any method on types
- Issues:
- `GetExpr` can reference either a property on a `ComplexType` or a method.
- A method (or function) can be overloaded, for example ```py list[T].__getitem__(int) -> T``` and ```py list[T].__getitem__(slice) -> list[T]```
#day(4)
- Rework complex types: extension type, combine properties and methods as members
#day(5)
- Implement member lookup
- Adapt operations
- Handle generic members
#day(6)
- Redefine builtins with members
- Tidy up
- Add unary operations and subscripts
#day(7)
- Resolve overloaded functions
- Add slices
- Add simple code generator

40
journal/week6.typ Normal file
View File

@@ -0,0 +1,40 @@
#import "template.typ": week, day
#show: week.with(num: 6)
#day(1)
- Simple code generator
- Redesign CLI
- Split overloaded command into multiple simple commands
- Add some commands
- Add for loops
- Start implementing cast assertions
#day(2)
- Weekly meeting
- Forward raw unhandled Python statements and expressions
- Generate cast assertions (type)
- Add generator tests
#day(3)
- Generate stubs from Midas definitions
#day(4)
- Generate predicate functions
#day(5)
- Type check predicate body
#day(6)
- Add variance to type variables (infer, use in subtype check, integrate in generated stubs)
- Unify / match types in generic function calls
#day(7)
- Unify / match types in generic function calls

34
journal/week7.typ Normal file
View File

@@ -0,0 +1,34 @@
#import "template.typ": week, day
#show: week.with(num: 7)
#day(1)
- better handle type variables
- write simple demo script
- various fixes
#day(2)
- weekly meeting
- start implementing data-frame and column types
#day(3)
- statically check cast expressions on literal values
- add unsafe cast
- setup user manual
- setup report
#day(4)
- work on data-frame and column types (method resolution, subtyping)
#day(5)
- work on data-frame and column types (asserts, dunders)
- start writing user manual (quick start)
#day(7)
- work on user manual (Midas reference, supported Python syntax)

49
journal/week8.typ Normal file
View File

@@ -0,0 +1,49 @@
#import "template.typ": week, day
#show: week.with(num: 8)
#day(1)
- improvements and bugfixes
- unknown frame methods
- assertion on column values
- allow unknowns in more places
- parse empty calls
- tuple type instantiation
- `str` methods
- multi-parameter generic
- tuple expression
#day(2)
- weekly meeting
- generate stubs when compiling
- work on frames and columns (brainstorm / setup methods)
- start working on call dispatcher
#day(3)
- finish call dispatcher
- add type aliases
- work on frame and columns method registry
#day(4)
- implement group-by on frames and columns
- implement some methods on frames and columns
#day(5)
- implement arithmetic, comparison and aggregation methods, `head`/`tail` and some attributes on frames and columns
- refactor printers
- rename `Function.Argument` -> `Function.Parameter`
- update manual for frames and columns
- add some docstrings
#day(6)
- add more docstrings
#day(7)
- add more docstrings

43
journal/week9.typ Normal file
View File

@@ -0,0 +1,43 @@
#import "template.typ": week, day
#show: week.with(num: 9)
#day(1)
- add more docstrings
- handle column subscript
- handle `not` operator
- properly type check parameter default values
- handle import statements
- handle column type instantiation
#day(2)
- parse int literals as integers
- implement scalar ops on frames and columns
- add more docstrings
- fix some bugs, make some small improvements
- complete weather pipeline example with frame operations
- implement formulae to compute aggregation method return types
#day(3)
- weekly meeting
- update syntax definitions
- check variable assignment when referenced
- add CI to run tests
- remove complex type
- complete user manual, including CLI subcommands
- add variance manager
- minor improvements
#day(4)
- check, document and fix function subtyping logic
- add some tests
- cleanup repository
#day(5)
- remove some raised errors to use diagnostics
- code repository submission

38
justfile Normal file
View File

@@ -0,0 +1,38 @@
# Local Variables:
# mode: makefile
# End:
set shell := ["bash", "-uc"]
outdir := "out"
report_out_path := outdir / "report.pdf"
summary_out_path := outdir / "summary.pdf"
default: all
_setup:
mkdir -p {{outdir}}
check-links document:
#!/usr/bin/env python3
import re
import requests
import sys
print("Checking links in {{document}}...")
with open("{{document}}", "rb") as f:
r = rb"</Type/Action/S/URI/URI\((.*?)\)"
matches = set(re.findall(r, f.read(), re.S))
print(f"Found {len(matches)} links")
for url in matches:
print(f"Testing {url.decode('utf-8')}")
res = requests.head(url, headers={"User-Agent": "BrokenURLChecker 1.0"})
if not (200 <= res.status_code <= 399):
print(f"{url} is broken: {res.status_code} {res.reason}")
sys.exit(1)
report: _setup
typst c --root . report/bachelor_thesis.typ {{report_out_path}}
summary: _setup
typst c --root . summary/exec_summary.typ {{summary_out_path}}
all: report summary

25
meta.typ Normal file
View File

@@ -0,0 +1,25 @@
#let title = "Midas"
#let subtitle = none
#let authors = "Louis Heredero"
#let thesis-supervisor = "Prof. Dr Dimi Racordon"
#let thesis-co-supervisor = none
#let thesis-expert = "Dr Sébastien Doeraene"
#let thesis-id = "ISC-ID-26-8"
#let project-repos = "https://git.kb28.ch/HEL/midas"
#let mirror-repo = "https://github.com/LordBaryhobal/midas"
#let school = "Haute École d'Ingénierie de Sion"
#let programme = "Informatique et systèmes de communication (ISC)"
#let keywords = ("engineering", "type systems", "gradual typing")
#let major = "Data engineering"
#let date = datetime(year: 2026, month: 7, day: 10) // Date of the thesis & the declaration (or datetime.today())
#let permanent-email = "louis@heredero.org"
#let video-url = none
#let picture-web-opt-out = false // set to true to keep your picture off the web
#let email-web-opt-out = false // set to true to keep your email off the web
#let academic-year = "2025-2026"

211
midas.sublime-syntax Normal file
View File

@@ -0,0 +1,211 @@
%YAML 1.2
---
name: Midas
file_extensions:
- midas
scope: source.midas
variables:
identifier: "[a-zA-Z_][a-zA-Z0-9_]*"
contexts:
prototype:
- include: comments
main:
- include: keywords
- include: types
comments:
- match: "//"
scope: punctuation.definition.comment.midas
push:
- meta_scope: comment.line.midas
- match: $
pop: true
- match: /\*
scope: punctuation.definition.comment.midas
push:
- meta_scope: comment.block.midas
- match: \*/
pop: true
string:
- meta_include_prototype: false
- meta_scope: string.quoted.double.c
- match: '"'
pop: true
keywords:
- match: \balias\b
scope: keyword.declaration.midas
push: alias-stmt
- match: \btype\b
scope: keyword.declaration.midas
push: type-stmt
- match: \bextend\b
scope: keyword.declaration.midas
push: extend-stmt
- match: \bpredicate\b
scope: keyword.declaration.midas
push: predicate-stmt
alias-stmt:
- match: "{{identifier}}"
scope: entity.name.type
- match: "="
scope: keyword.operator.equal.midas
push: type-expr
- match: $
pop: true
type-stmt:
- match: "{{identifier}}"
scope: entity.name.type
- match: \[
push: type-params
- match: "="
scope: keyword.operator.equal.midas
push: type-expr
- match: $
pop: true
type-expr:
- match: \b(fn)\s*(\()
captures:
1: keyword.other.midas
2: punctuation.section.group.begin
push: fn-params
- match: \b(where)\b
scope: keyword.other.midas
set: constraint
- match: "Frame"
scope: entity.name.type
push:
- match: \[
push: frame-schema
- match: $
pop: true
- match: "{{identifier}}"
scope: entity.name.type
- match: $
pop: 2
fn-params:
- match: "({{identifier}})(:)"
captures:
1: variable.parameter.midas
2: punctuation.separator.annotation.midas
push:
- include: type-expr
- match: \?
scope: keyword.operator.qmark.midas
- match: "(?=,)"
scope: punctuation.separator.midas
pop: true
- match: '(?=\))'
pop: true
- include: type-expr
- match: '\)'
set:
- match: "->"
scope: keyword.operator.arrow.midas
set: type-expr
constraint:
- match: $
pop: 2
- match: \d+(\.\d+)?
scope: constant.numeric.midas
- match: \b(true|false|none)\b
scope: constant.language.midas
- match: '"'
push: string
- match: (<=|>=|<|>|==|!=|&)
scope: keyword.operator
- match: _
scope: variable.language.midas
- match: '{{identifier}}(?=\s*\()'
scope: variable.function.midas
- match: "{{identifier}}"
scope: variable.other.readwrite.midas
type-params:
- match: "<:"
scope: keyword.operator.subtype.midas
- match: "[a-zA-Z][a-zA-Z_0-9]*"
scope: entity.name.type
- match: "]"
pop: true
extend-stmt:
- match: "{{identifier}}"
scope: entity.name.type
- match: \[
push: type-params
- match: \{
scope: punctuation.section.block.begin
set: extend-body
extend-body:
- include: member-stmt
- match: \}
scope: punctuation.section.block.end
pop: true
member-stmt:
- match: \b(prop|def)\b
scope: keyword.other.midas
push:
- match: "{{identifier}}"
scope: variable.other.member
- match: ":"
push: type-expr
- match: $
pop: true
predicate-stmt:
- match: "{{identifier}}"
scope: entity.name.function.midas
- match: '\('
push: predicate-params
- match: "="
scope: keyword.operator.equal.midas
set: constraint
- match: $
pop: true
predicate-params:
- match: "({{identifier}})(:)"
captures:
1: variable.parameter.midas
2: punctuation.separator.annotation.midas
push:
- include: type-expr
- match: "(?=,)"
scope: punctuation.separator.midas
pop: true
- match: '(?=\))'
pop: true
- match: '\)'
pop: true
frame-schema:
- include: frame-column
- match: \]
# scope: punctuation.section.block.end
pop: true
frame-column:
- match: "{{identifier}}"
scope: variable.other.member
- match: ":"
push: type-expr

10
report/acronyms.typ Normal file
View File

@@ -0,0 +1,10 @@
#import "@preview/acrostiche:0.7.0": *
#let acronyms = (
"TaPL": ([Types and Progamming Languages@tapl],),
"LSP": (link("https://en.wikipedia.org/wiki/Liskov_substitution_principle")[Liskov substitution principle],),
"AST": ([Abstract Syntax Tree],),
"LUB": ([Least Upper Bound],),
)
#init-acronyms(acronyms)

View File

@@ -0,0 +1,13 @@
#import "../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: code
#let call-dispatcher-code = raw(
read("../code/call_dispatcher.py"),
lang: "python",
block: true
)
#figure(
code(call-dispatcher-code),
caption: [Some call dispatcher methods]
) <fig:call-dispatcher>

View File

@@ -0,0 +1,88 @@
#import "@preview/curryst:0.6.0": prooftree, rule, rule-set
#import "@preview/gentle-clues:1.3.1" as gc
#import "@preview/lovelace:0.3.1": pseudocode-list
#let req = math.op("req")
This document formalizes the logic used when checking whether a function is a subtype of another.
= Definitions
A *Parameter specification* has a list of positional-only parameters $P$, mixed parameters $M$ and keyword-only parameters $K$:
$ S = (P, M, K) $
A *Parameter* has an index $i$, a name $n$ and a required flag $r$:
$ p = (i, n, r) $
A *Function* has a param spec $S$ and a return type $R$:
$ F = (S, R) $
= Main rules
We want to define a rule for checking structural subtyping of functions, i.e. to check when $F_1 <: F_2$
There are two conditions to check:
#align(center, prooftree(
rule(
$Gamma tack S_2 <: S_1$,
$Gamma tack R_1 <: R_2$,
$Gamma tack F_1 <: F_2$,
),
))
The second condition is trivial to check.
The first condition is a bit more tricky.
For a parameter specification $S_2$ to be a subtype of another $S_1$, the latter needs to be fully compatible with any usages of the former. What this means is that #link(<cond-1>)[(1)] any argument that can be passed to $S_2$ must be accepted by $S_1$, and #link(<cond-2>)[(2)] $S_1$ must not have additional required arguments that are not in $S_2$. However, $S_1$ can have additional optional parameters not present in $S_2$.
After mapping parameters of $S_1$ and $S_2$, types must be checked such that if a parameter $p_i: T in S_1$ is mapped to a parameter $q_j: U in S_2$, $U <: T$.
= Detailed rules for *ParamSpec* subtyping
#gc.info(title: [Notation])[
In the following equations:
- the notation $S in.rev a^i: T$ will be used to denote that a parameter spec $S$ accepts an argument named $a$ at index $i$ of type $T$
- the special name $alpha$ will be used to denote any argument without a specific name
- the special name $phi$ will be used to denote any parameter without a specific name
- $AA$ denotes the group of all arguments, i.e. $alpha in AA$
- $PP$ denotes the group of all parameters, i.e. $p in PP$
- $req(S, alpha)$ is a predicate checking whether $alpha$ is required in $S$
]
== Arguments of $S_2$ are compatible with $S_1$ <cond-1>
Formally, the condition is:
$
forall alpha in AA, S_2 in.rev alpha => S_1 in.rev alpha
$
Let $S_1 = (P_1, M_1, K_1)$ and $S_2 = (P_2, M_2, K_2)$.
For each positional-only parameter $phi_i in P_2$, $phi_i in P_1 or phi_i in M_1$. A positional-only parameter of $S_2$ can either be positional-only or mixed in $S_1$. Additionally, $not req(S_2, phi_i) => not req(S_1, phi_i)$. If $phi_i$ is optional in $S_2$, it must also be optional in $S_1$ so that a call omitting it is valid.
Similarly, for each keyword-only parameter $p in K_2$, $p in K_1 or p in M_1$. A keyword-only parameter of $S_2$ can either be keyword-only or mixed in $S_1$. Additionally, $not req(S_2, p) => not req(S_1, p)$. If $p$ is optional in $S_2$, it must also be optional in $S_1$ so that a call omitting it is valid.
Finally, for mixed parameters, the rule is slightly more complex. Either there is a corresponding mixed parameter in $S_1$, or the parameter is covered by both a positional/mixed and a keyword/mixed parameter. In the second case, we must keep in mind that only one of the match will made at runtime, or maybe even none if the parameter is optional in $S_2$, meaning the parameters in $S_1$ _must_ be optional.
We can thus split the rule in two. $forall p_i in M_2$:
$
cases(
p_i in M_1 and not req(S_2, p_i) => not req(S_1, p_i),
"or",
underbrace((phi_i in P_1 or phi_i in M_1), "Positional") and
underbrace((p in K_1 or p in M_1), "Keyword") and
underbrace((not req(S_1, phi_i) and not req(S_1, p)), "Optional")
)
$
== No additional required arguments in $S_1$ <cond-2>
Formally, the condition is:
$
forall alpha in AA, S_1 in.rev alpha and req(S_1, alpha) => S_2 in.rev alpha and req(S_2, alpha)
$
Each parameter in $S_1$ that is not matched by a parameter in $S_2$ must be optional:
$
forall p_i in S_1, p_i in.not S_2 => not req(S_1, p_i)
$

View File

@@ -0,0 +1,24 @@
#import "../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: code
#import "../utils.typ": code-ref
#let is-subtype-code = raw(
read("../code/is_subtype.py"),
lang: "python",
block: true
)
#let is-func-subtype-code = raw(
read("../code/is_func_subtype.py"),
lang: "python",
block: true
)
#figure(
code(is-subtype-code),
caption: [Implementation of `TypesRegistry.is_subtype` (#code-ref(<is_subtype>, "midas/checker/registry.py"))#footnote[The order of cases is slightly different from the real implementation for grouped presentation purposes]]
) <fig:is_subtype>
#figure(
code(is-func-subtype-code),
caption: [Implementation of `TypesRegistry.is_func_subtype` (#code-ref(<is_func_subtype>, "midas/checker/registry.py"))]
) <fig:is_func_subtype>

View File

@@ -0,0 +1,216 @@
#import "@preview/acrostiche:0.7.0": acr
#import "utils.typ": format-ast-nodes
#let token-types = (
"Punctuation": (
"LEFT_PAREN",
"RIGHT_PAREN",
"LEFT_BRACKET",
"RIGHT_BRACKET",
"LEFT_BRACE",
"RIGHT_BRACE",
"COLON",
"COMMA",
"UNDERSCORE",
"ARROW",
"AND",
"QMARK",
"DOT",
),
"Operators": (
"PLUS",
"MINUS",
"STAR",
"SLASH",
"GREATER",
"GREATER_EQUAL",
"LESS",
"LESS_EQUAL",
"EQUAL",
"EQUAL_EQUAL",
"BANG_EQUAL",
"BANG",
),
"Literals": (
"IDENTIFIER",
"NUMBER",
"TRUE",
"FALSE",
"NONE",
"STRING",
),
"Keywords": (
"TYPE",
"ALIAS",
"PREDICATE",
"EXTEND",
"WHERE",
"PROP",
"DEF",
"FUNC",
),
"Misc": (
"COMMENT",
"WHITESPACE",
"EOF",
"NEWLINE",
),
)
#let token-types-cells = {
let cells = ()
for (category, types) in token-types.pairs() {
cells.push([*#category*])
cells += types
}
// Transpose
let per-col = calc.ceil(cells.len() / 4)
let total = per-col * 4
cells = (cells + (none,) * (total - cells.len())).chunks(per-col)
cells = cells.first().zip(..cells.slice(1)).flatten()
cells
}
#let ast-nodes = (
("Other classes", none, ```python
class TypeParam:
location: Location
name: Token
bound: Optional[Type]
class MemberKind(Enum):
PROPERTY = auto()
METHOD = auto()
class ParamSpec:
l_paren: Token
pos: list[FunctionType.Parameter]
mixed: list[FunctionType.Parameter]
kw: list[FunctionType.Parameter]
```),
("Statements", `Stmt`, ```python
class TypeStmt:
name: Token
params: list[TypeParam]
type: Type
class AliasStmt:
name: Token
type: Type
class MemberStmt:
name: Token
type: Type
kind: MemberKind
class ExtendStmt:
name: Token
params: list[TypeParam]
members: list[MemberStmt]
class PredicateStmt:
name: Token
params: list[ParamSpec]
body: Expr
```),
("Expressions", `Expr`, ```python
class LogicalExpr:
left: Expr
operator: Token
right: Expr
class BinaryExpr:
left: Expr
operator: Token
right: Expr
class UnaryExpr:
operator: Token
right: Expr
class CallExpr:
callee: Expr
arguments: list[Expr]
keywords: dict[str, Expr]
class GetExpr:
expr: Expr
name: Token
class VariableExpr:
name: Token
class GroupingExpr:
expr: Expr
class LiteralExpr:
value: Any
class WildcardExpr:
token: Token
```),
("Types", `Type`, ```python
class NamedType:
name: Token
class GenericType:
type: Type
args: list[Type]
class ConstraintType:
type: Type
constraint: Expr
class FunctionType:
params: ParamSpec
returns: Type
class Parameter:
location: Optional[Location] = None
name: Optional[Token]
type: Type
required: bool
class FrameType:
columns: list[Column]
class Column:
location: Optional[Location] = None
name: Token
type: Type
```),
)
#let midas-ast-nodes = table(
inset: .5em,
row-gutter: 2em,
stroke: gray,
..ast-nodes.map(nodes => format-ast-nodes(..nodes))
)
#show figure: set block(breakable: true)
#figure(
grid(
columns: 4,
column-gutter: 3em,
inset: .5em,
..token-types-cells,
),
caption: [Midas Token Types],
kind: table,
supplement: [Table],
) <tab:token-types>
#figure(
midas-ast-nodes,
caption: [Midas #acr("AST") Nodes],
kind: table,
supplement: [Table],
) <tab:midas-ast-nodes>

View File

@@ -0,0 +1,243 @@
#import "@preview/fervojo:0.1.1": default-css, render
#let extra-css = ```css
svg.railroad .terminal rect {
fill: #F7DCD4;
}
```
#let css = default-css() + bytes(extra-css.text)
#let literal = ```
{[`literal` <
[`number` 'digit' * ! <!, ["." 'digit' * !]>],
[`boolean` <"False", "True">],
[`string` <["\"" 'char'*! "\""], ["'" 'char'*! "'"]>],
[`none` "None"]
>]}
```
#let grouping = ```
{[`grouping` "(" 'expression' ")"]}
```
#let primary = ```
{[`primary` <"_", 'literal', 'identifier', 'grouping'>]}
```
#let reference = ```
{[`reference` 'primary' <!, ["." 'identifier']*!>]}
```
#let call-args = ```
{[`call-args` "(" <!, <'expression', ['identifier' "=" 'expression']>*","#`Same rules as Python`> ")"]}
```
#let call = ```
{[`call` 'reference' <!, 'call-args'*!>]}
```
#let unary = ```
{[`unary` <[<"+", "-", "!"> 'unary'], 'call'>]}
```
#let factor = ```
{[`factor` 'unary'*<"*", "/">]}
```
#let term = ```
{[`term` 'factor'*<"+", "-">]}
```
#let comparison = ```
{[`comparison` 'term'*<">", "<", ">=", "<=">]}
```
#let equality = ```
{[`equality` 'comparison'*<"==", "!=">]}
```
#let expression = ```
{[`expression` 'equality'*"&"]}
```
#let constraint = ```
{[`constraint` 'expression']}
```
#let template-param = ```
{[`template-param` 'identifier' <!, ["<:" 'type']>]}
```
#let template = ```
{[`template` "[" <!, 'template-param'*","> "]"]}
```
#let named-type = ```
{[`named-type` 'identifier']}
```
#let type-args = ```
{[`type-args` "[" <!, 'type'*","> "]"]}
```
#let frame-schema = ```
{[`frame-schema` "[" <!, ['TOKEN' ":" 'type']*","> "]"]}
```
#let generic-type = ```
{[`generic-type` <["Frame" 'frame-schema'], ['named-type' <!, 'type-args'>]>]}
```
#let grouped-type = ```
{[`grouped-type` "(" 'type' ")"]}
```
#let base-type = ```
{[`base-type` <'grouped-type', 'generic-type'>]}
```
#let constraint-type = ```
{[`constraint-type` 'base-type' <!, ["where" 'constraint']>]}
```
#let pos-param = ```
{[`pos-param` <!, ['identifier' ":"]> 'type' <!, "?">]}
```
#let kw-param = ```
{[`kw-param` 'identifier' ":" 'type' <!, "?">]}
```
#let param-spec = ```
{[`param-spec` "(" <!, <'pos-param', "/", "*", 'kw-param'>*",">#`Same rules as Python` ")"]}
```
#let func-type = ```
{[`func-type` "fn" 'param-spec' "->" 'type']}
```
#let type = ```
{[`type` <'func-type', 'constraint-type'>]}
```
#let alias-statement = ```
{[`alias-statement` "alias" 'identifier' "=" 'type']}
```
#let type-statement = ```
{[`type-statement` "type" 'identifier' <!, 'template'> "=" 'type']}
```
#let member-stmt = ```
{[`member-stmt` <"prop", "def"> 'identifier' ":" 'type']}
```
#let extend-statement = ```
{[`extend-statement` "extend" 'type' "{" <!, 'member-stmt'*!> "}"]}
```
#let predicate-statement = ```
{[`predicate-statement` "predicate" 'identifier' <!, 'param-spec'*!> "=" 'constraint']}
```
#let statement = ```
{[`statement` <'alias-statement', 'type-statement', 'extend-statement', 'predicate-statement'>]}
```
#let rules = (
literal: literal,
grouping: grouping,
primary: primary,
reference: reference,
call-args: call-args,
call: call,
unary: unary,
factor: factor,
term: term,
comparison: comparison,
equality: equality,
expression: expression,
constraint: constraint,
template-param: template-param,
template: template,
named-type: named-type,
type-args: type-args,
generic-type: generic-type,
grouped-type: grouped-type,
base-type: base-type,
constraint-type: constraint-type,
pos-param: pos-param,
kw-param: kw-param,
param-spec: param-spec,
func-type: func-type,
type: type,
alias-statement: alias-statement,
type-statement: type-statement,
member-stmt: member-stmt,
extend-statement: extend-statement,
predicate-statement: predicate-statement,
statement: statement,
)
#let inline = (
"grouping",
"literal",
"template-param",
"template",
"call-args",
"type-args",
"named-type",
"grouped-type",
"generic-type",
"base-type",
"constraint-type",
"pos-param",
"kw-param",
"func-type",
"member-stmt",
"alias-statement",
"type-statement",
"extend-statement",
"predicate-statement",
)
= Statements and expressions
#let all-rules = for (name, rule) in rules.pairs().rev() {
[== #name]
render(rule, css: css)
}
#let substitute(base-rule) = {
let new-rule = base-rule
for name in inline {
let rule = rules.at(name)
let replacement = rule.text.slice(1, -1).replace(regex("\[`.*?`"), "[")
replacement = "[" + replacement + "#`" + name + "`]"
new-rule = new-rule.replace(
"'" + name + "'",
replacement,
)
}
if new-rule != base-rule {
new-rule = substitute(new-rule)
}
return new-rule
}
#let capitalize(word) = {
return upper(word.slice(0, 1)) + word.slice(1)
}
#let display-name(name) = {
let words = name.split("-").map(capitalize)
return [#words.join(" ") (#raw(name))]
}
#let all-combined = for (name, rule) in rules.pairs() {
if not name in inline {
[== #display-name(name)]
let combined = substitute(rule.text)
render(raw(combined), css: css)
//raw(block: true, combined)
}
}

View File

@@ -0,0 +1,13 @@
#import "../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: code
#let midas-typer-members-code = raw(
read("../code/midas_typer_skeleton.py"),
lang: "python",
block: true
)
#figure(
code(midas-typer-members-code),
caption: [Midas Typer Members]
) <fig:midas-typer-members>

View File

@@ -0,0 +1,172 @@
#import "@preview/acrostiche:0.7.0": acr
#import "utils.typ": format-ast-nodes
#let ast-nodes = (
("Other classes", none, ```python
class ParamSpec:
pos: list[Function.Parameter]
mixed: list[Function.Parameter]
kw: list[Function.Parameter]
@property
def all(self) -> list[Function.Parameter]:
return self.pos + self.mixed + self.kw
class ImportAlias:
location: Location
name: str
alias: Optional[str] = None
@property
def imported_name(self) -> str:
return (
self.alias
if self.alias is not None else
self.name
)
```),
("Type annotations", `MidasType`, ```python
class BaseType:
base: str
args: tuple[MidasType,...]
class FrameColumn:
name: Optional[str]
type: Optional[MidasType]
class FrameType:
columns: list[FrameColumn]
```),
("Statements", `Stmt`, ```python
class ExpressionStmt:
expr: Expr
class Function:
name: str
params: ParamSpec
returns: Optional[MidasType]
body: list[Stmt]
class Parameter:
location: Optional[Location] = None
name: str
type: Optional[MidasType]
default: Optional[Expr]
class TypeAssign:
name: str
type: MidasType
class AssignStmt:
targets: list[Expr]
value: Expr
class ReturnStmt:
value: Optional[Expr]
class IfStmt:
test: Expr
body: list[Stmt]
orelse: list[Stmt]
class Pass: ...
class ForStmt:
target: Expr
iterator: Expr
body: list[Stmt]
class ImportStmt:
imports: list[ImportAlias]
class FromImportStmt:
module: Optional[str]
imports: list[ImportAlias]
level: int
class RawStmt:
stmt: ast.stmt
```),
("Expressions", `Expr`, ```python
class BinaryExpr:
left: Expr
operator: ast.operator
right: Expr
class CompareExpr:
left: Expr
operator: ast.cmpop
right: Expr
class UnaryExpr:
operator: ast.unaryop
right: Expr
class CallExpr:
callee: Expr
arguments: list[Expr]
keywords: dict[str, Expr]
class GetExpr:
object: Expr
name: str
class LiteralExpr:
value: Any
class VariableExpr:
name: str
class LogicalExpr:
left: Expr
operator: ast.boolop
right: Expr
class CastExpr:
type: MidasType
expr: Expr
unsafe: bool
class TernaryExpr:
test: Expr
if_true: Expr
if_false: Expr
class ListExpr:
items: list[Expr]
class DictExpr:
keys: list[Optional[Expr]]
values: list[Expr]
class SubscriptExpr:
object: Expr
index: Expr
class SliceExpr:
lower: Optional[Expr]
upper: Optional[Expr]
step: Optional[Expr]
class TupleExpr:
items: tuple[Expr, ...]
class RawExpr:
expr: ast.expr
```),
)
#let python-ast-nodes = table(
inset: .5em,
stroke: gray,
row-gutter: 2em,
..ast-nodes.map(nodes => format-ast-nodes(..nodes))
)
#show figure: set block(breakable: true)
#figure(
python-ast-nodes,
caption: [Python #acr("AST") Nodes],
) <tab:python-ast-nodes>

View File

@@ -0,0 +1,13 @@
#import "../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: code
#let python-typer-function-code = raw(
read("../code/python_check_function.py"),
lang: "python",
block: true
)
#figure(
code(python-typer-function-code),
caption: [Implementation of `PythonTyper.visit_function`]
) <fig:python-visit_function>

View File

@@ -0,0 +1,37 @@
#import "@preview/codly:1.3.0": codly-disable, codly-enable
#import "../requirements.typ": isc-hei-bthesis
#let format-ast-nodes(name, base-cls, code) = {
let nodes = code.text.split(regex(`\n\nclass`.text)).map(n => if n.starts-with("class") {n} else {"class" + n})
let cells = nodes.map(n => raw(n, block: true, lang: "python"))
if calc.rem(cells.len(), 3) == 2 {
let last-two = cells.slice(-2)
cells = cells.slice(0, -2)
let last = grid.cell(
colspan: 3,
stack(
dir: ltr,
spacing: 1fr,
none,
..last-two,
none
)
)
cells.push(last)
}
align(center)[*#name*]
if base-cls != none [Base class: #base-cls]
codly-disable()
grid(
columns: 3,
column-gutter: 1fr,
row-gutter: 2em,
align: left + top,
..cells
)
codly-enable()
}

View File

@@ -0,0 +1,29 @@
#import "../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: code
#figure(
code(raw(
block: true,
lang: "python",
read("../code/variance_tracker.py")
)),
caption: [Implementation of variance `Tracker`]
) <fig:midas-variance-tracker>
#figure(
code(raw(
block: true,
lang: "python",
read("../code/variance_inferrer.py")
)),
caption: [Implementation of variance `VarianceInferrer`]
) <fig:midas-variance-inferrer>
#figure(
code(raw(
block: true,
lang: "python",
read("../code/variance_manager.py")
)),
caption: [Implementation of variance `VarianceManager`]
) <fig:midas-variance-manager>

192
report/bachelor_thesis.typ Normal file
View File

@@ -0,0 +1,192 @@
// ___ ____ ____ _ _ _____ ___
// |_ _/ ___| / ___| | | | | ____|_ _| Informatique et
// | |\___ \| | ___ | |_| | _| | | systèmes de communication
// | | ___) | |__|___| | _ | |___ | | HEI Sion · HES-SO Valais / mui 24-26
// |___|____/ \____| |_| |_|_____|___|
//
// 52 65 61 64 69 6e 67 20 68 65 78 20 66 6f 72 20 66 75 6e 3f 20 49 53 43 20 66 6f 72 65 76 65 72
//
#import "requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: *
#import "@preview/codly:1.3.0": codly-init, codly
#import "@preview/codly-languages:0.1.10": codly-languages
#import "../meta.typ"
#import "utils.typ": include-offset
#let doc_language = "en"
#show: codly-init
#codly(
languages: codly-languages
+ (
midas: (
name: "Midas",
color: rgb("#eedd47"),
icon: box(
image(
"../assets/icon.svg",
height: 130%,
fit: "contain",
),
),
),
),
)
#set raw(
syntaxes: path("../midas.sublime-syntax")
)
#show: thesis.with(
title: meta.title,
subtitle: meta.subtitle,
authors: meta.authors,
language: doc_language,
thesis-supervisor: meta.thesis-supervisor,
thesis-co-supervisor: meta.thesis-co-supervisor,
thesis-expert: meta.thesis-expert,
thesis-id: meta.thesis-id,
project-repos: meta.project-repos,
school: meta.school,
programme: meta.programme,
keywords: meta.keywords,
major : meta.major,
date: meta.date,
// Declaration of honour signature
signature: image("figs/signature_placeholder.svg", width: 4.5cm), // A scan/photo of your handwritten signature
revision: "1.0",
code-theme: "bluloco-light",
// The cover might show a red "ATTENTION REQUISE" box listing required fields still
// left at their placeholder values (and warns if the title/subtitle is too long).
// Uncomment to hide it, but only do this if you know what you are doing.
// hide-completeness-warning: true,
)
// If using acronyms
#import "@preview/acrostiche:0.7.0": *
#include "acronyms.typ"
// A tidy acronym table for the appendix, using the acronyms declared above.
// (Kept here, not in the package, so acrostiche stays an example-only dependency.)
#let acronym-table() = print-index(
title: page-title(i18n(doc_language, "acronym-table-title"), mult: 1, top: 1em, bottom: 1em),
sorted: "up",
delimiter: " : ",
row-gutter: 0.7em,
outlined: false,
)
////////////////////////////
// Let's get started folks!
////////////////////////////
#cleardoublepage()
#include "pages/abstract.typ"
#cleardoublepage()
#include "pages/résumé.typ"
#cleardoublepage()
#declaration-of-honour()
#cleardoublepage()
#include "pages/acknowledgements.typ"
/*
== The content of a thesis
The general structure of a bachelor thesis typically includes the following sections:
1. *Abstract*: A concise summary of the thesis, including the research question, methodology, results, and conclusions.
2. *Résumé*: A summary of the thesis in French.
3. *Acknowledgements*: [Optional] A section to thank those who supported your work.
4. *Table of Contents*: An organized list of chapters and sections.
5. *Introduction*: Presents the background/context, motivation, objectives, and scope and plan of the thesis.
6. *State of the Art / Literature Review*: Reviews existing research and situates the thesis within the academic context, if relevant to your work.
7. *Development and Methodology*: Describes the methods, materials, and procedures used in the research/thesis.
8. *Results*: Presents the findings of the research, often with tables, figures, and analysis.
9. *Discussion*: Interprets the results, discusses implications, and relates findings to the research question.
10. *Conclusion*: Summarizes the main findings and contributions, and suggests future work.
11. *References / Bibliography*: Lists all sources cited in the thesis.
12. *Appendices*: (Optional) Contains supplementary material such as raw data, code, or additional explanations.
This structure may vary depending on the field of study, but these elements are commonly found in most bachelor theses. They are recommended for the _ISC Bachelor thesis_ and should be adapted to the specific requirements of your thesis (e.g., if you have a state of the art section or not).
You can also change the order or the names of the sections, for instance, if you want to put the state of the art before the introduction, or if you want to add a section on methodology before the results.
*/
#include "chapters/01_introduction.typ"
#include "chapters/02_state_of_the_art.typ"
#include "chapters/03_theory.typ"
#include "chapters/04_implementation.typ"
#include "chapters/05_results_discussion.typ"
#include "chapters/06_conclusion.typ"
#pagebreak()
#the-bibliography(
bib-file: read("bibliography.bib", encoding: none),
full: true,
style: "ieee"
)
//////////////
// Appendices
//////////////
#cleardoublepage()
#appendix-page()
#pagebreak()
#set heading(numbering: "A.1", supplement: [Appendix])
#set figure(numbering: (..nums) => counter(heading).display("A.1") + "." + numbering("1", ..nums))
// Table of acronyms (optional). Defined near the acronyms above.
#acronym-table()
#pagebreak()
// Table of listings
#table-of-figures()
// Code inclusion
#pagebreak()
#code-samples()
#include "appendices/is_subtype.typ"
#include "appendices/midas_typer_skeleton.typ"
#include "appendices/variance.typ"
#include "appendices/python_typer.typ"
#include "appendices/call_dispatcher.typ"
#pagebreak()
= Midas Language Definition <app:midas-syntax>
#import "appendices/midas_railway.typ": all-combined
#all-combined
= Function Subtyping Rules <app:function-subtyping>
#include-offset("appendices/function_subtyping.typ")
= Midas Language Objects
#include-offset("appendices/midas_parsing.typ")
= Python Language Objects
#include-offset("appendices/python_parsing.typ")

118
report/bibliography.bib Normal file
View File

@@ -0,0 +1,118 @@
% Encoding: UTF-8
@book{tapl,
author = {Pierce, Benjamin C.},
title = {Types and Programming Languages},
year = {2002},
isbn = {0262162091},
publisher = {The MIT Press},
edition = {1st},
abstract = {A type system is a syntactic method for automatically checking the absence of certain erroneous behaviors by classifying program phrases according to the kinds of values they compute. The study of type systems -- and of programming languages from a type-theoretic perspective -- has important applications in software engineering, language design, high-performance compilers, and security.This text provides a comprehensive introduction both to type systems in computer science and to the basic theory of programming languages. The approach is pragmatic and operational; each new concept is motivated by programming examples and the more theoretical sections are driven by the needs of implementations. Each chapter is accompanied by numerous exercises and solutions, as well as a running implementation, available via the Web. Dependencies between chapters are explicitly identified, allowing readers to choose a variety of paths through the material.The core topics include the untyped lambda-calculus, simple type systems, type reconstruction, universal and existential polymorphism, subtyping, bounded quantification, recursive types, kinds, and type operators. Extended case studies develop a variety of approaches to modeling the features of object-oriented languages.}
}
@article{gator,
author = {Geisler, Dietrich and Yoon, Irene and Kabra, Aditi and He, Horace and Sanders, Yinnon and Sampson, Adrian},
title = {Geometry types for graphics programming},
year = {2020},
issue_date = {November 2020},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
volume = {4},
number = {OOPSLA},
url = {https://doi.org/10.1145/3428241},
doi = {10.1145/3428241},
abstract = {In domains that deal with physical space and geometry, programmers need to track the coordinate systems that underpin a computation. We identify a class of geometry bugs that arise from confusing which coordinate system a vector belongs to. These bugs are not ruled out by current languages for vector-oriented computing, are difficult to check for at run time, and can generate subtly incorrect output that can be hard to test for. We introduce a type system and language that prevents geometry bugs by reflecting the coordinate system for each geometric object. A value's geometry type encodes its reference frame, the kind of geometric object (such as a point or a direction), and the coordinate representation (such as Cartesian or spherical coordinates). We show how these types can rule out geometrically incorrect operations, and we show how to use them to automatically generate correct-by-construction code to transform vectors between coordinate systems. We implement a language for graphics programming, Gator, that checks geometry types and compiles to OpenGL's shading language, GLSL. Using case studies, we demonstrate that Gator can raise the level of abstraction for shader programming and prevent common errors without inducing significant annotation overhead or performance cost.},
journal = {Proc. ACM Program. Lang.},
month = nov,
articleno = {173},
numpages = {25},
keywords = {computer graphics, geometry, language design, type systems}
}
@inproceedings{Siek2006GradualTF,
title={Gradual Typing for Functional Languages},
author={Jeremy G. Siek and Walid Taha},
year={2006},
url={https://api.semanticscholar.org/CorpusID:1398902}
}
@Book{Nystrom2021,
author = {Nystrom, Robert},
title = {{Crafting Interpreters}},
year = {2021},
publisher = {Genever Benning},
isbn = {978-0990582946},
pagetotal = {640},
url = {https://craftinginterpreters.com/},
added-at = {2025-04-07T18:48:41.000+0200},
biburl = {https://www.bibsonomy.org/bibtex/277c8c518a2426a59a8e4c3a720e60d23/gron},
interhash = {98f889463df208a828c08042cd116e94},
intrahash = {77c8c518a2426a59a8e4c3a720e60d23},
keywords = {AST Book Bytecode Interpreters Visitor},
month = {July},
timestamp = {2025-04-07T18:49:46.000+0200},
}
@Book{Householder1951,
author = {Householder, Alston S.},
title = {Monte Carlo Method},
year = {1951},
series = {Applied Mathematics Series},
number = {12},
note = {Proceedings of a symposium held June 29, 30, and July 1, 1949},
publisher = {U.S. Department of Commerce, National Bureau of Standards},
pages = {36},
address = {Washington, D.C.},
}
@Online{HOPL,
author = {Diarmuid Pigott},
title = {Online Historical Encyclopaedia of Programming Languages},
url = {https://hopl.info/},
language = {en},
urldate = {2026-07-13},
}
@Online{SO2025Survey,
title = {2025 Stack Overflow Developer Survey},
year = {2025},
url = {https://survey.stackoverflow.co/2025/technology#most-popular-technologies-language-language},
language = {en},
organization = {Stack Overflow},
urldate = {2026-07-13},
}
@Online{PythonGlossary,
title = {Python Glossary},
url = {https://docs.python.org/3/glossary.html#term-duck-typing},
language = {en},
urldate = {2026-07-13},
}
@TechReport{MCOReport,
author = {{{National Aeronautics and Space Administration}}},
title = {Mars Climate Orbiter Mishap Investigation Board - Phase I Report},
institution = {NASA Lessons Learned Information System},
year = {1999},
language = {en},
number = {641},
month = {11},
url = {https://llis.nasa.gov/lesson/641},
}
@Online{Pebble,
author = {Louis Heredero},
title = {Pebble},
year = {2026},
url = {https://git.kb28.ch/HEL/pebble},
language = {en},
}
@Misc{enwiki:1326872870,
author = {{Wikipedia contributors}},
title = {Definite assignment analysis --- {Wikipedia}{,} The Free Encyclopedia},
year = {2025},
note = {[Online; accessed 19-July-2026]},
url = {https://en.wikipedia.org/w/index.php?title=Definite_assignment_analysis&oldid=1326872870},
}
@Comment{jabref-meta: databaseType:biblatex;}

View File

@@ -0,0 +1,44 @@
#import "../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: todo
#import "../utils.typ": quote-block
= Introduction <chap:intro>
#quote-block[J. von Neumann @Householder1951][
Any one who considers arithmetical methods of producing random digits is, of course, in a state of sin
]
Dogs are often said to be man's best friend for their unwavering loyalty. As human beings, we thrive on patterns and predictability. On the other hand, our little animal friends can sometimes be irrational and surprise us with their unpredictable behavior. Computers however, these thought-less automatic machines made of metal, would be much better companions.
By their fundamental essence, computers and other similar machines are deterministic. As developers, we simply give them series of instructions, algorithms, functions and other scripts. Their one and only job is to execute our commands, one after the other, sometimes at the same time. An addition is always an addition, a byte is always a byte, and most importantly, a dog is always a dog.
When programming, developers use formal languages to instruct their devices to do particular tasks. Theses languages are designed to be unambiguous and generally explicit about what they describe. To the machine interpreting that written text, only one meaning is possible. "But", you may say, "sometimes there are bugs when I run my program". Of course, bugs are an inherent part of programming, but not because the machine might not understand you, because you explained it wrongly.
Errors and bugs are always caused by the human factor of computer science.#footnote[Notable exceptions are of course hardware failures which are a totally separate kind of issue]
Over the years, we have created a terrifyingly large number of programming languages#footnote[At least 8945 in 2005 according to the Historical Encyclopaedia of Programming Languages@HOPL] and developed countless tools to help developers avoid errors. Some are more famous than others, some are short-lived, and some remained obscure research projects which never made it out to the public.
While programming languages such as C and Java have long been some of the most popular among developers, another language seemed to have taken the lead in recent years. According to Stack Overflow's 2025 Developer Survey, Python is the most popular programming language among respondents, from beginners to professional developers.@SO2025Survey
Python is a very flexible scripting language, used in many fields, from small games, one-off data processing scripts and personal tooling to desktop applications and data processing pipelines. It is simple enough for beginners to easily learn it and play with it but highly expressive and with a rich ecosystem to build complex projects and production software.
One feature of Python that can be both a great benefit for lazy programmers or fast iteration, and a curse for safety and predictability is its use of duck typing. Duck typing is defined as "A programming style which does not look at an objects type to determine if it has the right interface; instead, the method or attribute is simply called or used"@PythonGlossary, applying the principle "If it looks like a duck and quacks like a duck, it must be a duck.", also known as the duck test.
Additionally, the Python language uses dynamic typing, a design principle allowing users to selectively type values, for example through type hints. These annotations are entirely optional in Python and have no direct runtime effect.#footnote[The only runtime consequence of adding annotations may be additional attributes to access them as strings at runtime] Their goal is to be interpreted by type checkers, like MyPy or Pyright, to verify a program's validity statically.
== Motivation
As explained above, Python is a very flexible language, sometimes too flexible. For beginners trying to learn programming, this can be a double-edged sword. One the one hand, the language is quite lenient and allows mixing data types, reusing variables with different types and passing values that are not at all what was expected by a function but still have the correct attributes or methods. On the other hand, it can lead to confusing behavior, when a parameter does not fit the developer's expectation or a variable is changed in some part of the code to a completely different kind of value. At the professional level, this can also prove dangerous. Mixing medical measurements or having a production service crash because of a type error can become an expensive mistake with real-world impact.
Secondly, as every Java developer can tell you, runtime errors are the worst. The dreaded `NullPointerException` continues to haunt many developers. Although some runtime errors like this are quite loud and can crash an hour-long computation process, others are much more subtle and tricky to catch. A famous example of this is the historical crash of NASA's Mars Climate Orbiter in 1999, which failed its orbital insertion due to a unit error mixing metric and imperial measurements.@MCOReport
Lastly, designing a safe code base and including tests to check that values conform to what is expected can be a tedious and often unrewarding process. Simplifying this process for user is one of the motivation for the famous Python library Pydantic, allowing users to define data structures that can validate inputs when instantiated.
== Objectives
In light of the various points exposed in the previous section, I set out to create a potential solution, a tool to help Python developers code more safely and avoid runtime type errors.
The general goal of this bachelor project is to create a type system on top of Python, using type hints, which can help detect non-trivial type errors (i.e. not necessarily structurally wrong, and also on complex types like dataframes), and produce runtime assertions to check type conformity where static checking is not possible.
The system should not impede on Python's dynamic typing philosophy. It should ensure soundness where types are annotated or inferred, while leaving the user free to omit some and perform unsafe operations.
It system must be flexible to allow checking various kinds of constraints (e.g. value domain, geometric shape, distribution, etc.) and allow extension to add support for more Python features and packages.
Finally, the system must be simple to use for average Python developers, and be able to seamlessly integrate into existing Python code.

View File

@@ -0,0 +1,21 @@
#import "../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: todo
= State of the Art <chap:state-of-the-art>
/*
- Python type hints (https://peps.python.org/pep-0484/):
- base types
- type aliases
- structural subtyping with Protocols -> matches duck-typing (https://peps.python.org/pep-0544/)
- Existing type checkers
- MyPy / Pyright
- Existing libraries
- Pandera: runtime only, syntax heavy, but quite complete
- Similar ideas
- Gator system (https://capra.cs.cornell.edu/research/gator/)
*/

View File

@@ -0,0 +1,244 @@
#import "../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: todo
#import "@preview/gentle-clues:1.3.1" as gc
#import "@preview/acrostiche:0.7.0": acr
#import "@preview/curryst:0.6.0": prooftree, rule
#import "03_theory/python_syntax.typ": python-syntax
#import "03_theory/midas_syntax.typ": midas-syntax
#import "03_theory/typing.typ"
= Underlying Theory and Typing Rules <chap:theory>
#gc.info[
This chapter presents some type theory notions that form the basis of a type checker and establishes some typing rules we would wish to implement for Python. The reader may skip this more theoretical chapter to the implementation in @chap:impl. These notions are only explained to justify some implementation decisions and provide a solid basis on which to build the type checker but are not strictly necessary to understand the concrete development.
]
The first step to build a useful type checker for Python is to identify the concrete requirements. By identifying what kind of expressions and relationships we are dealing with, we can then select the rules we need to define and handle, and implement appropriate solutions. The concepts and ideas covered in this chapter are mainly derived from the wonderful #acr("TaPL") by Benjamin C. Pierce. This books serves as a reference for all type theory notions presented in this report. This report does not intend to become the new #acr("TaPL").
== Principles <sec:theory-principles>
To talk about type theory and typing rules, we must first define some concepts. B. C. Pierce suggests one definition for type systems:
#quote(block: true)[
A type system is a tractable syntactic method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute.@tapl
]
At its core, a type system provides techniques to ensure the absence of unwanted behavior due to incompatibilities between value types. Although often associated with computer science and programming languages, the fundamental concept of a type system is a mathematical construct.
In the following sections, we will define both syntax rules, to lay out legal constructs in the languages, and typing rules, to build relationships and theorems in our type system.
Syntactically, we will use different kinds of elements, as described in @tab:calculus-elmts.
#figure(
table(
columns: 3,
table.header[*Element*][*Meta-variable*][*Description*],
[Terms], $"t"$, [Building blocks of the language, expressions which can be evaluated],
[Values], $"v"$, [Subset of terms, possible final results of evaluation],
[Statements], $"s"$, [Language constructs that do not evaluate to a value and may have side-effects],
[Types], $"T"$, [Category of values of the same kind],
),
caption: [Calculus elements]
) <tab:calculus-elmts>
A term $"t"$ is said to be of type $"T"$, written $"t": "T"$ if it can be statically proven that it evaluates to a value belonging to type $"T"$.
Additionally, we will need to define rules that link different types together in a compatibility relationship. For example, we can say that a car is a kind of vehicle. In this case, the type `Car` is said to be a "subtype" of `Vehicle`. This relationship is asymmetric and transitive, and is written $"S" <: "T"$ (read "S is a subtype of T").
Finally, because we are dealing with a complex programming language such as Python, we need to introduce the concept of a context. In Python, as in most other languages, users can define variables and functions taking named parameters. This fact means that evaluating an expression, or even typing it, requires knowing some things about the context of what comes before. Taking the example of @fig:example-context, we can see that evaluating or typing the expression `a + a` on line 2 requires knowing the type (or value) of `a`, which was set in a different statement on line 1.
#figure(
```python
a: float = 3
b = a + a
```,
caption: [Example Python expression requiring context]
) <fig:example-context>
The notations for context are as follows:
#align(center, grid(
columns: 2,
gutter: 1em,
align: (center, left),
$Gamma$,
[the context, a list of bindings, mapping terms to types],
$Gamma, "t": "T"$,
[the context extended with the binding of $"t"$ to the type $"T"$],
))
Finally, the rules expressed in @sec:theory-syntax are written in the form of theorems using the following mathematical syntaxes:
#align(center, grid(
columns: 2,
gutter: 1em,
align: (center, left),
prooftree(rule($P_1$, $...$, $P_n$, $C$)),
[Given premises $P_1, ..., P_n$, conclusion $C$ is true],
$Gamma tack P$,
[$Gamma$ "judges" that $P$ is true, i.e. $P$ is true given context $Gamma$],
$P tack.l Gamma'$,
[Evaluating $P$ produces the new context $Gamma'$]
))
== Syntax rules <sec:theory-syntax>
In this section, we define syntax rules for both Python and our type definition language Midas. Obviously, Python already has syntax rules defining what is or is not valid code. What is defined in @sec:theory-syntax-python are a subset of constructs which our type checker will be able to process.
=== Python syntax <sec:theory-syntax-python>
@tab:python-syntax-rules lists mosts Python constructs we want to support with our type checker (notable exceptions are listed below). This subset of the Python language is sufficient to express a wide range of programs, including data processing pipelines and moderately complex scripts.
#figure(
python-syntax,
caption: [Python syntax rules],
supplement: [Table],
kind: table,
) <tab:python-syntax-rules>
Some syntaxes are simplified or omitted from @tab:python-syntax-rules for the sake of conciseness, readability and scope. Indeed, this work's primary focus is not on the theoretical and formal approach to type checking but rather on the concrete application of it to produce a useful tool for developers. For example, function signature in Python are rather complex and flexible, allowing positional-only, keyword-only and mixed parameters, argument sinks, and default values. Expressing this level of flexibility in a formal definition as those presented above is tricky and not necessarily pertinent to this work.
Other syntaxes not referenced in this report are voluntarily left out because they either fall out of the scope of this work or are either not fundamental to the language or not necessary to most developers. Such constructs include classes, match statements, while loops, `for`/`else` blocks and the walrus operator~(`:=`).
=== Midas syntax <sec:theory-syntax-midas>
Our type system includes a dedicated language to define custom types that can be used in Python code. This language is hereafter referred to as the Midas language, or simply Midas. Its goal is to allow users to concisely define types, aliases, subtypes and the like in a simple and intuitive language. All syntax rules are listed in @tab:midas-syntax-rules.
#figure(
midas-syntax,
caption: [Midas syntax rules],
supplement: [Table],
kind: table,
) <tab:midas-syntax-rules>
Parameter specifications in function types and predicates are simplified here for conciseness. In actuality, the supported syntax is similar to Python's regarding positional-only, keyword-only and mixed arguments, with the following notable differences:
- the name of positional-only parameters is optional, i.e. `fn(float, /) -> bool` is valid
- default values are not supported but optional parameters may be indicated with a question mark (`?`) after the type, e.g. `fn(a: float?) -> bool`
A more detailed definition of the syntax is available in @app:midas-syntax.
Some elements are worth explaining here. Midas offers four base statements through four keywords: `alias`, `type`, `extend` and `predicate`.\
The first is rather straightforward: ```midas alias X = T``` defines an alias named `X` for the type `T`.\
The second is a simple subtype definition. ```midas type X = T``` is similar to an alias, but it creates a subtype relationship instead of an equivalence. `X` is thus a subtype of `T`. This also allows defining generic types using type parameters, bounded or not, which can be referenced in the right-hand side of the definition. For example ```midas type Foo[T <: U] = list[T]``` defines a type generic `Foo` with one parameter `T` subtype of `U`, which is a subtype of `list[T]`.\
The third, `extend`, is linked to a subtype definition. It allows users to define members on a type, such as properties/attributes (`prop`) and methods (`def`). Methods may be overloaded to combine multiple signatures under the same name. The type specific after `extend` must obviously be defined.\
The last kind of statement provides user with a way to define named constraint expressions and reuse them as functions in other constraint expressions. Predicates are defined like functions, with a list of parameters. This list may be split into multiple parameter specifications, for example ```midas predicate foo(a: float)(b: int) = a < b``` to allow partial application.
A particularity of Midas are its constraint types. A constraint type `T where e` is built from a base type `T` and a constraint expression `e`. It allows binding a constraint on the values belonging to this type, which will be materialized by assertions at runtime.
== Typing rules <sec:theory-typing>
Now that we have defined what Python syntax we will support and our own definition language, we need to define how our type checker will be able to bind types to Python expressions. This section is heavily inspired by the _Pure simply typed lambda-calculus~($lambda_->$)_, _Simply typed lambda-calculus with subtyping~($lambda_(<:)$)_, _Polymorphic lambda-calculus (System F)_ and _Bounded quantification (kernel $F_(<:)$)_ presented in Chapters 9, 15, 23 and 26 of #acr("TaPL")@tapl.
=== Literals <sec:typing-literals>
First and foremost, we can define elementary typing rules for all literal values. These rules having no premises, they are simple axioms. @tab:typing-literals lists all literal typing rules.
#figure(
typing.literals,
caption: [Typing rules: literals],
kind: table,
supplement: [Table],
) <tab:typing-literals>
Other constructs, although not constants, directly map to builtin types. These include literal lists, tuples and dictionaries. Each of these has a corresponding `list[T]`, `tuple` and `dict[K, V]` type. We will not define formal rules in this section regarding these elements, but a more in depth explanation will be given in the implementation of the type checker, in @sec:python-check-literals.
=== Expressions <sec:typing-expressions>
Apart from literals, developers also need some building blocks to express their programs. These expressions include variables, function calls, operations, etc. and need their own typing rules. The rules listed in @tab:typing-expressions cover most expressions we will handle, as defined in @sec:theory-syntax-python. Some syntaxes are omitted to keep this chapter short and because they don't necessarily bring new theoretical concepts.
#figure(
typing.expressions,
caption: [Typing rules: expressions],
kind: table,
supplement: [Table],
) <tab:typing-expressions>
#smallcaps[T-Var] simply states that a variable can be typed iff it is in the context.
#smallcaps[T-Call] is a simplified rule of the concrete behavior. Taking into account all call forms with positional and keyword arguments is a rather tedious process which is left as an exercise to the reader.
#smallcaps[T-Tern] is worth a few more words too. Typing rules used by Midas are, by design, stricter than what Python allows. In this case, because we have chosen not to include union types, an expression can only have at most one type, thus the branches must belong to a common type. The specific types of each branch may differ thanks to #smallcaps[T-Sub], defined in @tab:typing-subtyping-base. Additionally, the test expression must be of type $"bool"$, whereas Python can evaluate any object to a boolean.
#smallcaps[T-Op] is used for all binary operations. In Python, these are implemented in _dunder-methods_, such as `__add__` for the `+` operator. A similar rule could be defined for unary operations but is omitted here for brevity.
=== Statements <sec:typing-statements>
Finally, expressions can be used in statements, which are special constructs that can have side-effects. We listed in @sec:theory-syntax-python the particular statements that Midas should support, and @tab:typing-statements provides rules to type check their components and effects.
#figure(
typing.statements,
caption: [Typing rules: statements],
kind: table,
supplement: [Table],
) <tab:typing-statements>
#smallcaps[T-Annot] is a rule which handles Python type annotations. It states that the type checker must take note of type hints in the context.
#smallcaps[T-Assign] handles assignments to variables. For an assignment to be valid, the value must be of the same type as the variable's type (modulo subsumption, #smallcaps[T-Sub]).
#smallcaps[T-Seq] allows sequences of statements.
#smallcaps[T-IfElse], like #smallcaps[T-Tern] is a stricter version of how Python processes `if` statements. Indeed, Midas will not allow leaking context from inside the bodies of any branch. If a variable is declared inside an `if` statement, Midas will not allow references outside of it.
#gc.info[
You may be familiar with the walrus operator `:=` which is often used in `if` statements to simultaneously declare a variable and use it as an expression. It it thus a mix between a simple expression, which may be used everywhere, and a statement, with the side-effect of declaring a variable.
]
#smallcaps[T-Def] is a gross simplification of how functions can be defined. It does not cover multiple parameters, positional-only and keyword-only parameters, complex bodies with multiple and implicit returns, etc. Again, for the sake of simplicity and readability, we will not define a complete rule to handle all forms and features, but the implementation will go into more details in @sec:python-functions.
=== Subtyping <sec:typing-subtyping>
Similarly to some calculi described in #acr("TaPL")@tapl and to allow flexibility, we must equip our type system with a subtyping relationship. This relationship allows using some types in place of others where it is sound to do so. The subtyping rules presented in @tab:typing-subtyping-base cover the base cases of subtyping.
#figure(
typing.subtyping,
caption: [Typing rules: subtyping base],
kind: table,
supplement: [Table],
) <tab:typing-subtyping-base>
The subtyping relationship is by definition both reflective (#smallcaps[S-Refl]) and transitive (#smallcaps[S-Trans]).
#smallcaps[T-Sub] is a consequence of the #acr("LSP"). A term $"t"$ of type $"S"$ can be used anywhere a term of type $"T"$ is expected if $"S"$ is a subtype of $"T"$.
In addition to these base rules, we need to define how functions, constraint types and generic types are handled.
For constraint types, we will take the simple approach of considering only the base type for the subtype relationship. A more complete and interesting implementation could implement subtyping of constraint expression, where a condition such as `_ < 10` is a subtype of `_ < 100`, but the added complexity was deemed out of scope for this particular project. We do nonetheless define #smallcaps[S-Constr] in @tab:typing-subtyping-constraint to handle the base case.
#figure(
typing.subtyping-constraint,
caption: [Typing rules: subtyping constraint type],
kind: table,
supplement: [Table],
) <tab:typing-subtyping-constraint>
Generics are handled using similar rules to the _Bounded quantification (kernel $F_(<:)$)_ calculus presented in #acr("TaPL") Chapter 26@tapl. Additionally, Midas supports implicit variance, which is inferred from the locations in which type parameters are used, and is used when checking subtypes of applied generic types. A detailed explanation of variance inference is provided in the corresponding implementation section, @sec:variance-inference.
Finally, functions in Python are complex types. The general subtyping rule is given in @tab:typing-subtyping-function, but the complete set of rules for checking parameter specifications is too complex to include here. It is however detailed in @app:function-subtyping.
#figure(
typing.subtyping-function,
caption: [Typing rules: subtyping functions],
kind: table,
supplement: [Table],
) <tab:typing-subtyping-function>
=== Special types <sec:theory-special-types>
Two special types can be added to our type system for practical purposes. The first is a regular top type, as represented by `Any` in Python. Every type is a subtype of `Any`, as stated by #smallcaps[S-Any] in @tab:typing-subtyping-top.
In addition to `Any`, we will add a second top type to represent unknowns. When a user omits an annotation, the type checker can use this type as a placeholder to track that a particular expression was indeed processed but its type could not be determined. This has many practical benefits, among which avoiding early exits and propagating unknowns. Additionally, this allows the type checker to differentiate a variable which has specifically been typed as `Any`, and can contain _any_ kind of value, from a variable whose type the checker does not know.
#figure(
typing.subtyping-top,
caption: [Typing rules: subtyping top types],
kind: table,
supplement: [Table],
) <tab:typing-subtyping-top>
The special type `None`, also later referred to as `UnitType`, is used in Midas as a unit type, mapping Python functions' behavior regarding implicit returns.
/*
- Identify requirements
- Introduction to TAPL
- Grammar and typing rules for Midas, paralleled with TAPL
- Omitted rules, simplifications, mechanisms not implemented
*/

View File

@@ -0,0 +1,61 @@
#import "utils.typ": *
#let types = (
($"X"$, [_named type_]),
($"T" ["T"^(i in 1..n)]$, [_type application_]),
($"T" #syntax[where] "e"$, [_constraint type_]),
($#syntax[fn] (attach("a"_i: "T"_i, tr: i in 1..n)) -> "T"$, [_function type_]),
)
#let statements = (
($#syntax[alias] "X" = "T"$, [_alias definition_]),
($#syntax[type] "X" = "T"$, [_type definition_]),
($#syntax[type] "X"["P"^(i in 1..n)] = "T"$, [_generic definition_]),
($ cases(
#syntax[extend] "X"["P"^(i in 1..n)] space \{,
quad m^(j in 1..M),
\},
delim: "["
) $, [_generic definition_]),
($#syntax[predicate] "p" = "e"$, [_predicate alias_]),
($#syntax[predicate] "p" (attach("a"_i: "T"_i, tr: i in 1..n))^(j in 1..m) = "e"$, none),
($$, [_predicate definition_]),
)
#let type-parameters = (
($X$, [_type variable_]),
($X <: T$, [_bounded type\ variable_]),
)
#let member-statements = (
($#syntax[prop] x: T$, [_property_]),
($#syntax[def] x: T$, [_method_]),
)
#let expressions = (
($x$, [_variable_]),
($"i"$, [_integer literal_]),
($"f"$, [_float literal_]),
($"z"$, [_string literal_]),
($"True"$, [_constant true_]),
($"False"$, [_constant false_]),
($"None"$, [_constant none_]),
($f("t")$, [_call_]),
($"t"_1 "op" "t"_2$, [_operation_]),
($"t"."x"$, [_attribute_]),
($\_$, [_self reference_])
)
#let midas-syntax = grid(
columns: (1fr, 1fr),
gutter: 2em,
syntax-grid(
("T", "types", types),
("e", "expressions", expressions),
),
syntax-grid(
("s", "statements", statements),
("P", "type parameters", type-parameters),
("m", "member statements", member-statements),
),
)

View File

@@ -0,0 +1,68 @@
#import "utils.typ": *
#let terms = (
($"x"$, [_variable_]),
($"i"$, [_integer literal_]),
($"f"$, [_float literal_]),
($"z"$, [_string literal_]),
($"True"$, [_constant true_]),
($"False"$, [_constant false_]),
($"None"$, [_constant none_]),
($f("t")$, [_call_]),
($"t"_21 #syntax[if] "t"_1 #syntax[else] "t"_22$, [_ternary_]),
($"t"_1 "op" "t"_2$, [_operation_]),
($"t" [ "t" ]$, [_subscript_]),
($"t"."x"$, [_attribute_]),
)
#let values = (
($"i"$, [_integer literal_]),
($"f"$, [_float literal_]),
($"z"$, [_string literal_]),
($"True"$, [_constant true_]),
($"False"$, [_constant false_]),
($"None"$, [_constant none_]),
)
#let statements = (
($"t"$, [_expression_]),
($"s"; "t"$, [_inline sequence_]),
($ cases(
"s" #nl,
"s",
delim: "["
) $, [_multiline sequence_]),
($"x" = "t"$, [_assignment_]),
($"x": "T"$, [_variable declaration_]),
($ cases(
#syntax[def] f("x": "T") -> "T": #nl,
#tab "t" #nl,
delim: "["
) $, [_def_]),
($ cases(
#syntax[if] "t": #nl,
tab "s" #nl,
#syntax[else]: #nl,
tab "s" #nl,
delim: "["
) $, [_if / else_]),
($ cases(
#syntax[for] "x" #syntax[in] "t":#nl,
#tab "s",
delim: "["
) $, [_for loop_]),
($#syntax[return]$, [_bare return_]),
($#syntax[return] "t"$, [_value return_]),
)
#let python-syntax = grid(
columns: (1fr, 1fr),
gutter: 2em,
syntax-grid(
("t", "terms", terms),
("v", "values", values),
),
syntax-grid(
("s", "statements", statements),
),
)

View File

@@ -0,0 +1,206 @@
#import "@preview/curryst:0.6.0"
#import "utils.typ": *
#let rule(
name,
..premises,
conclusion,
python,
) = (
return (
name: name,
rule: curryst.prooftree(
curryst.rule(
..premises.pos(),
conclusion,
name: smallcaps[(#name)],
),
),
python: python,
)
)
#let literals-rules = (
rule(
"T-Int",
$Gamma tack "i": "int"$,
```py 12: int```
),
rule(
"T-Float",
$Gamma tack "f": "float"$,
```py 12.34: float```
),
rule(
"T-Str",
$Gamma tack "z": "str"$,
```py "foo": str```
),
rule(
"T-True",
$Gamma tack "True": "bool"$,
```py True: bool```
),
rule(
"T-False",
$Gamma tack "False": "bool"$,
```py False: bool```
),
rule(
"T-None",
$Gamma tack "None": "None"$,
```py None: None```
),
)
#let expressions-rules = (
rule(
"T-Var",
$"x": "T" in Gamma$,
$Gamma tack "x": "T"$,
```py x```,
),
rule(
"T-Call",
$Gamma tack f: "T"_1 -> "T"_2$,
$Gamma tack "t": "T"_1$,
$Gamma tack f("t"): "T"_2$,
```py
def func(a: S) -> T: ...
...
func(a): T
```,
),
rule(
"T-Tern",
$Gamma tack "t"_1: "bool"$,
$Gamma tack "t"_21: "T"$,
$Gamma tack "t"_22: "T"$,
$Gamma tack "t"_21 #syntax[if] "t"_1 #syntax[else] "t"_22: "T"$,
```py (true if cond else false): T ```,
),
rule(
"T-Op",
$Gamma tack "t"_1: "T"_1$,
$Gamma tack "t"_2: "T"_2$,
$"op": "T"_1 -> "T"_2 -> "T"_3 in Gamma$,
$Gamma tack "t"_1 "op" "t"_2: "T"_3$,
```py (a + b): T```,
),
)
#let statements-rules = (
rule(
"T-Annot",
$Gamma tack "x": "T" tack.l Gamma, "x": "T"$,
```py x: T```,
),
rule(
"T-Assign",
$Gamma tack "x": "T"$,
$Gamma tack "t": "T"$,
$Gamma tack "x" = "t" tack.l Gamma$,
```py x = t```,
),
rule(
"T-Seq",
$Gamma tack "s"_1 tack.l Gamma'$,
$Gamma' tack "s"_2 tack.l Gamma''$,
$Gamma tack "s"_1; "s"_2 tack.l Gamma''$,
```py a = 3; a: int```
),
rule(
"T-IfElse",
$Gamma tack "t": "bool"$,
$Gamma tack "s"_1 tack.l Gamma'$,
$Gamma tack "s"_2 tack.l Gamma''$,
$Gamma tack #syntax[if] "t": "s"_1 #syntax[else]: "s"_2 tack.l Gamma$,
```py
if cond:
...
else:
...
```,
),
rule(
"T-Def",
$Gamma, f: "T"_1 -> "T"_2, "x": "T"_1 tack "t": "T"_2$,
$ Gamma tack cases(delim: #none, #syntax[def] &f("x": "T"_1) -> "T"_2:, &#syntax[return] "t") space tack.l space Gamma, f: "T"_1 -> "T"_2 $,
```py
def func(a: S) -> T:
return ...: T
```,
),
)
#let subtyping-rules = (
rule(
"S-Refl",
$"S" <: "S"$,
none,
),
rule(
"S-Trans",
$"S" <: "U"$,
$"U" <: "T"$,
$"S" <: "T"$,
none,
),
rule(
"T-Sub",
$Gamma tack "t": "S"$,
$"S" <: "T"$,
$Gamma tack "t": "T"$,
none,
),
)
#let rules-grid(rules, columns: 1, large: false) = {
let cells = rules.map(
r => (r.rule, r.python)
).chunks(columns).flatten()
let header = ([*Rule*], [*Python example*]) * columns
grid(
columns: (auto, if large {1fr} else {auto}) * columns,
//row-gutter: 2em,
//column-gutter: 1em,
column-gutter: (0pt, 3em) * columns,
inset: (x:.5em, y: 1em),
align: (center+horizon, right+horizon),
//stroke: (x, _) => if calc.rem(x, 2) == 0 and x != 0 {(left: black)},
grid.header(..header),
..cells,
)
}
#let literals = rules-grid(literals-rules, columns: 2)
#let expressions = rules-grid(expressions-rules)
#let statements = rules-grid(statements-rules, large: true)
#let subtyping = curryst.rule-set(
..subtyping-rules.map(r => r.rule)
)
#let subtyping-constraint = curryst.prooftree(
curryst.rule(
$"S" <: "T"$,
$"S" #syntax[where] "e" <: "T"$,
name: smallcaps[(S-Constr)],
)
)
#let subtyping-function = curryst.prooftree(
curryst.rule(
$"S"_2 <: "S"_1$,
$"R"_1 <: "R"_2$,
$#syntax[fn] ("S"_1) -> "R"_1 <: #syntax[fn] ("S"_2) -> "R"_2$,
name: smallcaps[(S-Func)],
)
)
#let subtyping-top = curryst.rule-set(
curryst.prooftree(curryst.rule(
$"T" <: "Any"$,
name: smallcaps[(S-Any)],
)),
curryst.prooftree(curryst.rule(
$"T" <: "Unknown"$,
name: smallcaps[(S-Unknown)],
)),
)

View File

@@ -0,0 +1,48 @@
#let syntax(body) = {
set text(weight: "bold", fill: rgb(100, 50, 0))
body
}
#let blank(r, c) = grid.cell(
rowspan: r,
colspan: c
)[]
#let tab = sym.arrow.r.stop
#let nl = move(dx: -2pt, dy: 2pt, sym.arrow.curve.l)
#let syntax-preamble = doc => {
show tab: set text(fill: gray.darken(20%))
show sym.arrow.curve.l: set text(fill: gray.darken(20%))
set math.cases(gap: 4pt)
show math.equation: set align(left)
doc
}
#let syntax-grid(..sections) = {
let cells = ()
for (i, (meta-var, name, elements)) in sections.pos().enumerate() {
if i != 0 {
cells.push(grid.cell(colspan: 4)[])
}
cells += ($#meta-var$, $::=$, none, [_#{name}_])
cells.push(blank(elements.len(), 2))
cells += elements.map(
e => if e.last() == none {
grid.cell(colspan: 2, e.first())
} else {
e
}
).flatten()
}
show: syntax-preamble
grid(
columns: (auto, auto, 1fr, auto),
align: (left, left, left, right).map(a => a + horizon),
column-gutter: .4em,
row-gutter: 1.2em,
..cells,
)
}

View File

@@ -0,0 +1,39 @@
#import "../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: todo
#import "../utils.typ": include-offset
#import "@preview/acrostiche:0.7.0": acr
#import "@preview/gentle-clues:1.3.1" as gc
#import "../../meta.typ"
= Implementation <chap:impl>
Now that we have chosen a subset of Python to support and some type checking rules, we may start implementing the type checker itself. We will split the implementation into three relatively independent parts: the Midas language (parsing and registering types), type checking Python and the generator (to output runnable code with runtime assertions).
The Python language has been chosen for implementing the type checker for several reasons. First, the student was already greatly familiar with that language and its environment. Secondly, as stated in the introduction, Python is a highly versatile tool which is particularly good at manipulating data, and is easy to iterate with. Then, the student had already implemented a simple interpreter which could be reused and adapted for Midas, as explained in @sec:impl-midas. Finally, Python already provides an `ast` module in its standard library to parse and unparse Python source code, and manipulate its #acr("AST") nodes.
In @sec:impl-overview, we will first look at the whole system from a top-down perspective to locate its components and get a feel of how they connect to each other.
#gc.info[
This chapter contains many references to the project's source code, which is available in the repository at #link(meta.project-repos).\
Additionally, a mirror is also available on GitHub at #link(meta.mirror-repo).
]
#pagebreak()
#include-offset(path("04_implementation/01_overview.typ"))
#include-offset(path("04_implementation/02_types.typ"))
#include-offset(path("04_implementation/03_registry.typ"))
#include-offset(path("04_implementation/04_midas_language.typ"))
#include-offset(path("04_implementation/05_python_checking.typ"))
#include-offset(path("04_implementation/06_generation.typ"))
/*
Subjects:
- Variance inference
- Environment
- Resolver
- Evaluator
- CallDispatcher
- Registry (`is_subtype`)
- MethodRegistry (frames and columns)
*/

View File

@@ -0,0 +1,33 @@
#import "../../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: todo
#import "../../figs/architecture.typ"
#import "@preview/acrostiche:0.7.0": acr
= Architecture Overview <sec:impl-overview>
Our type checker is composed of several interdependent elements shown in @fig:architecture. At its core, there is a type registry which holds a list of all registered types. This registry is initialized with builtin types, like `float` and `str`, and can be further populated by user definitions written in the Midas language. Finally, it is used when type checking the Python source code based on the type checking rules we defined in @sec:theory-typing.
#figure(
architecture.overview,
caption: [Implementation Architecture Overview],
kind: image,
supplement: [Figure],
) <fig:architecture>
The different components have the following responsibilities:
/ Midas Typer: Take in a Midas definition file or some source code, parse it, process each statement and register new types in the registry. It must also check references between types and provide users with diagnostics in case of errors.
/ Python Typer: Take in a Python file or some source code, parse it, walk through each statement and expression, take note of type hints and otherwise infer types if possible, detect any incompatibilities, i.e. type errors and report them to the user.
/ Types Registry: Hold a registry of existing types (builtin or user-defined) and predicates, provide a method to check subtyping according to our rules (i.e. `is_subtype(type1, type2)`) and provide some methods to register, lookup and manipulate types.
/ Generator: Take in a Python #acr("AST"), type judgments (i.e. conclusions of the type checker) and the registry to produce new Python code with assertions that check types at runtime where necessary as well as constraint predicates.
Apart from the types registry, another component will be used across the whole system which is not shown in @fig:architecture: the reporter. The reporter is a simple object that will collect all diagnostics produced at different steps of the process. That includes syntax errors in Midas files, unknown references, type errors and more.
/*
- Main elements
- Definition language
- Supported Python syntax (cf. grammar and typing rules)
- Parse and type check
- Produce user-facing diagnostics
- Generate runtime assertions
- Architecture overview
*/

View File

@@ -0,0 +1,151 @@
#import "../../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: todo
#import "../../utils.typ": fn-link, code-ref
#import "@preview/acrostiche:0.7.0": acr
= Internal Type Representations <sec:impl-types>
Before we can parse type definitions or type check Python code, we need to define structures to represent our types.
In our type system, we will indeed have different kinds of types with different properties. All types described in this section are grouped under a union type named `Type` for easier references in annotations. Additionally, we will later need to define some basic functions to manipulate types, for example to substitute parameters in a generic type. These functions will be introduced where needed in later sections. The source code for internal type representations and these basic functions is available in the repository in #code-ref(<types>, "midas/checker/types.py").
== Base Types
The simplest types are those at the root of the type lattice with no or few properties. These include top-types like `Any`, `UnknownType` and `UnitType`/`None`, as described in @sec:theory-special-types, which can be represented as simple empty classes like in @fig:types-base-types. Builtin types also have a dedicated `BaseType` kind which holds the type's name.
For the special `tuple` type, we can define a more specific class which can hold the each item's type. This will allow nice type checking of subscript expressions for example.
#figure(
```python
class TopType: ...
class UnknownType: ...
class UnitType: ...
class BaseType:
name: str
class TupleType:
items: tuple[Type, ...]
```,
caption: [Type kinds: base types]
) <fig:types-base-types>
== Derived Types
When defining subtypes in Midas, we will need to store that link in the registry. There are multiple approaches to subtyping, which can either be nominal or structural. In the case of Midas, we will generally stick to nominal subtyping, i.e. subtypes are explicitly defined, with some exceptions like constraint types and function types, as described in @sec:typing-subtyping.
Instead of storing the subtype relationship in a separate registry, we will embed it in the type itself by using a `DerivedType` class containing the type's name and super-type. This allows easy pattern matching without additional queries to the registry, and keeps the type hierarchy clear and explicit.
A similar approach is used for constraint types, by embedding the base type and the constraint expression in the same `ConstraintType` object, as shown in @fig:types-derived-types.
#figure(
```python
class DerivedType:
name: str
type: Type
class ConstraintType:
type: Type
constraint: m.Expr
```,
caption: [Type kinds: derived types]
) <fig:types-derived-types>
== Generic Types
To define generic types, we first need type variables, which are kinds of placeholder types. These type variables have a name, an optional bounding type and a variance. The latter can be represented as a simple enum. As explained in @sec:typing-subtyping, variance is inferred rather than explicitly annotated by the user. This inference process is described in @sec:variance-inference.
Once type variables are defined, generic types are simply a kind of derived type with a list of parameters.
We also need to define an application counterpart to represent a generic type that has been instantiated with some concrete type arguments. Here, the choice of having this `AppliedType` kind instead of simply using the generic's body with its parameters substituted has been made for multiple reasons. Most importantly, it allows diagnostics to be more specific and informative and eases some comparisons between different applied types.
These types are implemented by the classes in @fig:types-generics.
#figure(
```python
class Variance(StrEnum):
INVARIANT = "INVARIANT"
COVARIANT = "COVARIANT"
CONTRAVARIANT = "CONTRAVARIANT"
class TypeVar:
name: str
bound: Optional[Type]
variance: Variance = Variance.INVARIANT
class GenericType:
name: str
params: list[TypeVar]
body: Type
class AppliedType:
name: str
args: list[Type]
body: Type
```,
caption: [Type kinds: generic types]
) <fig:types-generics>
== Function Types
As noted in the theory chapter (@chap:theory), functions in Python are complex and highly flexible.
A function type thus have a parameter specification and a return type. That parameter specification contains three kinds of parameters: positional-only (`pos`), keyword-only (`kw`) and mixed (`mixed`).
@fig:types-functions shows the implemented structures to handle function types and their parameters.
For simplicity, each parameter will store both its position and name, as well as its type and a flag indicating whether it is required or not (e.g. parameters with default values are optional). You may notice an additional `unsupported` flag in @fig:types-functions:10, which is added for some dataframe-related methods. More information shall be given in @sec:impl-python #todo[replace ref].
Finally, we will also define a structure to hold multiple signature of an overloaded function because it cannot be represented as a single `Function`. You may also notice that `OverloadedFunction.overloads` does not store a list of `Function` but simply a list of `Type`, in @fig:types-functions:16. This allows the use of generic functions, which are `Function` types wrapped inside a `GenericType`.
#figure(
```python
class Function:
params: ParamSpec
returns: Type
class Parameter:
pos: int
name: str
type: Type
required: bool
unsupported: bool = False
class ParamSpec:
pos: list[Function.Parameter] = field(default_factory=list)
mixed: list[Function.Parameter] = field(default_factory=list)
kw: list[Function.Parameter] = field(default_factory=list)
class OverloadedFunction:
overloads: list[Type]
```,
caption: [Type kinds: function types]
) <fig:types-functions>
== Dataframe types
Because Midas has been designed with data scientists in mind, it will also try and type check some common dataframe operations. To do so, we want the user to be able to define dataframe schemas and use their columns. We thus define `ColumnType` and `DataFrameType` in @fig:types-dataframes, which can be thought of as more abstract representations of Pandas' `Series` and `DataFrame`. Additionally, we define special objects to handle group-by entities which are intermediary values used when computing aggregations. These group-by types are necessary to distinguish them from the base dataframe or column because they provide different methods.
#figure(
```python
class ColumnType:
type: Type
class DataFrameType:
columns: list[Column]
class Column:
index: int
name: Optional[str]
type: ColumnType
class FrameGroupBy:
frame: DataFrameType
class ColumnGroupBy:
column: ColumnType
```,
caption: [Type kinds: dataframe types]
) <fig:types-dataframes>
== Predicates
Although not types, predicates will also be represented by similar dataclasses in the types registry, as defined in @fig:types-predicate.
#figure(
```python
class Predicate:
type: Type
body: m.Expr
alias: bool
```,
caption: [Predicate Dataclass]
) <fig:types-predicate>
This class holds three properties of predicates:
- `type`: the function signature of the predicate.\
For example, ```midas predicate less_than(max: float)(v: float) = v < max``` has the signature ```midas fn(max: float) -> fn(v: float) -> bool```
- `body`: the raw predicate expression. This will be used to generate equivalent Python code and perform static checks against literal values
- `alias`: a flag indicating whether a predicate is a simple alias of another, used for example with partially applied predicates (see @sec:midas-predicate-stmt)

View File

@@ -0,0 +1,340 @@
#import "../../utils.typ": code-ref
#import "@preview/codly:1.3.0": codly
#import "../../appendices/is_subtype.typ": is-subtype-code, is-func-subtype-code
= Types Registry <sec:impl-registry>
With structures to represent our types, we now need to implement the registry which hold all builtin and user-defined types, as well as named predicates. As a reminder of requirements given in @sec:impl-overview, the registry must also provide a method `is_subtype` to check whether according to our subtyping rules one type is subtype of another, a method to register a type with a name, a method to lookup a type given a name, and some methods to manipulate types, such as instantiating a generic type given some arguments. We will also registration and lookup methods for predicates, as well as for type members (defined in `extend` statements).
@fig:registry-contract shows the minimal contract our registry must satisfy.
#figure(
```python
class TypesRegistry:
def get_type(self, name: str) -> Type: ...
def define_type(self, name: str, type: Type): ...
def define_member(
self,
type_name: str,
member_name: str,
member_type: Type,
kind: MemberKind,
): ...
def define_predicate(self, name: str, predicate: Predicate): ...
def is_subtype(self, type1: Type, type2: Type) -> bool: ...
def apply_generic(self, type: Type, args: list[Type]) -> Type: ...
def lookup_member(self, type: Type, member_name: str) -> Optional[Type]: ...
def lookup_predicate(self, name: str) -> Optional[Predicate]: ...
```,
caption: [Minimal Registry Contract]
) <fig:registry-contract>
The `define_*` and `lookup_*`/`get_*` methods are quite straightforward, inserting and querying an internal dictionary with some added safeguards and errors to prevent redefining an entity or handle undefined references. Additionally, `define_member` handles overriding methods by wrapping multiple method definitions with the same member name inside an `OverloadedFunction` type. This process is detailed in @sec:define_member hereafter. The complete implementation of `TypesRegistry` is available in the repository in #code-ref(<types-registry>, "midas/checker/registry.py")
== `define_member` <sec:define_member>
#figure(
```python
def define_member(
self,
type_name: str,
member_name: str,
member_type: Type,
kind: MemberKind,
):
members: dict[str, Member] = self._members.setdefault(type_name, {})
if member_name in members:
current: Member = members[member_name]
if current.kind != kind:
self.logger.error(
f"Member '{member_name}' is already defined as a {current.kind},"
+ f" cannot define a {kind} with the same name"
)
return
if kind != MemberKind.METHOD:
self.logger.error(
f"Member '{member_name}' already defined for type {type_name},"
+ " only methods can be overloaded"
)
return
combined: Type
match current.type:
case OverloadedFunction(overloads=overloads):
combined = OverloadedFunction(overloads=overloads + [member_type])
case _:
combined = OverloadedFunction(overloads=[current.type, member_type])
members[member_name] = Member(kind=current.kind, type=combined)
else:
members[member_name] = Member(kind=kind, type=member_type)
```,
caption: [Implementation of `TypesRegistry.define_member`]
) <fig:define_member>
First in @fig:define_member:8, we retrieve the dictionary of all members defined for the given type, and check wether a member is already defined with the given name in @fig:define_member:9. If that is the case, we check whether the kind is equal; we avoid registering a method with the same name as a property and vice-versa. The current implementation simply ignores such definitions but an error could also be raised to be more explicit to the user.
A second check in @fig:define_member:17 avoid redefining a member which is not a method (i.e. a property). If we are redefining a method, an `OverloadedFunction` is then built to combine already defined signatures with the new one, as implemented in @fig:define_member:24 to @fig:define_member:29.
== `lookup_member`
`lookup_member` also needs some logic to handle each kind ot types. Indeed, looking up a member on a type (e.g. when processing an attribute reference expression like `foo.bar`), it may be defined in any of the type's supertypes too. Thus the method needs to recurse in the hierarchy if the member cannot be found directly on the requested type.
#figure(
```python
def lookup_member(self, type: Type, member_name: str) -> Optional[Type]:
match type:
case BaseType(name=name):
if name in self._members:
if member_name in self._members[name]:
return self._members[name][member_name].type
return None
case DerivedType(name=name, type=base):
if name in self._members:
if member_name in self._members[name]:
return self._members[name][member_name].type
return self.lookup_member(base, member_name)
case AppliedType(name=name, body=body, args=args):
generic: Type = self.get_type(name)
if not isinstance(generic, GenericType):
raise ValueError("AppliedType not derived from a GenericType")
substitutions = {
type_var.name: arg for arg, type_var in zip(args, generic.params)
}
if name in self._members:
if member_name in self._members[name]:
member_type: Type = self._members[name][member_name].type
return substitute_typevars(member_type, substitutions)
member_type2: Optional[Type] = self.lookup_member(body, member_name)
if member_type2 is not None:
member_type2 = substitute_typevars(member_type2, substitutions)
return member_type2
case ConstraintType(type=base):
return self.lookup_member(base, member_name)
case TypeVar(bound=bound) if bound is not None:
return self.lookup_member(bound, member_name)
case UnknownType():
return UnknownType()
case _:
self.logger.debug(f"Can't get member on {type}")
return None
```
) <fig:lookup_member>
Because we defined our internal type representations with dataclasses, we can easily leverage Python's pattern-matching capabilities to handle each case, as shown in @fig:lookup_member. The method is also quite straightforward though two things can be noted. The first is that looking up a member on `UnknownType` returns `UnknownType`. This basically tells the registry to go along with any references to unknown types, trusting the user that what they are doing is correct. It also allows gracefully propagating errors to avoid early returns that could be caused by raising an exception. The second important part of `lookup_member` is how `AppliedType` is handled. Since this type is derived from a generic type, its members may contain type variables. These are substituted lazily when referenced, i.e. in this method. `substitute_typevars` is a method which performs this substitution recursively given a mapping of type parameters to concrete type arguments. Its implementation is available in the repository in #code-ref(<substitute_typevars>, "midas/checker/types.py").
== `apply_generic`
`apply_generic` is a simple method which builds an `AppliedType` from a `GenericType` and a list of type arguments. This method is used when processing expressions such as `Foo[Bar]` and is implemented using the aforementioned `substitute_typevars`. Moreover, it checks potential bounds of type parameters. It is also used for the special `TupleType` which is constructed as `tuple[Type1, Type2, ...]`, as shown in @fig:apply_generic.
#figure(
```python
def apply_generic(self, type: Type, args: list[Type]) -> Type:
match type:
case DerivedType(name=name, type=base):
return DerivedType(name=name, type=self.apply_generic(base, args))
case GenericType(name=name, params=type_vars, body=body):
n_args: int = len(args)
n_type_vars: int = len(type_vars)
if n_args < n_type_vars:
raise ValueError(
f"Missing type arguments, expected {n_type_vars} but only {n_args} provided"
)
if n_args > n_type_vars:
raise ValueError(
f"Too many type arguments, expected {n_type_vars} but {n_args} provided"
)
substitutions: dict[str, Type] = {}
for arg, type_var in zip(args, type_vars):
if type_var.bound is not None and not self.is_subtype(
arg, type_var.bound
):
raise ValueError(
f"Type argument {arg} is not a subtype of {type_var.bound}"
)
substitutions[type_var.name] = arg
return AppliedType(
name=name,
args=args,
body=substitute_typevars(body, substitutions),
)
case BaseType(name="tuple"):
return TupleType(items=tuple(args))
case _:
raise ValueError(f"{type} is not a generic type")
```,
caption: [Implementation of `TypesRegistry.apply_generic`]
) <fig:apply_generic>
The first case handling `DerivedType`, @fig:apply_generic:3 to @fig:apply_generic:4, is a kind of syntactic sugar to define subtypes of generic types without redefining and forwarding type parameters, as demonstrated in @fig:generic-subtype.
#figure(
```midas
type Foo[T] = T
type Bar1[T] = Foo[T]
// is functionally equivalent to
type Bar2 = Foo
```,
caption: [Generic subtype syntactic sugar]
) <fig:generic-subtype>
== `is_subtype` <sec:is_subtype>
This method is one of the central parts of our type system. Its role is simple: judge, according to the rules we defined in @sec:typing-subtyping (and some we skipped), whether a given type (`type1`) should be considered a subtype of another (`type2`).
We will first look at the simplest cases and work our way up to the more complex ones. The complete implementation of `is_subtype` is given in @fig:is_subtype#footnote[The order of cases is slightly different from the real implementation for grouped presentation purposes].
The trivial case where `type1` is the same as `type2` can be handled with a simple equality check, which is implemented by the `dataclasses` module (#smallcaps[S-Refl] in @tab:typing-subtyping-base). This is the first check in the method, as shown in @fig:is_subtype-equal.
#codly(
range: (1, 3),
smart-skip: true
)
#figure(
is-subtype-code,
caption: [`is_subtype`: equal types]
) <fig:is_subtype-equal>
Even if the types differ, some cases such as top types are still trivially handled. If `type2` is a top type, `type1` is by definition a subtype (#smallcaps[S-Any] and #smallcaps[S-Unknown] in @tab:typing-subtyping-top).
#codly(
ranges: ((5, 10), (71, 71)),
smart-skip: true
)
#figure(
is-subtype-code,
caption: [`is_subtype`: top types]
) <fig:is_subtype-top>
For builtin types, we define some hardcoded subtype relationships, which are checked if both types are instances of `BaseType`. It may happen one or both of the types are type variables. If that is the case and the type variable has a bound, we may recursively check the subtype relationship against the bound. If not, we cannot make any assumption about the type of the variable and must return `False`. @fig:is_subtype-base-vars shows how both these cases are handled.
#codly(
range: (12, 23),
smart-skip: true
)
#figure(
is-subtype-code,
caption: [`is_subtype`: builtins and type variables]
) <fig:is_subtype-base-vars>
Then we have two similar kinds of types. First, `DerivedType` which encode an explicit subtype relationship, and `ConstraintType` which contain a base type and a constraint. To check these, we simply call `is_subtype` on the base type recursively. The latter corresponds to #smallcaps[S-Constr] in @tab:typing-subtyping-constraint. Note that we only consider `type1`, and not `type2`. The reason we only recurse on the potential subtype is that we are checking whether `type2` is in the hierarchy _above_ `type1`, i.e. a supertype. Because we don't allow multiple inheritance, the type lattice is basically a tree (in the graph theory sense) and a supertype must be in the same branch. This recursion process is an application of #smallcaps[S-Trans] (see @tab:typing-subtyping-base), which should either converge at one of the simpler cases described above or converge at a negative result if the subtype relationship cannot be verified (i.e. not subtyping rule was matched).
The implementation shown in @fig:is_subtype-derived-constr is a straightforward application of these rules.
#codly(
range: (25, 29),
smart-skip: true
)
#figure(
is-subtype-code,
caption: [`is_subtpye`: derived and constraint types]
) <fig:is_subtype-derived-constr>
Special care must be taken when comparing two `AppliedType`, that is, instances of generic types.
For $"T"_1["A"_11, "A"_12, ...] <: "T"_2["A"_21, "A"_22, ...]$ to be true, $"T"_1$ and $"T"_2$ must first refer to the same generic type. If they are, we must then check that each pair of arguments $("A"_11, "A"_21), ("A"_12, "A"_22), ..$ respect the variance of corresponding type parameters. This means that for a given triplet $("A"_1, "A"_2, "P")$, where $"A"_1$ and $"A"_2$ are paired arguments of `type1` and `type2`, and $"P"$ is the matching type parameter of the generic type:
- if $"P"$ is _covariant_, we must check that $"A"_1 <: "A"_2$
- if $"P"$ is _contravariant_, we must check that $"A"_2 <: "A"_1$
- if $"P"$ is _invariant_, we must check both conditions
This verification is implemented as in @fig:is_subtype-applied-type.
#codly(
range: (31, 50),
smart-skip: true
)
#figure(
is-subtype-code,
caption: [`is_subtype`: applied types]
) <fig:is_subtype-applied-type>
The second case simply handles other situations where `type1` is an `AppliedType`, recursively checking its body against `type2` similarly to derived types.
Only three rules remain to check for dataframes, columns and most importantly functions.
Columns are simply regarded as invariant generic types. They are not implement using a regular `GenericType`/`AppliedType` because it makes many mechanisms much simpler to implement and reason about, especially regarding attributes and methods, which is worth making them a special construct.
For dataframes, another approach is taken: structural subtyping. What this means in our type checker is that a dataframe is considered a subtype of another if it has at least the same columns (by name) as the supertype, and they are compatible (i.e. columns of `type1` are subtypes of `type2`'s). This idea has some benefits and drawbacks.
Starting with the negative, allowing `type1` to have more columns than `type2` could have a runtime impact. For example, if a function iterates over the columns or applies an operation which is not compatible with one of the extra columns, runtime behavior would not match the type checker's expectations. On the other hand, this allows much more flexibility for users who can pass whole dataframe to function which only need a subset of columns.
A potential solution not explored in this work could be to add a dedicated type, construct or syntax for explicit structural subtyping.
Finally, as shown in @fig:is_subtype-df-cols-funcs, functions are checked separately. Indeed, the algorithm as described in @tab:typing-subtyping-function and @app:function-subtyping is too complex to inline in this method. The implementation is discussed in @sec:is_func_subtype.
#codly(
range: (51, 69),
smart-skip: true
)
#figure(
is-subtype-code,
caption: [`is_subtype`: dataframes, columns and functions]
) <fig:is_subtype-df-cols-funcs>
== `is_func_subtype` <sec:is_func_subtype>
This section describes the implementation of the function subtyping verification algorithm. Please refer to @app:function-subtyping for more information on the underlying theory and formal rules.
The complete implementation of `is_func_subtype` is given in @fig:is_func_subtype.
The first thing `is_func_subtype` must check is whether the return types of the given functions are subtypes of one another (see #smallcaps[S-Func] in @tab:typing-subtyping-function). A simple early return can be added right at the beginning of the method, as shown in @fig:is_func_subtype-returns.
#codly(
range: (1, 3),
smart-skip: true
)
#figure(
is-func-subtype-code,
caption: [`is_func_subtype`: check return types]
) <fig:is_func_subtype-returns>
As we will need to get parameters of each function by kind, name and position, we will first extract the different lists and dictionaries in short variables as outlined in @fig:is_func_subtype-extract-params. These correspond to $(P_1, M_1, K_1)$ and $(P_2, M_2, K_2)$ in the theoretical description.
#codly(
range: (5, 22),
smart-skip: true
)
#figure(
is-func-subtype-code,
caption: [`is_func_subtype`: extracting parameters]
) <fig:is_func_subtype-extract-params>
We first check that `func2`'s positional- and keyword-only parameters are appropriately covered by `func1`. We also record parameter matches to later check subtyping between them and additional parameters of `func1`.
@fig:is_func_subtype-pos-kw shows how this is implemented with simple loops.
#codly(
range: (24, 52),
smart-skip: true
)
#figure(
is-func-subtype-code,
caption: [`is_func_subtype`: checking positional- and keyword-only parameters]
) <fig:is_func_subtype-pos-kw>
Verifying proper coverage of mixed arguments is slightly more complicated but a similar method can be used to implement the theoretical algorithm, such as in @fig:is_func_subtype-mixed.
#codly(
range: (54, 80),
smart-skip: true
)
#figure(
is-func-subtype-code,
caption: [`is_func_subtype`: checking mixed parameters]
) <fig:is_func_subtype-mixed>
Finally in @fig:is_func_subtype-extra-subtypes, we check that `func1` does not introduce new required parameters and that matching parameters respect contravariance.
#codly(
range: (82, 98),
smart-skip: true
)
#figure(
is-func-subtype-code,
caption: [`is_func_subtype`: check extra parameters and subtypes]
) <fig:is_func_subtype-extra-subtypes>

View File

@@ -0,0 +1,437 @@
#import "../../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: todo
#import "../../utils.typ": fn-link, code-ref
#import "@preview/acrostiche:0.7.0": acr
#import "../../appendices/midas_typer_skeleton.typ": midas-typer-members-code
#import "@preview/codly:1.3.0": codly
= Midas Definition Processing <sec:impl-midas>
For maximum flexibility and control over the whole process, it has been chosen to implement a custom parser for the Midas language from scratch. Moreover, the student already had some experience in implementing a parser and interpreter. Thus, most of the lexer and parser logic implemented in this section has been adapted from the student's previous #fn-link(<pebble-fn>, "https://git.kb28.ch/HEL/pebble")[pebble] project, which is itself based on the wonderful _Crafting Interpreters_ by Robert Nystrom@Nystrom2021.
Processing a Midas definitions file is done in 3 steps:
+ lexing, i.e. turning raw text bytes into tokens
+ parsing, i.e. assembling tokens into an #acr("AST") according to syntax rules defined in @sec:theory-syntax-midas (and @app:midas-syntax)
+ typing, i.e. processing each statement, registering types and predicates in the registry
Each of these steps map to a dedicated class, respectively `MidasLexer`, `MidasParser` and `MidasTyper`.
== Lexing and parsing <sec:midas-lexing-parsing>
The lexer and parser follow the structure presented by Nystrom@Nystrom2021 and implemented in #fn-link(<pebble-fn>, "https://git.kb28.ch/HEL/pebble")[pebble]@Pebble.
Concretely, the lexer scans the source code character by character and produces tokens. Several token types are defined to cover all needs in Midas, such as operators, identifiers, keywords and punctuation. The full list of token types is included in @tab:token-types. Whitespace and comments are also converted to tokens but are ignored by the parser. Each token, as represented by the class shown in @fig:token-class, has a token type, a lexeme (i.e. the raw characters making up that token) and a position. That position is crucial for reporting diagnostics as it allows precisely showing the user where an error is in the source file. Tokens representing literals also contain their literal value, like strings, numbers and constants.
#figure(
```python
class Token:
type: TokenType
lexeme: str
value: Any
position: Position
class Position:
file: Optional[str]
line: int
column: int
```,
caption: [`Token` and `Position` classes]
) <fig:token-class>
`MidasLexer` has a simple constructor taking in a source code string and optional file path, and a concise `process` method returning a list of tokens, as shown in @fig:lexer-signatures.
#figure(
```python
class MidasLexer:
def __init__(self, source: str, file: Optional[str] = None) -> None: ...
def process(self) -> list[Token]: ...
```,
caption: [Constructor and main method signatures of `MidasLexer`]
) <fig:lexer-signatures>
The parser receives this list of tokens and produces a sequence of statements. All #acr("AST") nodes are defined using frozen dataclasses, which are similar to Java's records. Like Nystrom's implementation, #acr("AST") classes are generated from a template using a script. This script also generates a visitor interface including methods for each node type. The script is available in the repository in #code-ref(<gen-script>, "gen/gen.py").
The Midas language uses three kinds of nodes:
- Statements (`Stmt`): top-level constructs introduced by keywords, have side-effects in the registry
- Expressions (`Expr`): composable building blocks for constraint expressions
- Types (`Type`): type constructors and references
The full list of #acr("AST") nodes used for Midas is available in @tab:midas-ast-nodes and their concrete implementation in the repository in #code-ref(<midas-ast>, "midas/ast/midas.py").
Like tokens, each node also keeps track of its location. The location object contains a starting position and an optional ending position, given by the starting and end token covered by the node. @fig:node-location shows the simple dataclass that is used to hold this information.
#figure(
```python
class Location:
lineno: int
col_offset: int
end_lineno: Optional[int]
end_col_offset: Optional[int]
```,
caption: [#acr("AST") node location class]
) <fig:node-location>
The complete implementations of `MidasLexer` and `MidasParser` are available in the project's repository in the following files:
- `MidasLexer`: #code-ref(<midas-lexer>, "midas/lexer/midas.py")
- `Lexer` (base class): #code-ref(<lexer>, "midas/lexer/base.py")
- `MidasParser`: #code-ref(<midas-parser>, "midas/parser/midas.py")
- `Parser` (base class): #code-ref(<parser>, "midas/parser/base.py")
Let's take a simple example of some Midas source code to highlight the different steps of the process:
#figure(
```midas
type Kelvin = float where _ >= 0
```,
caption: [Midas Example: source code]
) <fig:example-midas-src>
@fig:example-midas-src is first passed through the lexer which outputs a sequence of tokens, as shown in @fig:example-midas-tokens.
#figure(
```python
[
Token(type=TokenType.TYPE, lexeme='type', value=None,position="L1:1"),
Token(type=TokenType.WHITESPACE, lexeme=' ', value=None,position="L1:5"),
Token(type=TokenType.IDENTIFIER, lexeme='Kelvin',value=None,position="L1:6"),
Token(type=TokenType.WHITESPACE, lexeme=' ', value=None,position="L1:12"),
Token(type=TokenType.EQUAL, lexeme='=', value=None,position="L1:13"),
Token(type=TokenType.WHITESPACE, lexeme=' ', value=None,position="L1:14"),
Token(type=TokenType.IDENTIFIER, lexeme='float', value=None,position="L1:15"),
Token(type=TokenType.WHITESPACE, lexeme=' ', value=None,position="L1:20"),
Token(type=TokenType.WHERE, lexeme='where', value=None,position="L1:21"),
Token(type=TokenType.WHITESPACE, lexeme=' ', value=None,position="L1:26"),
Token(type=TokenType.UNDERSCORE, lexeme='_', value=None,position="L1:27"),
Token(type=TokenType.WHITESPACE, lexeme=' ', value=None,position="L1:28"),
Token(type=TokenType.GREATER_EQUAL,lexeme='>=', value=None,position="L1:29"),
Token(type=TokenType.WHITESPACE, lexeme=' ', value=None,position="L1:31"),
Token(type=TokenType.NUMBER, lexeme='0', value=0, position="L1:32"),
Token(type=TokenType.EOF, lexeme='', value=None,position="L1:33")
]
```,
caption: [Midas Example: tokens]
) <fig:example-midas-tokens>
These tokens are then passed through the parser which builds an #acr("AST") shown in @fig:example-midas-ast. This representation is produced by the `MidasASTPrinter` class which can be used via a dedicated command: ```sh midas parse file.midas```. More information about available commands are given in the dedicated #fn-link(<manual>, "https://git.kb28.ch/HEL/midas/src/branch/main/docs/manual.pdf")[manual].
#figure(
```AST
TypeStmt
name: "Kelvin"
params
type
ConstraintType
type
NamedType
name: "float"
constraint
BinaryExpr
left
WildcardExpr
operator: >=
right
LiteralExpr
value: 0
```,
caption: [Midas Example: #acr("AST")]
) <fig:example-midas-ast>
After passing through `MidasParser`, we thus obtain a stable and explicit structure that can be given to `MidasTyper` and interpreted (as far as a definition language can be interpreted).
== Processing statements <sec:midas-interpretation>
Each statement is processed in order. In the following sections we will get in more details for each kind of statements, and look at how we can implement their effects on the types registry.
The complete implementation of `MidasTyper` is available in the project's repository in #code-ref(<midas-typer>, "midas/checker/midas.py").
The basic members and methods referenced in implementations of this section are listed in @fig:midas-typer-members.
=== Building types <sec:midas-building-types>
Before we can register a new type or an alias, we must be able to convert an #acr("AST") representation of a type into our internal type representation structures. For this we leverage the visitor pattern by implementing the visitor class of `Type` #acr("AST") nodes, as generated in @sec:midas-lexing-parsing. We thus make `MidasTyper` extend ```python m.Type.Visitor[Type]```#footnote[To avoid confusion between Midas and Python AST nodes, their namespaces are imported as `m` and `p` respectively. A standalone reference to `Type` relates to the union of internal type representations mentioned in @sec:impl-types.]<fn:types-ref>, indicating that it must handle visiting any `m.Type` node and return a `Type` object.
As an example, visiting a `m.NamedType` node simply looks up the name in the registry to retrieve the definition for that type. If it cannot be found, an error is reported to the user and `UnknownType` is returned. This is the standard behavior we will implement whenever the type checker cannot make a definite judgement about something. As you may notice in @fig:midas-visit_named_type, the implementation checks `self._current_name` to detect cyclic references. In @fig:midas-visit_named_type:4, `self.get_type` is used instead of directly calling the registry's method to handle type variables, as explained in @sec:midas-type-stmt.
#figure(
```python
def visit_named_type(self, type: m.NamedType) -> Type:
name: str = type.name.lexeme
try:
return self.get_type(name)
except NameError:
msg: str = f"Undefined type {name}"
if self._current_name == name:
msg += ". Recursive types are not supported, use an extend block"
self.reporter.error(type.name.get_location(), msg)
return UnknownType()
```,
caption: [Midas Typer: implementation of `visit_named_type`]
) <fig:midas-visit_named_type>
Applied generics are built by looking up the type by its name, processing all arguments to build types and call `TypesRegistry.apply_generic`. The implementation shown in @fig:midas-visit_generic_type also handles the special `Column` type separately, as discussed in @sec:is_subtype.
#figure(
```python
def visit_generic_type(self, type: m.GenericType) -> Type:
match type.type:
case m.NamedType(name=Token(lexeme="Column")):
if len(type.args) != 1:
self.reporter.error(
type.location,
f"Column requires 1 type argument, {len(type.args)} provided",
)
return ColumnType(type=UnknownType())
return ColumnType(type=type.args[0].accept(self))
type_: Type = type.type.accept(self)
args: list[Type] = [arg.accept(self) for arg in type.args]
try:
return self.types.apply_generic(type_, args)
except Exception as e:
self.reporter.error(type.location, f"Cannot apply generic type: {e}")
return UnknownType()
```,
caption: [Midas Typer: implementation of `visit_generic_type`]
) <fig:midas-visit_generic_type>
Constraint types also need some special handling because they include an `m.Expr` node for the constraint expression. This expression is type checked, like Python code will, ensuring that operations are coherent and that the resulting type is a boolean. For more information, please refer to @sec:midas-checking-expr.
#figure(
```python
def visit_constraint_type(self, type: m.ConstraintType) -> Type:
base_type: Type = type.type.accept(self)
self._predicate_params["_"] = base_type
constraint_type: Type = self.type_of(type.constraint)
self._predicate_params = {}
if not self.types.is_subtype(constraint_type, self._bool):
self.reporter.error(
type.constraint.location,
f"Constraint must evaluate to a boolean, got {constraint_type}",
)
return ConstraintType(
type=base_type,
constraint=type.constraint,
)
```,
caption: [Midas Typer: implementation of `visit_constraint_type`]
) <fig:midas-visit_constraint_type>
As you can see in the implementation above, in @fig:midas-visit_constraint_type, we insert the base type as `"_"` in an internal `_predicate_params` dictionary. This will be used later when type checking expression (@sec:midas-checking-expr) to retrieve the "current" type when using a `m.WildcardExpr`.
Processing functions and dataframe types is naturally implemented by processing their internal types (e.g. parameters, columns) and building the corresponding internal representations.
=== Type checking expressions <sec:midas-checking-expr>
The process of type checking constraint expressions (`m.Expr`) is nearly identical to type checking a Python expression. Thus, the implementation is quite similar. This will be covered in the section concerning `PythonTyper`, i.e. @sec:python-check-expr.
For now, we only look at `visit_variable_expr` and `visit_wildcard_expr` which call `get_variable` to return the type of the referenced variable. This method is detailed in @fig:midas-typer-members and in essence does the following:
+ Look up the variable in the list of predicate parameters (including `_`)
+ Look up any predicate with the given name
+ Look up in the global environment or preamble for a builtin with the given name (e.g. `float`, `len`, etc.)
If all three lookups fail, `UnknownType` is returned and an error is reported.
=== Alias statement <sec:midas-alias-stmt>
Now that we can build types we must implement a way to register them for future reference.
The first and simplest statement is the alias statement (`m.AliasStmt`). Its effect is to bind the given name to the type defined on the right-hand side. The implementation is quite straightforward, as demonstrated in @fig:midas-visit_alias_stmt. Do note that `self._current_name` is set before processing the `m.Type` node, and cleared afterwards, so that cyclic references can be caught. The exception raised by the registry is also caught and reported through an error diagnostic to continue processing remaining statements.
#figure(
```python
def visit_alias_stmt(self, stmt: m.AliasStmt) -> None:
name: str = stmt.name.lexeme
self._current_name = name
type: Type = stmt.type.accept(self)
try:
self.types.define_type(name, type)
except ValueError:
self.reporter.error(stmt.location, f"Type {name} already defined")
self._current_name = None
```,
caption: [Midas Typer: implementation of `visit_alias_stmt`]
) <fig:midas-visit_alias_stmt>
=== Type statement <sec:midas-type-stmt>
Type statements work similarly to alias statements, though they wrap the defined type in a `DerivedType` or `GenericType` depending on whether there are parameters.
Additionally, if parameters are given, they are processed and transformed into `TypeVar` instances, and registered in an internal `_local_variables` dictionary. This internal registry is used by `TypesRegistry.get_type` to resolve references to type variables inside generic types and `extend` statements.
#figure(
```python
def visit_type_stmt(self, stmt: m.TypeStmt) -> None:
name: str = stmt.name.lexeme
self._current_name = name
params: list[TypeVar] = self._resolve_type_params(stmt.params)
type: Type = stmt.type.accept(self)
if len(params) != 0:
type = GenericType(name=name, params=params, body=type)
else:
type = DerivedType(name=name, type=type)
try:
self.types.define_type(name, type)
except ValueError:
self.reporter.error(stmt.location, f"Type {name} already defined")
self._local_variables.clear()
self._current_name = None
def _resolve_type_params(self, params: list[m.TypeParam]):
vars: list[TypeVar] = []
for param in params:
name: str = param.name.lexeme
bound: Optional[Type] = None
if param.bound is not None:
bound = param.bound.accept(self)
var = TypeVar(name=name, bound=bound)
self._local_variables[name] = var
vars.append(var)
return vars
```,
caption: [Midas Typer: implementation of `visit_type_stmt`]
) <fig:midas-visit_type_stmt>
=== Predicate statement <sec:midas-predicate-stmt>
When processing a predicate definition, we first need to gather all parameters and register them internally in `self._predicate_params`. Then we type check the predicate body, i.e. a constraint expression (`m.Expr`). After this we process all parameter specifications using the same method as for function types. Before defining the predicate, we also check that the body's type is valid, i.e. a subtype of `bool` or a function which returns a valid predicate (in case of a partially applied predicate). Lastly, we build a complete function signature for the predicate, combining curried parameter specifications into functions returning functions, and insert it in the registry. If the predicate definition does not include any parameter specification, we mark it as an alias. This whole procedure is implemented as shown in @fig:midas-visit_predicate_stmt.
#figure(
```python
def visit_predicate_stmt(self, stmt: m.PredicateStmt) -> None:
name: str = stmt.name.lexeme
for spec in stmt.params:
for param in spec.mixed:
assert param.name is not None
self._predicate_params[param.name.lexeme] = param.type.accept(self)
type: Type = self.type_of(stmt.body)
params: list[ParamSpec] = [self._visit_param_spec(spec) for spec in stmt.params]
if not self._is_valid_predicate(type):
self.reporter.error(
stmt.body.location,
f"Predicate function body must evaluate to a boolean, got {type}",
)
if len(params) != 0:
type = self._bool
for spec in reversed(params):
type = Function(
params=spec,
returns=type,
)
self._predicate_params = {}
try:
self.types.define_predicate(
name,
Predicate(
type=type,
body=stmt.body,
alias=len(params) == 0,
),
)
except ValueError:
self.reporter.error(stmt.location, f"Predicate {name} already defined")
def _is_valid_predicate(self, body: Type) -> bool:
match body:
case Function(returns=returns):
return self._is_valid_predicate(returns)
case _ if self.types.is_subtype(body, self._bool):
return True
case _:
return False
```,
caption: [Midas Typer: implementation of `visit_predicate_stmt`]
) <fig:midas-visit_predicate_stmt>
=== Extend statement <sec:midas-extend-stmt>
#todo[]
=== Example
Continuing with our example from @fig:example-midas-ast, the type statement would register a new type named `Kelvin` with internal representation given in
#figure(
```python
DerivedType(
name='Kelvin',
type=ConstraintType(
type=BaseType(name='float'),
constraint=BinaryExpr(
left=WildcardExpr(
token=Token(type=TokenType.UNDERSCORE, lexeme='_', value=None)
),
operator=Token(type=TokenType.GREATER_EQUAL, lexeme='>=', value=None),
right=LiteralExpr(value=0)
)
)
)
```,
caption: [Midas Example: registered type#footnote[Location and position objects are omitted for readability]]
) <fig:example-midas-type>
== Variance inference <sec:variance-inference>
The main `resolve` method of `MidasTyper`, as shown in @fig:midas-typer-resolve and @fig:midas-typer-members, first processes all statements, and then summons a `VarianceManager` to infer variance of all types.
#codly(
range: (68, 78),
smart-skip: true
)
#figure(
midas-typer-members-code,
caption: [Midas Typer: `resolve` method]
) <fig:midas-typer-resolve>
The inference process is actually not very complicated but rigorous. The objective is, for all type variables in all generic types, to walk through all their usages and record their polarity.
By polarity, we mean that:
- any _producer_ position, such as a function return type, is considered *positive*
- any _consumer_ position, such as a function parameter, is considered *negative*
Algorithmically, when inferring the variance of a variable, we start at the root generic type with a positive polarity. The inference function identifies all possible positions (type body and members) and recurses with the current polarity multiplied by the position's polarity. For example, if the current polarity is positive and a variable is used in a producer position, the resulting polarity used when recursing is $+ times + = +$. If however the variable is used in a consumer position, the polarity becomes $+ times - = -$. A consumer or negative position basically _flips_ the current polarity. When the recursion reaches the bottom usage, i.e. a simple `TypeVar`, the polarity is recorded.
This algorithm is implemented by the `VarianceInferrer` class in @fig:midas-variance-inferrer-walk.
#codly(
ranges: (
(1, 2),
(11, 66),
),
smart-skip: true
)
#figure(
raw(block: true, lang: "python", read("../../code/variance_inferrer.py")),
caption: [Implementation of `VarianceInferrer.infer` and `VarianceInferrer.walk`]
) <fig:midas-variance-inferrer-walk>
A `Tracker` helper class is responsible for keeping a record of all occurrences of each type variable, with a list of observed polarities.
When the generic type has been full walked, the tracker returns the list of type variables with their variance fixed, according to the following rule:
- if the variable only appears with positive polarity, it is *covariant*
- if the variable only appears with negative polarity, it is *contravariant*
- otherwise it is *invariant*
Its implementation is given in @fig:midas-variance-tracker.
It should be noted that we also use a `VarianceManager` to orchestrate how all the types are processed. The naive approach is to simply iterate over each type and infer their variance. However, this breaks down when a type is referenced before it is processed, or even inside itself. To counter such situations, we introduce a queue of types currently being processed. When walking through a type, if we encounter an `AppliedType`, we first check whether it is in the queue. If not, we ask the manager to infer its variance before continuing, as highlighted in @fig:midas-variance-inferrer-walk:42 to @fig:midas-variance-inferrer-walk:47.
`VarianceManager` is a simple helper class. Its main method, `infer`, is shown in @fig:midas-variance-manager-infer.
#codly(
range: (12, 21),
smart-skip: true
)
#figure(
raw(block: true, lang: "python", read("../../code/variance_manager.py")),
caption: [Implementation of `VarianceManager.infer`]
) <fig:midas-variance-manager-infer>
The complete implementation of all classes mentioned in this section is available in the repository in #code-ref(<midas-variance>, "midas/checker/variance.py").
/*
- Midas definition language
- Lexer + parser (Crafting Interpreters, Pebble)
- reference theory for grammar rules
- token location -> necessary later for diagnostics
- AST node generation, similar to CI (3 kinds, Stmt/Expr/Type)
- Typer
- reference theory for typing rules
- type structures
- types registry
*/

View File

@@ -0,0 +1,503 @@
#import "../../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: todo
#import "@preview/acrostiche:0.7.0": acr
#import "../../utils.typ": code-ref, fn-link
#import "@preview/codly:1.3.0": codly
#import "@preview/lovelace:0.3.1": pseudocode-list
#import "../../appendices/python_typer.typ": python-typer-function-code
#import "../../appendices/call_dispatcher.typ": call-dispatcher-code
= Python Type Checking <sec:impl-python>
We have now built a type definition language and registry, but it is of no use if we cannot type-check our Python code. In a similar fashion to `MidasTyper`, we must now implement a `PythonTyper`. Its role is to take in some Python source code and the types registry, walk through each statement and expression, infer the type of each term and verify the program's soundness. We will need several tools to concretize this process, such as a resolver to keep track of which value each variable references, and an environment to store the inferred types of local variables.
For the sake of readability and conciseness, many parts of the implementation will be omitted from the following sections, focusing instead on the basic principles and most interesting methods. As always, the full source code is available in the repository, mainly in #code-ref(<checker>, "midas/checker").
== Parsing Python <sec:python-parsing>
For consistency and resource sharing, we will mirror a number of structures and methods used for the Midas language. However, we do not need to implement a lexer and parser for Python as it already provides an `ast` module just for this purpose. Nonetheless, we will implement our own #acr("AST") nodes similar to those discussed in @sec:midas-lexing-parsing. This allows having the same structure as the Midas #acr("AST") and explicitly only implement supported Python constructs. Additionally, it will make some node namings and internal structures clearer.
The same generation script is used to create dataclasses for each node type (see @sec:midas-lexing-parsing).
For Python, we will also use three kinds of nodes:
- Statements (`Stmt`): top-level constructs which can have side-effects in the environment
- Expressions (`Expr`): composable building blocks with an inferrable type
- Types (`MidasType`): type expressions used in annotations
The full list of #acr("AST") nodes used for Python is available in @tab:python-ast-nodes and their concrete implementation in the repository in #code-ref(<python-ast>, "midas/ast/python.py").
We implement a `PythonParser` class which takes in an #acr("AST") module node generated from Python's own `ast` library, and produces an equivalent tree with our nodes, skipping unsupported constructs and simplifying some elements. Because `ast` also uses statement (`ast.stmt`) and expression (`ast.expr`) nodes, we must implement two methods `parse_expr(node: ast.expr) -> Expr` and `parse_stmt(node: ast.stmt) -> None | Stmt | list[Stmt]`. The latter does not simply return a `Stmt` object to allow single Python statements to be split into multiple nodes (e.g. `ast.AnnAssign` is split into a type assignment and a value assignment) or even not produce any node (e.g. `ast.Pass` nodes are skipped). We leverage again Python's `match` statement for pattern matching.
This section will not go into details about the parser's implementation because it is not particularly interesting and quite repetitive. The source code is still available in the repository in #code-ref(<python-parser>, "midas/parser/python.py").
== Resolving References <sec:python-resolver>
Although we will not _evaluate_ Python expressions, we will need to know what bindings refer to. Following chapter 11 of _Crafting Interpreters_@Nystrom2021, we will implement a resolver class. Its goal is to identify binding declarations, keep a record of which scope that declaration appears in and mark each reference with the binding it actually refers to. For example in @fig:example-scoping, the variable `foo` on @fig:example-scoping:4 refers to the inner variable, not the global one.
#figure(
```python
foo = 3
def bar():
foo = ""
print(foo)
```,
caption: [Example of variable scoping in Python]
) <fig:example-scoping>
The implementation is mostly adapted from a previous project, #fn-link(<pebble-fn>, "https://git.kb28.ch/HEL/pebble")[pebble] and based on Nystrom's@Nystrom2021 tutorial-like approach. We will not describe the whole implementation of our `Resolver`, which is available in the repository in #code-ref(<resolver>, "midas/checker/resolver.py"), but only mention two points of interest.
The first point is that this resolver will also perform a form of definite assignment analysis, which is "a data-flow analysis used by compilers to conservatively ensure that a variable or location is always assigned before it is used"@enwiki:1326872870. This is distinguishing variable declaration and definition, which is not explicit in Python's syntax. It allows producing useful error diagnostics such as in @fig:resolver-visit_variable_expr.
#figure(
```python
def visit_variable_expr(self, expr: p.VariableExpr) -> None:
if self.is_declared(expr.name) and not self.is_defined(expr.name):
self.reporter.error(
expr.location,
f"Variable '{expr.name}' is declared but may not be defined",
)
self.resolve_local(expr, expr.name)
```,
caption: [Implementation of `Resolver.visit_variable_expr`]
) <fig:resolver-visit_variable_expr>
Secondly, as stated in #smallcaps[T-IfElse] in @sec:typing-statements, our type checker will not allow leaking variables from inner scopes such as in `if`/`else` statements. Using scopes we can trivially isolate branches and discard inner declarations after such statements. However, we still want to perform assignment analysis. Taking the situation exhibited in @fig:example-if-else-assignment, the resolver can know that `foo` is definitely assigned when reaching @fig:example-if-else-assignment:6 even though no assignment is made outside of the conditional.
#figure(
```python
foo: str
if ...:
foo = "true"
else:
foo = "false"
print(foo)
```,
caption: [Example of fully assigned variable in `if` statement]
) <fig:example-if-else-assignment>
More generally, if all sub-branches assign to a variable, we can consider it defined in the parent scope. This is implemented as shown in @fig:resolver-visit_if_stmt. Here, `self.end_scope` returns the inner scope containing declarations and assignments made inside each branch. We then check which variable is defined in both branches and forward the definition.
#figure(
```python
def visit_if_stmt(self, stmt: p.IfStmt) -> None:
self.resolve(stmt.test)
self.begin_scope()
self.resolve(*stmt.body)
body: dict[str, bool] = self.end_scope()
self.begin_scope()
self.resolve(*stmt.orelse)
else_: dict[str, bool] = self.end_scope()
for name, is_defined in body.items():
if is_defined and else_.get(name, False):
self.define(name)
```,
caption: [Implementation of `Resolver.visit_if_stmt`]
) <fig:resolver-visit_if_stmt>
== Environments <sec:python-env>
#todo[]
== Type Checking Statements <sec:python-check-stmt>
We now have the tools to start type checking our Python code.
The input given to `PythonTyper` is basically a sequence of statements (`p.Stmt`). Using the visitor pattern, we make `PythonTyper` extend ```python p.Stmt.Visitor[None]``` and implement all `visit_*_stmt` methods.
=== Variable assignment <sec:python-var-assign>
One of the main mechanics manipulating the environment is variable declaration and assignment.
During parsing, a statement such as ```python foo: int = 3```, represented in Python as a single `ast.AnnAssign` node, is split into two #acr("AST") nodes. The first is a type assignment (`p.TypeAssign`), which declares a new variable with the given type. The second is a variable assignment (`p.AssignStmt`). Implementing `visit_type_assign` is straightforward: we first resolve the type annotation expression and then define a new variable in the current environment, as demonstrated in @fig:python-visit_type_assign.
#figure(
```python
def visit_type_assign(self, stmt: p.TypeAssign) -> None:
type: Type = self.resolve_type_expr(stmt.type)
self.env.define(stmt.name, type)
```,
caption: [Python Typer: implementation of `visit_type_assign`]
) <fig:python-visit_type_assign>
This method basically materializes #smallcaps[T-Annot] from @tab:typing-statements.
Handling the variable assignment part is a bit more involved, because Python (and our type checker) allows both assigning to multiple targets simultaneously (@fig:python-visit_assign_stmt:3) and assigning to attributes and subscripts (not only variables). This is the reason we use a `match` statement in @fig:python-visit_assign_stmt. This function embodies #smallcaps[T-Assign].
#codly(
ranges: (
(1, 9),
(19, 30)
),
smart-skip: true
)
#figure(
```python
def visit_assign_stmt(self, stmt: p.AssignStmt) -> None:
value_type: Type = self.type_of(stmt.value)
for target in stmt.targets:
self._assign(stmt.location, target, value_type)
def _assign(self, location: Location, target: p.Expr, value_type: Type):
match target:
case p.VariableExpr():
self._assign_var(location, target, value_type)
case p.GetExpr(object=object, name=name):
self._assign_attr(location, object, name, value_type)
case p.SubscriptExpr(object=p.VariableExpr() as var, index=index):
self._assign_sub(location, var, index, value_type)
case _:
self.reporter.warning(
target.location, f"Unsupported assignment to {target}"
)
def _assign_var(self, location: Location, target: p.VariableExpr, value_type: Type):
name: str = target.name
var_type: Optional[Type] = self.look_up_variable(name, target)
if var_type is None:
self.env.define(name, value_type)
else:
if not self.is_subtype(value_type, var_type):
self.reporter.error(
location,
f"Cannot assign {value_type} to variable '{name}' of type {var_type}",
)
```,
caption: [Python Typer: implementation of `visit_assign_stmt` (variable target)]
) <fig:python-visit_assign_stmt>
This is also one of the places our subtyping rules come into play. When assigning to an already defined variable, we check that the value's type is a subtype of the variable's type.#footnote[`PythonTyper.is_subtype` is simply a shortcut for calling `is_subtype` on the types registry], emitting an error diagnostics in case of incompatibility.
=== Returns <sec:python-returns>
One special control flow statement is the ```py return``` keyword.
Its effect is twofold. First, it cuts a branch short and any further statement in that branch is skipped. Secondly, it provides a possible return type for the parent function. The latter implies that return statements must appear inside functions.
To easily implement the first effect, we will take advantage of exceptions and raise one inside `visit_return_stmt` (named `ReturnException`). We must then catch this exception at the closest branching point, i.e. the entry point of a block. In our case, in addition to a method type checking a single statement (`process_stmt`), we can implement a method to type check a whole block (`process_block`). Inside the latter we can then wrap calls `process_stmt` in a `try`/`except` statement. If a `ReturnException` is caught while processing a block and some statements remain to be processed, we can emit a warning to the user indicating that they will be skipped at runtime.
@fig:python-visit_return_stmt shows how the exception is raised while @fig:python-process_block shows how the exception is caught.
#figure(
```python
def visit_return_stmt(self, stmt: p.ReturnStmt) -> None:
type: Type = self.type_of(stmt.value) if stmt.value is not None else UnitType()
self.env.return_types.append(type)
raise ReturnException(stmt)
```,
caption: [Python Typer: implementation of `visit_return_stmt`]
) <fig:python-visit_return_stmt>
#figure(
```python
def process_block(self, block: list[p.Stmt], env: Environment) -> bool:
previous_env: Environment = self.env
self.env = env
returned: bool = False
for i, stmt in enumerate(block):
try:
self.process_stmt(stmt)
except ReturnException:
returned = True
if i < len(block) - 1:
self.reporter.warning(
block[i + 1].location, "Unreachable statement"
)
break
self.env = previous_env
return returned
```,
caption: [Python Typer: implementation of `process_block`]
) <fig:python-process_block>
The second effect of return statements is executed by @fig:python-visit_return_stmt:3 by recording the return value's type in a list of all return types for the current function.
Similarly to how we handled variable assignments in `if` branches (see @fig:resolver-visit_if_stmt), if all sub-branches return, then the parent scope must also return, thus the implementation in @fig:python-visit_if_stmt.
#figure(
```python
def visit_if_stmt(self, stmt: p.IfStmt) -> None:
test_type: Type = self.type_of(stmt.test)
if (
not self.is_subtype(test_type, self.types.get_type("bool"))
and test_type != UnknownType()
):
self.reporter.error(
stmt.test.location, f"If test must be a boolean, got {test_type}"
)
env: Environment = Environment(self.env)
body_returned: bool = self.process_block(stmt.body, env)
else_returned: bool = self.process_block(stmt.orelse, env)
self.env.return_types.extend(env.return_types)
if body_returned and else_returned:
raise ReturnException(stmt)
```,
caption: [Python Typer: implementation of `visit_if_stmt`]
) <fig:python-visit_if_stmt>
=== Function definitions <sec:python-functions>
Function definitions include many components from all kinds of parameters, default values return type hints and their bodies. One particular property is the optionality of return type hints and the potential multiplicity of return statements inside a function body.
What we want for our type checker is to ensure soundness of return types while helping the user by giving them as much freedom as possible by inferring types where not explicitly given.
In the case of functions, this means that the user should be allowed to omit the return type hint and let the type checker infer it from return statements inside the body. To do so, we will implement the following method:
#[
+ Type check the function's body, collecting return types in the environment
+ If no return statement appears in the body, default to `UnitType`
+ Try and find a #acr("LUB") of all return types, only in this list of types#footnote[We check whether one of the types in the list is a supertype of all the others ($exists t_r in TT : forall t in TT, t <: t_r$)]
+ Unique return supertype?
- *Yes*: use it as the inferred return type
- *No*: report an error and use `UnknownType` as the inferred return type
+ Return type hint ?
- *Yes*: check that the inferred return type is a subtype of the annotated one, use the type hint as the function's return type
- *No*: use the inferred return type for the function
]
#codly(
range: (77, 105),
smart-skip: true
)
#figure(
python-typer-function-code,
caption: [Python Typer: function return type inference]
) <fig:python-function-return-type>
The complete implementation of `PythonTyper.visit_function` is listed in @fig:python-visit_function.
== Type Checking Expressions <sec:python-check-expr>
We extend `PythonTyper` to also type check expressions by inheriting ```python p.Expr.Visitor[Type]``` and implementing `visit_*_expr` methods. We thus make all expression visitor methods return a `Type` instance. Indeed, each Python expression is a typeable element composed into other expressions or statements. Some expressions such as literal value are trivial to type check whilst others can be much more complex. The latter are detailed in separate sections.
=== Literals <sec:python-check-literals>
Applying typing rules for literals (@tab:typing-literals) is only a matter of matching each value type to the corresponding builtin type representation, as shown in @fig:python-visit_literal_expr.
#figure(
```python
def visit_literal_expr(self, expr: p.LiteralExpr) -> Type:
match expr.value:
case bool(): return self.types.get_type("bool")
case int(): return self.types.get_type("int")
case float(): return self.types.get_type("float")
case str(): return self.types.get_type("str")
case None: return self.types.get_type("None")
case _:
self.reporter.warning(expr.location, f"Unknown literal {expr}")
return UnknownType()
```,
caption: [Python Typer: implementation of `visit_literal_expr`]
) <fig:python-visit_literal_expr>
For literal list expressions, we will reuse `TypesRegistry.reduce_types` method used in @fig:python-function-return-type to try and find a supertype of all item types.
#figure(
```python
def visit_list_expr(self, expr: p.ListExpr) -> Type:
list_type: Type = self.types.get_type("list")
item_types: list[Type] = [self.type_of(item) for item in expr.items]
item_types = self.types.reduce_types(item_types)
if len(item_types) == 0:
return list_type
if len(item_types) == 1:
item_type: Type = item_types[0]
return self.types.apply_generic(list_type, [item_type])
self.reporter.warning(
expr.location,
f"Heterogeneous list items: [{', '.join(map(str, item_types))}]",
)
return self.types.apply_generic(list_type, [UnknownType()])
```,
caption: [Python Typer: implementation of `visit_list_expr`]
) <fig:python-visit_list_expr>
Literal dictionaries are handled in the same manner, finding a supertype for keys and for values.
=== Operations
In Python, builtin operators are implemented through _dunder-methods_, i.e. methods on the operands. To the eyes of the type checker, an operation is thus equivalent to a function call. We can implement this idea by following these steps:
+ Get the dunder-method name corresponding to the operator
+ Type-check all operands (two for binary operators, one for unary operators)
+ Lookup the method on the left operand#footnote[Reverse operations (e.g. `__radd__`) have not been implemented in Midas yet]
+ Type check a call to the method with the given operand(s)
Step 1 is a simple lookup in a dictionary.\
Step 2 is a recursive call to type check the operand expressions.\
Step 3 calls `TypesRegistry.lookup_member`.\
Step 4 is delegated to a common `call_method` function, also used for call expressions (see @sec:python-check-calls).
Similarly, subscripts are de-sugared into calls to `__getitem__`.
== Type Checking Calls <sec:python-check-calls>
Function calls are not always as straightforward as matching arguments with parameters and getting the return type. For a start, the callee is not necessary a direct `Function`. It may be a `DerivedType` or an `AppliedType`, in which case we must _unfold_ the type hierarchy to get the actual function type. It may also be an `OverloadedFunction`, in which case we must resolve which overload to call. It can also be a `GenericType`, in which case we must try and resolve the actual type arguments based on usage. To keep the type checker tidy, we introduce a separate `CallDispatcher` class, which we can reuse in `MidasTyper` for call expressions too.
This dispatcher has one main entrypoint: `get_result`. This method, shown in @fig:dispatcher-get_result-signature, takes in a callee type, positional and keyword arguments, and returns a `CallResult` object. This object bundles information about the result type and potential error should the dispatcher fail to resolve the call. The complete methods discusses hereafter are included in @fig:call-dispatcher. Their implementations are available in the repository in #code-ref(<call-dispatcher>, "midas/checker/dispatcher.py").
#figure(
```python
class CallResult:
error: Optional[CallError] = None
result: Type = UnknownType()
message: Optional[str] = None
@property
def is_valid(self) -> bool: return self.error is None
@property
def error_message(self) -> str:
if self.message is not None:
return self.message
if self.error is not None:
return str(self.error)
return ""
class CallDispatcher(Generic[E]):
def get_result(
self,
location: Location,
callee: Type,
positional: list[TypedExpr[E]],
keywords: dict[str, TypedExpr[E]],
report_errors: bool = True,
) -> CallResult: ...
```,
caption: [Call Dispatcher: signature of `get_result` and `CallResult`]
) <fig:dispatcher-get_result-signature>
`CallDispatcher` is generic in `E`, which represents an expression base class. This allows instantiating it both for `m.Expr` and `p.Expr`.
The simple case where the callee is a `Function` involves matching call-site arguments with parameters in the function's specification. Then, if a match is possible each pair is check for correct typing. Similar to variable assignment (#smallcaps[T-Assign], see @sec:python-var-assign), an argument must be of the same type as the parameter it matches with (module subsumption). Pragmatically, this corresponds to @fig:dispatcher-match-func.
#codly(
range: (14, 24),
smart-skip: true
)
#figure(
call-dispatcher-code,
caption: [Call Dispatcher: call to `Function`]
) <fig:dispatcher-match-func>
Some other simple cases mentioned above can be handled with recursion. Calls to `UnknownType` are also allowed by the type checker, only resulting in an `UnknownType` too. These form the three simple match-cases in @fig:dispatcher-match-simple.
#codly(
range: (25, 34),
smart-skip: true
)
#figure(
call-dispatcher-code,
caption: [Call Dispatcher: call to `UnknownType`, `DerivedType` and `AppliedType`]
) <fig:dispatcher-match-simple>
For `OverloadedFunction`, we must first resolve which overload the calls should use. We defer this process to a `_match_overload` method which we will build now.
=== Matching Overload
This method receives the list of overloads and all call arguments. Its goal is to:
1. identify which overload is compatible
2. choose the most specific overload candidate if multiple are plausible
Regarding the first point, we simply iterate over the overload types and check whether a call with the given arguments is valid. As shown in @fig:overloads-filter-candidates, we first call a method named `_unwrap_function`. This is a simplified form of `get_result`, only to get the actual `Function`. You may find its implementation in @fig:call-dispatcher.
#codly(
range: (104, 135),
smart-skip: true
)
#figure(
call-dispatcher-code,
caption: [Matching Overload: filtering candidates]
) <fig:overloads-filter-candidates>
After having filtered the overload candidates, if only one remains we can use it as the actual function. If no overload matches the arguments, we directly return an error, as implemented in @fig:overloads-1-0-candidate.
#codly(
range: (143, 154),
smart-skip: true
)
#figure(
call-dispatcher-code,
caption: [Matching Overload: unique or no candidate]
) <fig:overloads-1-0-candidate>
Finally, if there are multiple candidates, we can try one last thing. If one of the candidates is more specific than all others, it is chosen as the actual function signature. By more specific, we mean that for each argument mapping in one overload, corresponding mappings in all other candidates have supertype parameters. Formally, if $CC$ is the list of valid candidates, $C_"spec"$ the potential most specific candidate and $C_"rest"$ another candidate ($a$ are arguments mapped to parameters $p$):
$
&exists C_"spec" ({(a_i, p_"spec"_i)^(i in 1..n)}) in CC :\
&forall C_"rest" ({(a_j, p_"rest"_j)^(j in 1..n)}) in CC,\
&forall i in 1..n, space p_"spec"_i <: p_"rest"_i
$
In Python, this translates to @fig:overloads-candidate-subtype.
#codly(
range: (156, 168),
smart-skip: true
)
#figure(
call-dispatcher-code,
caption: [Matching Overload: most specific overload]
) <fig:overloads-candidate-subtype>
Ultimately, if this also fails to find a unique, unambiguous candidate, an error is returned, as seen in @fig:overloads-error.
#codly(
range: (170, 176),
smart-skip: true
)
#figure(
call-dispatcher-code,
caption: [Matching Overload: default error]
) <fig:overloads-error>
Now that we have a method to choose an overload given some arguments, we can add the case in @fig:dispatcher-match-overloaded to `get_result`.
#codly(
range: (35, 44),
smart-skip: true
)
#figure(
call-dispatcher-code,
caption: [Call Dispatcher: call to `OverloadedFunction`]
) <fig:dispatcher-match-overloaded>
=== Generic function
Generic functions are useful for defining some kind of template behavior while allowing different types to be used. However, when it comes to a call to such a function, things get a bit more complicated. Indeed, type parameters must be mapped to concrete types and unified depending on the actual call-site arguments before getting the return type. Taking the example of a simple generic doubling function ```py def double(value: T) -> T```, the return type depends on the type of the argument. Furthermore, in a more complex case like ```py def add(v1: T, v2: T) -> T```, the type variable `T` must be mapped to the same type for both `v1` and `v2`.
This process is covered more in depth in chapter 22 of #acr("TaPL")@tapl.
For this purpose, we can implement a dedicated `Unifier` class whose role is to find appropriate substitutions for type variables in a generic call. Its source code is available in the repository in #code-ref(<unifier>, "midas/checker/unifier.py").
Using this class, we can complete `get_result` with the last case handling calls to a `GenericType`, as shown in @fig:dispatcher-match-generic.
#codly(
range: (45, 68),
smart-skip: true
)
#figure(
call-dispatcher-code,
caption: [Call Dispatcher: call to `GenericType`]
) <fig:dispatcher-match-generic>
== Casts and Static Evaluation <sec:python-check-casts>
#todo[]
== Frames and Columns <sec:python-df-cols>
#todo[]
== Output <sec:python-output>
#todo[]
/*
- Python type checking
- Parsing (short paragraph about AST nodes)
- Resolver
- Cf. CI
- Assignment analysis
- Typer
- Returns / if-else
- Environment
- Static constraint evaluation
*/

View File

@@ -0,0 +1,20 @@
#import "../../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: todo
= Code Generation <sec:impl-generation>
== Stubs <sec:gen-stubs>
#todo[]
== Output Code <sec:gen-code>
#todo[]
== Assertions <sec:gen-assertions>
#todo[]
/*
- Code generation
- Stubs
- Assertions
*/

View File

@@ -0,0 +1,4 @@
#import "../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: todo
= Results and Discussion <chap:results>

View File

@@ -0,0 +1,4 @@
#import "../requirements.typ": isc-hei-bthesis
#import isc-hei-bthesis: todo
= Conclusion <chap:conclusion>

View File

@@ -0,0 +1,190 @@
class OverloadCandidate:
function: Function
mapped: list[MappedArgument]
class CallDispatcher(Generic[E]):
def get_result(
self,
location: Location,
callee: Type,
positional: list[TypedExpr[E]],
keywords: dict[str, TypedExpr[E]],
report_errors: bool = True,
) -> CallResult:
match callee:
case Function() as function:
valid: bool
mapped: list[MappedArgument[E]]
valid, mapped = self.map_call_arguments(
function, location, positional, keywords
)
valid = valid and self._are_arguments_valid(mapped, report_errors)
if not valid:
return CallResult(error=CallError.INVALID_ARGS)
return CallResult(result=function.returns)
case UnknownType():
return CallResult(result=UnknownType())
case DerivedType(type=base):
return self.get_result(
location, base, positional, keywords, report_errors
)
case AppliedType(body=body):
return self.get_result(
location, body, positional, keywords, report_errors
)
case OverloadedFunction(overloads=overloads):
res = self._match_overload(
overloads, location, positional, keywords, report_errors
)
if res[0] is None:
return CallResult(
error=CallError.NO_MATCHING_OVERLOAD,
message=res[1],
)
return CallResult(result=res[0].returns)
case GenericType():
unifier: Unifier = Unifier(self.types)
pos: list[Type] = [a[1] for a in positional]
kw: dict[str, Type] = {k: v[1] for k, v in keywords.items()}
unified: Optional[Type] = unifier.unify_call(callee, pos, kw)
if unified is None:
pos_str: str = ", ".join(str(t) for t in pos)
kw_str: str = ", ".join(f"{k}: {v}" for k, v in kw.items())
message: str = (
f"Could not unify {callee}={callee.body} with pos=[{pos_str}] and kw={{{kw_str}}}"
)
if report_errors:
self.reporter.error(location, message)
return CallResult(
error=CallError.IMPOSSIBLE_UNIFICATION,
message=message,
)
return self.get_result(
location,
unified,
positional,
keywords,
report_errors,
)
case _:
message: str = f"{callee} ({callee.__class__.__name__}) is not callable"
if report_errors:
self.reporter.error(location, message)
return CallResult(
error=CallError.NOT_CALLABLE,
message=message,
)
def _unwrap_function(
self,
callee: Type,
positional: list[TypedExpr[E]],
keywords: dict[str, TypedExpr[E]],
) -> Union[tuple[Function, None], tuple[None, CallError]]:
match callee:
case Function():
return callee, None
case DerivedType(type=base):
return self._unwrap_function(base, positional, keywords)
case AppliedType(body=body):
return self._unwrap_function(body, positional, keywords)
case GenericType():
unifier: Unifier = Unifier(self.types)
unified: Optional[Type] = unifier.unify_call(
callee,
[a[1] for a in positional],
{k: v[1] for k, v in keywords.items()},
)
if unified is None:
return None, CallError.IMPOSSIBLE_UNIFICATION
return self._unwrap_function(unified, positional, keywords)
case _:
return None, CallError.NOT_CALLABLE
def _match_overload(
self,
overloads: list[Type],
location: Location,
positional: list[TypedExpr[E]],
keywords: dict[str, TypedExpr[E]],
report_errors: bool = True,
) -> Union[tuple[Function, None], tuple[None, str]]:
candidates: list[OverloadCandidate] = []
errors: list[CallError] = []
for overload in overloads:
function, unwrap_error = self._unwrap_function(
overload, positional, keywords
)
if function is None:
errors.append(unwrap_error)
continue
valid, mapped = self.map_call_arguments(
function=function,
location=location,
positional=positional,
keywords=keywords,
report_errors=False,
)
if valid and self._are_arguments_valid(mapped, report_errors=False):
candidates.append(
OverloadCandidate(
function=function,
mapped=mapped,
)
)
pos_types: str = ", ".join(str(type) for _, type in positional)
kw_types: str = ", ".join(
f"{name}: {type}" for name, (_, type) in keywords.items()
)
for_args: str = f"for arguments pos=[{pos_types}] and kw={{{kw_types}}}"
n_candidates: int = len(candidates)
if n_candidates == 1:
return candidates[0].function, None
if n_candidates == 0:
overloads_str: str = ", ".join(map(str, overloads))
errors_str: str = ", ".join(errors)
message: str = (
f"No matching overload in [{overloads_str}] {for_args} (errors: {errors_str})"
)
if report_errors:
self.reporter.error(location, message)
return None, message
for i1, c1 in enumerate(candidates):
mapped1: list[MappedArgument[E]] = c1.mapped
best_match: bool = True
for i2, c2 in enumerate(candidates):
if i1 == i2:
continue
mapped2: list[MappedArgument[E]] = c2.mapped
if not self._are_mapped_subtypes(mapped1, mapped2):
best_match = False
break
self.logger.debug(f"{c1.function} is a full overload of {c2.function}")
if best_match:
return c1.function, None
candidates_str: str = ", ".join(
str(candidate.function) for candidate in candidates
)
message: str = f"Multiple matching overloads {for_args}: {candidates_str}"
if report_errors:
self.reporter.error(location, message)
return None, message
def _are_mapped_subtypes(
self, mapped1: list[MappedArgument[E]], mapped2: list[MappedArgument[E]]
) -> bool:
by_expr: dict[E, Type] = {}
for arg in mapped1:
by_expr[arg.arg_expr] = arg.parameter.type
for arg in mapped2:
type2: Type = arg.parameter.type
type1: Type = by_expr[arg.arg_expr]
if not self.types.is_subtype(type1, type2):
return False
return True

View File

@@ -0,0 +1,98 @@
def is_func_subtype(self, func1: Function, func2: Function) -> bool:
if not self.is_subtype(func1.returns, func2.returns):
return False
pos1: list[Function.Parameter] = func1.params.pos
mixed1: list[Function.Parameter] = func1.params.mixed
kw1: dict[str, Function.Parameter] = {
param.name: param for param in func1.params.kw
}
pos2: list[Function.Parameter] = func2.params.pos
mixed2: list[Function.Parameter] = func2.params.mixed
kw2: dict[str, Function.Parameter] = {
param.name: param for param in func2.params.kw
}
mixed_by_pos: dict[int, Function.Parameter] = {
param.pos: param for param in mixed1
}
mixed_by_name: dict[str, Function.Parameter] = {
param.name: param for param in mixed1
}
matches: list[Match] = []
for param2 in pos2:
param1: Function.Parameter
if param2.pos < len(pos1):
param1 = pos1[param2.pos]
elif param2.pos in mixed_by_pos:
param1 = mixed_by_pos[param2.pos]
else:
return False
if not param2.required and param1.required:
return False
matches.append((param1, param2))
for name, param2 in kw2.items():
param1: Function.Parameter
if name in kw1:
param1 = kw1[name]
elif name in mixed_by_name:
param1 = mixed_by_name[name]
else:
return False
if not param2.required and param1.required:
return False
matches.append((param1, param2))
for param2 in mixed2:
pos_param1: Optional[Function.Parameter] = None
kw_param1: Optional[Function.Parameter] = None
if param2.name in kw1:
kw_param1 = kw1[param2.name]
elif param2.name in mixed_by_name:
kw_param1 = mixed_by_name[param2.name]
if param2.pos < len(pos1):
pos_param1 = pos1[param2.pos]
elif param2.pos in mixed_by_pos:
pos_param1 = mixed_by_pos[param2.pos]
if pos_param1 is None or kw_param1 is None:
return False
if pos_param1 == kw_param1:
param1: Function.Parameter = pos_param1
if not param2.required and param1.required:
return False
matches.append((param1, param2))
else:
if pos_param1.required or kw_param1.required:
return False
matches.append((pos_param1, param2))
matches.append((kw_param1, param2))
def is_matched(param: Function.Parameter) -> bool:
for p1, _ in matches:
if p1 == param:
return True
return False
all_params1: list[Function.Parameter] = pos1 + mixed1 + list(kw1.values())
for param1 in all_params1:
if not is_matched(param1) and param1.required:
return False
for param1, param2 in matches:
if not self.is_subtype(param2.type, param1.type):
return False
return True

71
report/code/is_subtype.py Normal file
View File

@@ -0,0 +1,71 @@
def is_subtype(self, type1: Type, type2: Type) -> bool:
if type1 == type2:
return True
match (type1, type2):
case (_, TopType()):
return True
case (_, UnknownType()):
return True
case (BaseType(name=name1), BaseType(name=name2)):
return self.is_builtin_subtype(name1, name2)
case (TypeVar(bound=bound), _):
if bound is None:
return False
return self.is_subtype(bound, type2)
case (_, TypeVar(bound=bound)):
if bound is None:
return True
return self.is_subtype(type1, bound)
case (DerivedType(type=base1), _):
return self.is_subtype(base1, type2)
case (ConstraintType(type=base1), _):
return self.is_subtype(base1, type2)
case (
AppliedType(name=name1, args=args1),
AppliedType(name=name2, args=args2),
) if (
name1 == name2
):
generic: Type = self.get_type(name1)
assert isinstance(generic, GenericType)
for param, arg1, arg2 in zip(generic.params, args1, args2):
variance: Variance = param.variance
if variance in {Variance.INVARIANT, Variance.COVARIANT}:
if not self.is_subtype(arg1, arg2):
return False
if variance in {Variance.INVARIANT, Variance.CONTRAVARIANT}:
if not self.is_subtype(arg2, arg1):
return False
return True
case (AppliedType(body=body), _):
return self.is_subtype(body, type2)
case (DataFrameType(columns=columns1), DataFrameType(columns=columns2)):
by_name1: dict[str, DataFrameType.Column] = {
col.name: col for col in columns1 if col.name is not None
}
for col2 in columns2:
if col2.name not in by_name1:
return False
if not self.is_subtype(by_name1[col2.name].type, col2.type):
return False
return True
case (ColumnType(type=inner1), ColumnType(type=inner2)):
if not self.are_equivalent(inner1, inner2):
return False
return True
case (Function(), Function()):
return self.is_func_subtype(type1, type2)
return False

View File

@@ -0,0 +1,88 @@
class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[Type], m.Type.Visitor[Type]):
logger: logging.Logger
reporter: FileReporter
types: TypesRegistry
dispatcher: CallDispatcher[m.Expr]
_local_variables: dict[str, TypeVar]
_predicate_params: dict[str, Type]
_current_name: Optional[str]
_preamble: Environment
def type_of(self, expr: m.Expr) -> Type:
"""Compute the type of the given expression
Args:
expr (m.Expr): the expression to type
Returns:
Type: the type of the expression
"""
type: Type = expr.accept(self)
return type
def get_type(self, name: str) -> Type:
"""Get a type from its name
Args:
name (str): the name of the type
Raises:
NameError: if the type is not defined
Returns:
Type: the type
"""
if name in self._local_variables:
return self._local_variables[name]
return self.types.get_type(name)
def get_variable(self, location: Location, name: str) -> Type:
"""Get the type of a variable
This function will first look into the current predicate's parameters if
we are in a predicate definition.
The the variable is looked up in the preamble (i.e. global environment)
Args:
location (Location): the location of the variable reference
name (str): the name of the variable
Returns:
Type: the type of the variable
"""
if name in self._predicate_params:
return self._predicate_params[name]
predicate: Optional[Predicate] = self.types.lookup_predicate(name)
if predicate is not None:
return predicate.type
global_: Optional[Type] = self._preamble.get(name)
if global_ is not None:
return global_
self.reporter.error(location, f"Unknown variable '{name}'")
return UnknownType()
def resolve(self, stmts: list[m.Stmt]):
"""Process a sequence of statements
Args:
stmts (list[m.Stmt]): the statements
"""
for stmt in stmts:
stmt.accept(self)
manager: VarianceManager = VarianceManager(self.types)
manager.infer_all()
def assert_bool(self, expr: m.Expr):
"""Check that the given expression is a subtype of `bool` or report an error
Args:
expr (m.Expr): the expression to check
"""
type: Type = self.type_of(expr)
if not self.types.is_subtype(type, self._bool):
self.reporter.error(expr.location, f"Must be a boolean but is {type}")

View File

@@ -0,0 +1,119 @@
def visit_function(self, stmt: p.Function) -> None:
env: Environment = Environment(self.env)
pos: list[Function.Parameter] = []
mixed: list[Function.Parameter] = []
kw: list[Function.Parameter] = []
def eval_param_type(param: p.Function.Parameter) -> Type:
default_type: Optional[Type] = None
if param.default is not None:
default_type = self.type_of(param.default)
if param.type is not None:
param_type: Type = self.resolve_type_expr(param.type)
if default_type is not None:
if not self.types.is_subtype(default_type, param_type):
self.reporter.error(
param.location or stmt.location,
f"Cannot use default value of type {default_type} for parameter of type {param_type}",
)
return param_type
if default_type is not None:
return default_type
return UnknownType()
position: int = 0
for param in stmt.params.pos:
pos.append(
Function.Parameter(
pos=position,
name=param.name,
type=eval_param_type(param),
required=param.default is None,
)
)
position += 1
for param in stmt.params.mixed:
mixed.append(
Function.Parameter(
pos=position,
name=param.name,
type=eval_param_type(param),
required=param.default is None,
)
)
position += 1
for param in stmt.params.kw:
kw.append(
Function.Parameter(
pos=position,
name=param.name,
type=eval_param_type(param),
required=param.default is None,
)
)
position += 1
param_spec: ParamSpec = ParamSpec(
pos=pos,
mixed=mixed,
kw=kw,
)
all_params: list[Function.Parameter] = pos + mixed + kw
for param in all_params:
env.define(param.name, param.type)
returns_hint: Optional[Type] = None
if stmt.returns is not None:
returns_hint = self.resolve_type_expr(stmt.returns)
inside_function: Function = Function(
params=param_spec,
returns=returns_hint,
)
self.env.define(stmt.name, inside_function)
returned: bool = self.process_block(stmt.body, env)
inferred_return: Type = UnknownType()
if not returned:
env.return_types.append(UnitType())
return_types: list[Type] = self.types.reduce_types(env.return_types)
if len(return_types) == 1:
inferred_return = return_types[0]
elif len(return_types) > 1:
self.reporter.error(
stmt.location,
f"Mixed return types: {return_types}",
)
returns: Type = UnknownType()
if returns_hint is not None:
assert stmt.returns is not None
returns = returns_hint
if not self.is_subtype(inferred_return, returns):
self.reporter.error(
stmt.returns.location,
f"Return type mismatch, annotated {returns} but returns {inferred_return}",
)
else:
returns = inferred_return
function: Type = Function(
params=param_spec,
returns=returns,
)
generic_params: list[TypeVar] = []
all_types: list[Type] = [param.type for param in all_params] + [returns]
for type in all_types:
if isinstance(type, TypeVar):
if type not in generic_params:
generic_params.append(type)
if len(generic_params) != 0:
function = GenericType(
name=stmt.name,
params=generic_params,
body=function,
)
self.env.define(stmt.name, function)

View File

@@ -0,0 +1,66 @@
Polarity = Literal[-1, 0, 1]
class VarianceInferrer:
def __init__(self, manager: VarianceManager) -> None:
self.manager: VarianceManager = manager
self.tracker: Tracker = Tracker([])
@property
def types(self) -> TypesRegistry:
return self.manager.types
def infer(self, type: GenericType) -> GenericType:
self.tracker = Tracker(type.params)
self.walk(type.body, 1, type.name)
members: dict[str, Member] = self.types._members.get(type.name, {})
for name, member in members.items():
self.walk(member.type, 1, type.name)
return GenericType(
name=type.name,
params=self.tracker.get_updated_vars(),
body=type.body,
)
def walk(
self,
type: Type,
polarity: Polarity,
base_name: str,
):
match type:
case Function(params=spec):
all_params: list[Function.Parameter] = spec.pos + spec.mixed + spec.kw
for param in all_params:
self.walk(
param.type,
-polarity,
base_name,
)
self.walk(type.returns, polarity, base_name)
case OverloadedFunction(overloads=overloads):
for overload in overloads:
self.walk(overload, polarity, base_name)
case AppliedType(name=name, args=args):
if self.manager.is_in_queue(name):
return
generic: Type = self.types.get_type(name)
assert isinstance(generic, GenericType)
generic = self.manager.infer(name, generic)
params: list[TypeVar] = generic.params
polarities: dict[Variance, Polarity] = {
Variance.INVARIANT: 0,
Variance.COVARIANT: 1,
Variance.CONTRAVARIANT: -1,
}
for arg, param in zip(args, params):
param_polarity: Polarity = polarities[param.variance]
self.walk(
arg,
cast(Polarity, polarity * param_polarity),
base_name,
)
case ConstraintType(type=base):
self.walk(base, polarity, base_name)
case TypeVar():
if type in self.tracker:
self.tracker.record(type, polarity)

View File

@@ -0,0 +1,27 @@
class VarianceManager:
def __init__(self, types: TypesRegistry) -> None:
self.types: TypesRegistry = types
self._queue: list[str] = []
self._inferred: set[str] = set()
def infer_all(self):
for name, type in self.types._types.items():
if isinstance(type, GenericType):
self.infer(name, type)
def infer(self, name: str, type: GenericType) -> GenericType:
if self.is_inferred(name):
return type
self._queue.append(name)
inferrer: VarianceInferrer = VarianceInferrer(self)
inferred: GenericType = inferrer.infer(type)
self.types._types[name] = inferred
self._queue.pop()
self._inferred.add(name)
return inferred
def is_in_queue(self, name: str) -> bool:
return name in self._queue
def is_inferred(self, name: str) -> bool:
return name in self._inferred

View File

@@ -0,0 +1,28 @@
class Tracker:
def __init__(self, vars: list[TypeVar]) -> None:
self.vars: list[TypeVar] = vars
self.refs: dict[str, set[Polarity]] = {var.name: set() for var in self.vars}
def record(self, var: TypeVar, polarity: Polarity):
self.refs[var.name].add(polarity)
def get_updated_vars(self) -> list[TypeVar]:
return [
TypeVar(
name=var.name, bound=var.bound, variance=self.get_variance(var.name)
)
for var in self.vars
]
def get_variance(self, name: str) -> Variance:
refs: set[Polarity] = self.refs[name]
if refs == {-1}:
return Variance.CONTRAVARIANT
if refs == {1}:
return Variance.COVARIANT
return Variance.INVARIANT
def __contains__(self, item: TypeVar | str):
if isinstance(item, TypeVar):
return item.name in self
return item in self.refs

View File

@@ -0,0 +1,70 @@
#import "@preview/cetz:0.5.2": canvas, draw
#import "@preview/fletcher:0.5.8" as fletcher: diagram, node, edge
#let overview = diagram(
node-stroke: .6pt,
node-fill: white,
node((0, 0), [Midas Typer], name: <midas>),
node((1, 0), [Python Typer], name: <python>),
node((0.5, 1), [Types Registry], name: <reg>),
node((1, 2), [Generator], name: <gen>),
edge(<midas>, "d", <reg>, "<|-|>"),
edge(<python>, "d", <reg>, "<|-"),
edge((<python.south>, 50%, <python.south-east>), "d", <gen>, "-|>"),
edge(<reg>, "d", <gen>, "-|>"),
node(align(bottom + left)[*Type Checker*], enclose: (<midas>, <python>, <reg>, <gen>), fill: teal.lighten(80%)),
node((-1, 0), [Midas File], name: <midas-file>),
node((-1, 1), [Python File], name: <python-file>),
edge(
<midas-file.south>,
((), "|-", (-1, 0.4)),
((), "-|", (<midas.south-west>, 50%, <midas.south>)),
((), "|-", <midas.south>),
"=|>",
mark-scale: 150%
),
edge(
<python-file.north>,
((), "|-", (-1, 0.6)),
((), "-|", (<python.south-west>, 50%, <python.south>)),
((), "|-", <python.south>),
"=|>",
mark-scale: 150%
),
/*node((-1, .5), [
types.midas\
source.py
], name: <files>),*/
/*edge(
(<files.north-east>, 80%, <files.east>),
((), "-|", (<midas.south-west>, 50%, <midas.south>)),
((), "|-", <midas.south>),
"=|>",
mark-scale: 150%,
),
edge(
(<files.south-east>, 80%, <files.east>),
((), "-|", (<python.south-west>, 50%, <python.south>)),
((), "|-", <python.south>),
"=|>",
mark-scale: 150%,
)*/
node((3, 1.5), [Stubs], name: <stubs>, width: 5.5em),
node((3, 2), [Generated Python], name: <output>, width: 5.5em),
edge(
<gen>,
<output>,
"=|>",
mark-scale: 150%
),
edge(
<gen>,
"r",
((), "|-", <stubs>),
<stubs>,
"=|>",
mark-scale: 150%
)
)

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="220" height="70" viewBox="0 0 220 70">
<!-- Placeholder handwritten-style signature for the template example. -->
<path d="M8 50 C 30 10, 45 60, 60 35 S 85 5, 100 40 C 110 60, 120 20, 135 38 S 165 55, 185 25 C 195 12, 205 30, 212 22"
fill="none" stroke="#1a2b6b" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M70 55 C 110 48, 150 58, 200 50" fill="none" stroke="#1a2b6b" stroke-width="1.2" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 514 B

16
report/fonts/README.md Normal file
View File

@@ -0,0 +1,16 @@
# License
All the fonts downloaded by this script for the layout of the documents are licensed under the [SIL Open Font License](https://openfontlicense.org/) which is included in [here](ofl.md).
## Installing fonts
This report template uses several fonts packaged in this repository. To install the fonts in a Linux environment, simply type:
```bash
source install_fonts.sh
```
from within the `fonts` directory and voilà!
The installer also creates a local fontconfig alias so Linux maps `Source Sans Pro` to `Source Sans 3`.
This keeps Typst/web template naming compatibility while avoiding missing-font warnings on Linux.

View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
VU="${GREEN}${NC}"
# v2: ships both "Source Sans 3" and "Source Sans Pro" (v2 name used by the
# Typst web editor) so templates compile without font warnings on both CLI and web.
FONTS_URL="https://files.isc-vs.ch/typst/modern-isc-fonts-v2.tar.gz"
FONTS_ARCHIVE="modern-isc-fonts-v2.tar.gz"
FONTS_DIR="modern-isc-fonts-v2"
echo -e "Downloading and installing fonts locally..."
fonts_dir="${HOME}/.local/share/fonts"
if [ ! -d "${fonts_dir}" ]; then
mkdir -p "${fonts_dir}"
echo -e "Created fonts directory $fonts_dir $VU"
else
echo -e "Found fonts directory $fonts_dir $VU"
fi
wget -q --show-progress "${FONTS_URL}"
if [ $? -ne 0 ]; then
echo -e "${RED}Error: Failed to download ${FONTS_ARCHIVE}.${NC}"
exit 1
fi
echo -e "Font bundle downloaded $VU"
tar -zxf "${FONTS_ARCHIVE}"
cp "${FONTS_DIR}"/*.ttf "${fonts_dir}/"
cp "${FONTS_DIR}"/*.otf "${fonts_dir}/"
echo -e "Fonts installed $VU"
echo -e "Rebuilding font cache..."
fc-cache -f
echo -e "Font cache rebuilt $VU"
rm -f "${FONTS_ARCHIVE}"
rm -rf "${FONTS_DIR}/"
# Verify all required fonts are visible to Typst
missing_fonts=()
for font in "Source Sans Pro" "Source Sans 3" "Inria Sans" "Fira Code"; do
if ! typst fonts | grep -q "^${font}$"; then
missing_fonts+=("$font")
fi
done
if [ ${#missing_fonts[@]} -eq 0 ]; then
echo -e "${VU} All required fonts found in Typst. Install successful!"
else
echo -e "${RED}The following fonts were not found by Typst: ${missing_fonts[*]}${NC}"
exit 1
fi

113
report/fonts/ofl.md Normal file
View File

@@ -0,0 +1,113 @@
Copyright &#40;c) ``<dates>``, ``<Copyright Holder>`` (``<URL|email>``),
with Reserved Font Name ``<Reserved Font Name>``.
Copyright &#40;c) ``<dates>``, ``<additional Copyright Holder>`` (``<URL|email>``),
with Reserved Font Name ``<additional Reserved Font Name>``.
Copyright &#40;c) ``<dates>``, ``<additional Copyright Holder>`` (``<URL|email>``).
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
<https://openfontlicense.org>
---
# SIL OPEN FONT LICENSE
##### *Version 1.1 - 26 February 2007*
PREAMBLE
----------
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
-------------
***Font Software*** refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
***Reserved Font Name*** refers to any names specified as such after the
copyright statement(s).
***Original Version*** refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
***Modified Version*** refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
***Author*** refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
------------------------
Permission is hereby granted, free of charge, to any person obtaining
a copy of the ***Font Software***, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the ***Font
Software***, subject to the following conditions:
1) Neither the ***Font Software*** nor any of its individual components,
in ***Original*** or ***Modified Versions***, may be sold by itself.
2) ***Original*** or ***Modified Versions*** of the ***Font Software*** may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No ***Modified Version*** of the ***Font Software*** may use the ***Reserved Font
Name(s)*** unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the ***Author(s)*** of the ***Font
Software*** shall not be used to promote, endorse or advertise any
***Modified Version***, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the ***Author(s)*** or with their explicit written
permission.
5) The ***Font Software***, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the ***Font Software***.
TERMINATION
-----------
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
-----------
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

21
report/pages/abstract.typ Normal file
View File

@@ -0,0 +1,21 @@
#import "@preview/isc-hei-bthesis:0.8.1" : *
#page-title("Abstract")
#v(1fr)
The abstract of a bachelor thesis should provide a concise summary of the entire work. It typically includes:
- The context and motivation for the research.
- The main objective or research question.
- A brief description of the methodology or approach used.
- The key results or findings.
- The main conclusion or implications of the work.
The abstract should be self-contained, clear, and usually does not exceed 250300 words. It allows readers to quickly understand the purpose and outcomes of the thesis without reading the full document.
The abstract *must* be written in both French and English.
#lorem(150)
#abstract-footer("en")

View File

@@ -0,0 +1,18 @@
#import "@preview/isc-hei-bthesis:0.8.1" : *
// Get the proper title for acknowledgements if not written in English
#page-title(context i18n(inc.global-language.get(), "acknowledgements"))
#v(1fr)
The *Acknowledgements* section of a bachelor thesis is where you express gratitude to those who supported you during your research and writing process. It is an *OPTIONAL* section. It may include:
- Academic supervisors or advisors who provided guidance.
- Professors or instructors who offered feedback or resources.
- Family and friends for emotional or practical support.
- Institutions or organizations that provided funding, facilities, or data.
- Anyone else who contributed significantly to your work.
Keep this section concise and sincere. It is typically placed after the abstract and before the main content of your thesis.
#v(1fr)

21
report/pages/résumé.typ Normal file
View File

@@ -0,0 +1,21 @@
#import "@preview/isc-hei-bthesis:0.8.1" : *
#page-title("Résumé")
#v(1fr)
Le résumé dun mémoire de bachelor doit fournir un aperçu concis de lensemble du travail. Il inclut généralement:
- Le contexte et la motivation de la recherche.
- Lobjectif principal ou la question de recherche.
- Une brève description de la méthodologie ou de lapproche utilisée.
- Les principaux résultats ou découvertes.
- La conclusion principale ou les implications du travail.
Le résumé doit être autonome, clair et ne pas dépasser habituellement 250 à 300 mots. Il permet aux lecteurs de comprendre rapidement le but et les résultats du mémoire sans lire lintégralité du document.
Le résumé doit être rédigé en français *et* en anglais.
#lorem(150)
#abstract-footer("fr")

159
report/plan.typ Normal file
View File

@@ -0,0 +1,159 @@
= General Plan
1. *Abstract*: concise summary, includes: research question, methodology, results, conclusions
2. *Résumé*: summary in French
3. *Acknowledgements*: [Optional] thank those who supported your work
4. *Table of Contents*
5. *Introduction*: background/context, motivation, objectives, scope and plan
6. *State of the Art / Literature Review*: existing research and situates thesis within academic context, if relevant to the work
7. *Development and Methodology*: methods, materials, and procedures
8. *Results*: findings, often with tables, figures, and analysis
9. *Discussion*: Interpret results, discuss implications, and relate findings to research question
10. *Conclusion*: Summarize main findings and contributions, suggest future work
11. *References / Bibliography*: List all sources cited
12. *Appendices*: (Optional) Contains supplementary material such as raw data, code, or additional explanations
= Introduction
== Background / context
- Programming
- Deterministic -> ask the machine to do something, does it
- Ambiguities come from developer
- Python
- Duck typing
- (Highly) Dynamic
- Very popular, especially in data science
- Type hints
- Type theory introduction
- Why does the IDE know that float + str not valid, but not that EUR + USD is also invalid
== Motivation
- Python is often too flexible
- Can be good but also confusing for beginners
- Dangerous for production use
- Even type-checkers can be too lenient
- Runtime errors are the worst
- Hour-long pipeline process crashing in the middle can be costly
- Silent errors producing the wrong results are close to impossible to locate
- Manually checking things can be tedious and unrewarding
== Objectives
Create a type system on top of Python, using type hints, which can help detect non-trivial type errors (i.e. not necessarily structurally wrong, and also on complex types like dataframes), and produces runtime assertions to check type conformity where static checking is not possible.
This system should ensure soundness where types are annotated or inferred, while leaving the user free to omit some and perform unsafe operations.
The system must be flexible to allow checking various kinds of constraints (e.g. value domain, geometric shape, distribution, etc.) and allow extension.
Finally, the system must be simple to use for average Python developers, and be able to seamlessly integrate into existing Python code.
== Scope and plan
TODO
= State of the art
- Python type hints (https://peps.python.org/pep-0484/):
- base types
- type aliases
- structural subtyping with Protocols -> matches duck-typing (https://peps.python.org/pep-0544/)
- Existing type checkers
- MyPy / Pyright
- Existing libraries
- Pandera: runtime only, syntax heavy, but quite complete
- Similar ideas
- Gator system (https://capra.cs.cornell.edu/research/gator/)
= Development and methodology
2 sections:
1. theory
2. implementation
== Theory
- Identify requirements
- Introduction to TAPL
- Grammar and typing rules for Midas, paralleled with TAPL
- Omitted rules, simplifications, mechanisms not implemented
== Implementation
- Main elements
- Definition language
- Supported Python syntax (cf. grammar and typing rules)
- Parse and type check
- Produce user-facing diagnostics
- Generate runtime assertions
- Architecture overview
- Midas definition language
- Lexer + parser (Crafting Interpreters, Pebble)
- reference theory for grammar rules
- token location -> necessary later for diagnostics
- AST node generation, similar to CI (3 kinds, Stmt/Expr/Type)
- Typer
- reference theory for typing rules
- type structures
- types registry
- Python type checking
- Parsing (short paragraph about AST nodes)
- Resolver
- Cf. CI
- Assignment analysis
- Typer
- Returns / if-else
- Environment
- Static constraint evaluation
- Code generation
- Stubs
- Assertions
/*
Subjects:
- Variance inference
- Environment
- Resolver
- Evaluator
- CallDispatcher
- Registry (`is_subtype`)
- MethodRegistry (frames and columns)
*/
= Results
TODO
= Discussion
TODO
= Conclusion
TODO
== Future work
=== Python features
- support for more common structures and methods (e.g. numpy array, more methods on dataframes)
- support for more builtin types: Iterator, Sequence, etc.
- argument sinks
- while loops, lambdas, classes
- multi-file project and imports
=== Typing features
- expected type
- literal value propagation
=== Improvements
- more control on assertion type, for example to avoid expensive checks
- less redundant check for know part of type (e.g. a dataframe is still a dataframe if only the columns have changed)
- better integration with VSCode (e.g. inline diagnostics)
- generate checks for members (does the object being cast have the given properties and methods?)

1
report/requirements.typ Normal file
View File

@@ -0,0 +1 @@
#import "@preview/isc-hei-bthesis:0.8.1"

View File

@@ -0,0 +1,511 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!--
Name: 3024 day
Author: Jan T. Sott
License: Public Domain Mark 1.0
URL: https://github.com/idleberg/3024.tmTheme
Base16 template for TextMate by Chris Kempson (https://github.com/chriskempson)
-->
<plist version="1.0">
<dict>
<key>author</key>
<string>Jan T. Sott</string>
<key>name</key>
<string>3024 day</string>
<key>comment</key>
<string>https://github.com/idleberg/3024.tmTheme</string>
<key>semanticClass</key>
<string>theme.light.3024</string>
<key>colorSpaceName</key>
<string>sRGB</string>
<key>gutterSettings</key>
<dict>
<key>background</key>
<string>#f7f7f7</string>
<key>divider</key>
<string>#f7f7f7</string>
<key>foreground</key>
<string>#4a4543</string>
<key>selectionBackground</key>
<string>#f7f7f7</string>
<key>selectionForeground</key>
<string>#a5a2a2</string>
</dict>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>background</key>
<string>#f7f7f7</string>
<key>caret</key>
<string>#4a4543</string>
<key>foreground</key>
<string>#4a4543</string>
<key>invisibles</key>
<string>#d6d5d4</string>
<key>lineHighlight</key>
<string>#d6d5d4</string>
<key>selection</key>
<string>#d6d5d4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Text</string>
<key>scope</key>
<string>variable.parameter.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#4a4543</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Comments</string>
<key>scope</key>
<string>comment, punctuation.definition.comment</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#807d7c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation</string>
<key>scope</key>
<string>punctuation.definition.string, punctuation.definition.variable, punctuation.definition.string, punctuation.definition.parameters, punctuation.definition.string, punctuation.definition.array</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#4a4543</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Delimiters</string>
<key>scope</key>
<string>none</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#4a4543</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Operators</string>
<key>scope</key>
<string>keyword.operator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#4a4543</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keywords</string>
<key>scope</key>
<string>keyword, keyword.control</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#a16a94</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variables</string>
<key>scope</key>
<string>variable</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#db2d20</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Functions</string>
<key>scope</key>
<string>entity.name.function, meta.require, support.function.any-method</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#01a0e4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Classes</string>
<key>scope</key>
<string>meta.class, support.class, entity.name.class, entity.name.type.class</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ed0c8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Methods</string>
<key>scope</key>
<string>keyword.other.special-method</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#01a0e4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>storage</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#a16a94</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Support</string>
<key>scope</key>
<string>support.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#b5e4f4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Strings, Inherited Class</string>
<key>scope</key>
<string>string, constant.other.symbol, entity.other.inherited-class</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#01a252</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Integers</string>
<key>scope</key>
<string>constant.numeric</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ed0c8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Floats</string>
<key>scope</key>
<string>none</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ed0c8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Boolean</string>
<key>scope</key>
<string>none</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ed0c8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Constants</string>
<key>scope</key>
<string>constant</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ed0c8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tags</string>
<key>scope</key>
<string>entity.name.tag</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#db2d20</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Attributes</string>
<key>scope</key>
<string>entity.other.attribute-name</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ed0c8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Attribute IDs</string>
<key>scope</key>
<string>entity.other.attribute-name.id, punctuation.definition.entity</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#01a0e4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Selector</string>
<key>scope</key>
<string>meta.selector</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#a16a94</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Values</string>
<key>scope</key>
<string>none</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ed0c8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Headings</string>
<key>scope</key>
<string>markup.heading punctuation.definition.heading, entity.name.section</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#01a0e4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Units</string>
<key>scope</key>
<string>keyword.other.unit</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ed0c8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Bold</string>
<key>scope</key>
<string>markup.bold, punctuation.definition.bold</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#ed0c8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Italic</string>
<key>scope</key>
<string>markup.italic, punctuation.definition.italic</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#a16a94</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Code</string>
<key>scope</key>
<string>markup.raw.inline</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#01a252</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Link Text</string>
<key>scope</key>
<string>string.other.link</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#db2d20</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Link Url</string>
<key>scope</key>
<string>meta.link</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ed0c8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Lists</string>
<key>scope</key>
<string>markup.list</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#db2d20</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Quotes</string>
<key>scope</key>
<string>markup.quote</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ed0c8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Separator</string>
<key>scope</key>
<string>meta.separator</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#d6d5d4</string>
<key>foreground</key>
<string>#4a4543</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Inserted</string>
<key>scope</key>
<string>markup.inserted</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#01a252</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Deleted</string>
<key>scope</key>
<string>markup.deleted</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#db2d20</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Changed</string>
<key>scope</key>
<string>markup.changed</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#a16a94</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Colors</string>
<key>scope</key>
<string>constant.other.color</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#b5e4f4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Regular Expressions</string>
<key>scope</key>
<string>string.regexp</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#b5e4f4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Escape Characters</string>
<key>scope</key>
<string>constant.character.escape</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#b5e4f4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Embedded</string>
<key>scope</key>
<string>punctuation.section.embedded, variable.interpolation</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#cdab53</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid</string>
<key>scope</key>
<string>invalid.illegal</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#db2d20</string>
<key>foreground</key>
<string>#f7f7f7</string>
</dict>
</dict>
</array>
<key>uuid</key>
<string>14875ac8-6a02-493d-9cfa-1701c764e24b</string>
</dict>
</plist>

View File

@@ -0,0 +1,948 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!-- Generated by: TmTheme-Editor -->
<!-- ============================================ -->
<!-- app: http://tmtheme-editor.herokuapp.com -->
<!-- code: https://github.com/aziz/tmTheme-Editor -->
<plist version="1.0">
<dict>
<key>name</key>
<string>Angular-io-Code</string>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>background</key>
<string>#F5F6F7</string>
<key>foreground</key>
<string>#5C707A</string>
<key>invisibles</key>
<string>#5C707A</string>
<key>caret</key>
<string>#5C707A</string>
<key>gutter</key>
<string>#F5F6F7</string>
<key>gutterForeground</key>
<string>#5C707A</string>
<key>guide</key>
<string>#969896</string>
<key>stackGuide</key>
<string>#969896</string>
<key>activeGuide</key>
<string>#969896</string>
<key>lineHighlight</key>
<string>#FFFFFF00</string>
<key>findHighlight</key>
<string>#969896</string>
<key>findHighlightForeground</key>
<string>#969896</string>
<key>selection</key>
<string>#969896</string>
<key>selectionBorder</key>
<string>#ffffff</string>
<key>bracketsForeground</key>
<string>#647F11</string>
<key>bracketsOptions</key>
<string>underline</string>
<key>bracketContentsForeground</key>
<string>#647F11</string>
<key>bracketContentsOptions</key>
<string>underline</string>
<key>tagsForeground</key>
<string>#647F11</string>
<key>tagsOptions</key>
<string>underline</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Comment</string>
<key>scope</key>
<string>comment</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#969896</string>
<key>fontStyle</key>
<string>italic</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>String</string>
<key>scope</key>
<string>string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>RegExp Operator</string>
<key>scope</key>
<string>regexp-operator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>RegExp Character Class</string>
<key>scope</key>
<string>string.regexp.characterclass punctuation.definition.string.begin, string.regexp.characterclass punctuation.definition.string.end</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Number</string>
<key>scope</key>
<string>constant.numeric</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Built-in Constant</string>
<key>scope</key>
<string>constant.language</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>User-defined Constant</string>
<key>scope</key>
<string>constant.character, constant.other, variable.other.constant</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variable</string>
<key>scope</key>
<string>variable</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>keyword</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Bitwise</string>
<key>scope</key>
<string>bitwise-operator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>storage</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage Type</string>
<key>scope</key>
<string>storage.type</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Class Name</string>
<key>scope</key>
<string>entity.name.class</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Inherited Class</string>
<key>scope</key>
<string>entity.other.inherited-class</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function Name</string>
<key>scope</key>
<string>entity.name.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function Argument</string>
<key>scope</key>
<string>variable.parameter</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#5C707A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag Name</string>
<key>scope</key>
<string>entity.name.tag</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag Attribute</string>
<key>scope</key>
<string>entity.other.attribute-name</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library Function</string>
<key>scope</key>
<string>support.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library Constant</string>
<key>scope</key>
<string>support.constant</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library Class</string>
<key>scope</key>
<string>support.type, support.class</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library Variable</string>
<key>scope</key>
<string>support.other.variable</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid</string>
<key>scope</key>
<string>invalid, invalid.illegal, invalid.deprecated</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#f5f5f5</string>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Find-in-files Filename</string>
<key>scope</key>
<string>entity.name.filename.find-in-files</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#5C707A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Find-in-files Line Numbers</string>
<key>scope</key>
<string>constant.numeric.line-number.find-in-files, constant.numeric.line-number.match.find-in-files</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#969896</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Diff Header</string>
<key>scope</key>
<string>meta.diff.header</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#969896</string>
<key>background</key>
<string>#ffffff</string>
<key>fontStyle</key>
<string>italic</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Diff Header</string>
<key>scope</key>
<string>meta.diff.header punctuation.definition.from-file.diff</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
<key>background</key>
<string>#ffecec</string>
<key>fontStyle</key>
<string>italic </string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Diff Header</string>
<key>scope</key>
<string>meta.diff.header punctuation.definition.to-file.diff</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
<key>background</key>
<string>#eaffea</string>
<key>fontStyle</key>
<string>italic </string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Diff Range</string>
<key>scope</key>
<string>meta.diff.range</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#969896</string>
<key>fontStyle</key>
<string>italic </string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Diff Deleted</string>
<key>scope</key>
<string>markup.deleted</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#ffecec</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Diff Deleted Punctuation</string>
<key>scope</key>
<string>markup.deleted punctuation.definition.inserted</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Diff Inserted</string>
<key>scope</key>
<string>markup.inserted</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#eaffea</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Diff Inserted Punctuation</string>
<key>scope</key>
<string>markup.inserted punctuation.definition.inserted</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>GitGutter Deleted</string>
<key>scope</key>
<string>markup.deleted.git_gutter</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>GitGutter Inserted</string>
<key>scope</key>
<string>markup.inserted.git_gutter</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>GitGutter Modified</string>
<key>scope</key>
<string>markup.changed.git_gutter</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#969896</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>GitGutter Ignored</string>
<key>scope</key>
<string>markup.ignored.git_gutter</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#b3b3b3</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>GitGutter Untracked</string>
<key>scope</key>
<string>markup.untracked.git_gutter</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#b3b3b3</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Entity Punctuation</string>
<key>scope</key>
<string>source.css punctuation.definition.entity</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#5C707A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Pseudo Selector</string>
<key>scope</key>
<string>source.css entity.other.attribute-name.pseudo-class, source.css entity.other.attribute-name.pseudo-element</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Property Value</string>
<key>scope</key>
<string>source.css meta.value, source.css support.constant, source.css support.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Color</string>
<key>scope</key>
<string>source.css constant.other.color</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Entity Punctuation</string>
<key>scope</key>
<string>source.scss punctuation.definition.entity</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#5C707A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Pseudo Selector</string>
<key>scope</key>
<string>source.scss entity.other.attribute-name.pseudo-class, source.scss entity.other.attribute-name.pseudo-element</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Color</string>
<key>scope</key>
<string>source.scss support.constant.property-value, source.scss support.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variable</string>
<key>scope</key>
<string>source.scss variable</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>this</string>
<key>scope</key>
<string>variable.language.this.js</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function</string>
<key>scope</key>
<string>source.js entity.name.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
<key>fontStyle</key>
<string>regular</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function Definition</string>
<key>scope</key>
<string>source.js meta.function entity.name.function, source.js entity.name.function meta.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>New Function</string>
<key>scope</key>
<string>entity.name.type.new.js</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function Prototype</string>
<key>scope</key>
<string>variable.language.prototype.js</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Support Function</string>
<key>scope</key>
<string>source.js support.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function Prototype</string>
<key>scope</key>
<string>support.type.object.console.js</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON Property</string>
<key>scope</key>
<string>meta.structure.dictionary.json string.quoted.double.json</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#5C707A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON Value</string>
<key>scope</key>
<string>meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
<key>fontStyle</key>
<string>regular</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>source.python keyword</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>source.python storage</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage Type</string>
<key>scope</key>
<string>source.python storage.type</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function</string>
<key>scope</key>
<string>source.python entity.name.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Class</string>
<key>scope</key>
<string>source.php entity.name.type.class</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Language Variable</string>
<key>scope</key>
<string>variable.language.ruby</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Module Name</string>
<key>scope</key>
<string>entity.name.type.module.ruby</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Class Name</string>
<key>scope</key>
<string>entity.name.type.class.ruby</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Inherited Class</string>
<key>scope</key>
<string>entity.other.inherited-class.ruby</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation</string>
<key>scope</key>
<string>punctuation.definition.heading.markdown, punctuation.definition.italic.markdown, punctuation.definition.bold.markdown, punctuation.definition.string.begin.markdown, punctuation.definition.string.end.markdown, punctuation.definition.metadata.markdown, punctuation.definition.link.markdown, punctuation.definition.blockquote.markdown, punctuation.definition.raw.markdown</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Separator</string>
<key>scope</key>
<string>text.html.markdown meta.separator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#5C707A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Heading</string>
<key>scope</key>
<string>text.html.markdown markup.heading</string>
<key>settings</key>
<dict>
</dict>
</dict>
<dict>
<key>name</key>
<string>Code Block</string>
<key>scope</key>
<string>text.html.markdown markup.raw.block</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#5C707A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Inline Code</string>
<key>scope</key>
<string>text.html.markdown markup.raw.inline</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#5C707A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Link and Image</string>
<key>scope</key>
<string>text.html.markdown meta.link, text.html.markdown meta.image</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Link URL</string>
<key>scope</key>
<string>text.html.markdown markup.underline.link, text.html.markdown constant.other.reference</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>List</string>
<key>scope</key>
<string>text.html.markdown markup.list</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Bold</string>
<key>scope</key>
<string>text.html.markdown markup.bold</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string> bold</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Italic</string>
<key>scope</key>
<string>text.html.markdown markup.italic</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Bold Italic</string>
<key>scope</key>
<string>text.html.markdown markup.bold markup.italic</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string> italic bold</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Italic Bold</string>
<key>scope</key>
<string>text.html.markdown markup.italic markup.bold</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic bold</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Decorators</string>
<key>scope</key>
<string>tag.decorator.js entity.name.tag.js, tag.decorator.js punctuation.definition.tag.js, tag.decorator.ts entity.name.tag.ts, tag.decorator.ts punctuation.definition.tag.ts</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#647F11</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Type</string>
<key>scope</key>
<string>meta.return.type, meta.return-type, meta.cast, meta.type.annotation, support.type, entity.name.class, entity.name.type, storage.type.cs, storage.type.java</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D43669</string>
</dict>
</dict>
</array>
<key>colorSpaceName</key>
<string>sRGB</string>
<key>semanticClass</key>
<string>theme.light.angular-io-code</string>
<key>author</key>
<string>NoHomey</string>
<key>comment</key>
<string>Angular.io inspired theme</string>
</dict>
</plist>

View File

@@ -0,0 +1,294 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>author</key>
<string>Austin Cummings</string>
<key>name</key>
<string>Chrome DevTools</string>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>background</key>
<string>#FFFFFF</string>
<key>caret</key>
<string>#000000</string>
<key>foreground</key>
<string>#000000</string>
<key>invisibles</key>
<string>#B3B3B3F4</string>
<key>lineHighlight</key>
<string>#0000001A</string>
<key>selection</key>
<string>#BAD6FD</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>String</string>
<key>scope</key>
<string>string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#C41A16</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Number</string>
<key>scope</key>
<string>constant.numeric</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#1C00CF</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>keyword</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#AA0D91</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Operator</string>
<key>scope</key>
<string>keyword.operator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#000000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Identifier</string>
<key>scope</key>
<string>constant.language</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#AA0D91</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Exception</string>
<key>scope</key>
<string>support.class.exception</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#990000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function name</string>
<key>scope</key>
<string>entity.name.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#000000</string>
<!-- <key>fontStyle</key>
<string>italic</string> -->
</dict>
</dict>
<dict>
<key>name</key>
<string>Type name</string>
<key>scope</key>
<string>entity.name.type</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold underline</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Arguments</string>
<key>scope</key>
<string>variable.parameter</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Comment</string>
<key>scope</key>
<string>comment</string>
<key>settings</key>
<dict>
<!-- <key>fontStyle</key>
<string>italic</string> -->
<key>foreground</key>
<string>#007400</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid</string>
<key>scope</key>
<string>invalid</string>
<key>settings</key>
<dict>
<!-- <key>background</key>
<string>#E71A114D</string> -->
<key>foreground</key>
<string>#FF0000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Trailing whitespace</string>
<key>scope</key>
<string>invalid.deprecated.trailing-whitespace</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#E71A1100</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Embedded source</string>
<key>scope</key>
<string>text source</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#FAFAFAFC</string>
<key>foreground</key>
<string>#000000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag</string>
<key>scope</key>
<string>meta.tag, declaration.tag</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#AA0D91</string>
</dict>
</dict>
<!-- <dict>
<key>name</key>
<string>Constant</string>
<key>scope</key>
<string>constant, support.constant</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#000000</string>
</dict>
</dict> -->
<dict>
<key>name</key>
<string>Support</string>
<key>scope</key>
<string>support</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#000000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>storage</string>
<key>settings</key>
<dict>
<!-- <key>fontStyle</key>
<string>bold</string> -->
<key>foreground</key>
<string>#AA0D91</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Section name</string>
<key>scope</key>
<string>entity.name.section</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold underline</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Frame title</string>
<key>scope</key>
<string>entity.name.function.frame</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#000000</string>
<!-- <string>#881280</string> -->
</dict>
</dict>
<dict>
<key>name</key>
<string>XML Declaration</string>
<key>scope</key>
<string>meta.tag.preprocessor.xml</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#333333</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag Attribute</string>
<key>scope</key>
<string>entity.other.attribute-name</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<!-- <string>#3366CC</string> -->
<string>#994500</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag Name</string>
<key>scope</key>
<string>entity.name.tag</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#881280</string>
<!-- <key>fontStyle</key>
<string>bold</string> -->
</dict>
</dict>
</array>
<key>uuid</key>
<string>4FCFA210-B247-11D9-9D00-000D93347A42</string>
</dict>
</plist>

View File

@@ -0,0 +1,436 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>author</key>
<string>Kobzarev Mikhail</string>
<key>name</key>
<string>EditPlus</string>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>background</key>
<string>#FFFFFF</string>
<key>caret</key>
<string>#000000</string>
<key>foreground</key>
<string>#000000</string>
<key>invisibles</key>
<string>#B3B3B3F4</string>
<key>lineHighlight</key>
<string>#00808060</string>
<key>selection</key>
<string>#BAD6FD</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>String</string>
<key>scope</key>
<string>string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#FF00FF</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Number</string>
<key>scope</key>
<string>constant.numeric</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#800080</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Regular expression</string>
<key>scope</key>
<string>string.regexp</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#FF0080</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>keyword</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0000FF</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Identifier</string>
<key>scope</key>
<string>constant.language</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0000FF</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Exception</string>
<key>scope</key>
<string>support.class.exception</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#990000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function name</string>
<key>scope</key>
<string>entity.name.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#800000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Type name</string>
<key>scope</key>
<string>entity.name.type</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold underline</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Arguments</string>
<key>scope</key>
<string>variable.parameter</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Comment</string>
<key>scope</key>
<string>comment</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#008000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid</string>
<key>scope</key>
<string>invalid</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#E71A114D</string>
<key>foreground</key>
<string>#FF0000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Trailing whitespace</string>
<key>scope</key>
<string>invalid.deprecated.trailing-whitespace</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#E71A1100</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Embedded source</string>
<key>scope</key>
<string>text source</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#FFFFFF</string>
<key>foreground</key>
<string>#800000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Functions Alt</string>
<key>scope</key>
<string>support.function.construct</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#FFFFFF</string>
<key>foreground</key>
<string>#0000FF</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag</string>
<key>scope</key>
<string>meta.tag, declaration.tag</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0033CC</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Constant</string>
<key>scope</key>
<string>constant, support.constant</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#800000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Support</string>
<key>scope</key>
<string>support</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#3333FF</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation</string>
<key>scope</key>
<string>punctuation.definition.variable</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#3333FF</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation Alt</string>
<key>scope</key>
<string>punctuation.definition.string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#FF00FF</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Object Ref</string>
<key>scope</key>
<string>meta.function-call</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#800000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Var Alt</string>
<key>scope</key>
<string>variable.other</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#800000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Var Alt 2</string>
<key>scope</key>
<string>variable.other.php</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#008080</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation Alt</string>
<key>scope</key>
<string>punctuation.section.embedded</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#800000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Operators Alt</string>
<key>scope</key>
<string>keyword.operator.assignment</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#800000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Operators Alt 2</string>
<key>scope</key>
<string>keyword.operator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#800000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Operators Alt 3</string>
<key>scope</key>
<string>storage.modifier</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#800000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>SQL</string>
<key>scope</key>
<string>punctuation.definition.string.begin</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#FF00FF</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>storage</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#3333FF</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Section name</string>
<key>scope</key>
<string>entity.name.section</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold underline</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Frame title</string>
<key>scope</key>
<string>entity.name.function.frame</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#0000FF</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>XML Declaration</string>
<key>scope</key>
<string>meta.tag.preprocessor.xml</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#333333</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag Attribute</string>
<key>scope</key>
<string>entity.other.attribute-name</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#FF0000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag Name</string>
<key>scope</key>
<string>entity.name.tag</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>SublimeLinter Error</string>
<key>scope</key>
<string>sublimelinter.mark.error</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#D02000</string>
</dict>
</dict><dict>
<key>name</key>
<string>SublimeLinter Warning</string>
<key>scope</key>
<string>sublimelinter.mark.warning</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#DDB700</string>
</dict>
</dict><dict>
<key>name</key>
<string>SublimeLinter Gutter Mark</string>
<key>scope</key>
<string>sublimelinter.gutter-mark</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#FFFFFF</string>
</dict>
</dict></array>
<key>uuid</key>
<string>4FCFA210-B247-11D9-9D00-000D93347A42</string>
</dict>
</plist>

View File

@@ -0,0 +1,374 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>author</key>
<string>Ankur Gupta</string>
<key>name</key>
<string>GitHub Clean White</string>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>background</key>
<string>#FFFFFF</string>
<key>caret</key>
<string>#000000</string>
<key>foreground</key>
<string>#000000</string>
<key>invisibles</key>
<string>#B3B3B3F4</string>
<key>lineHighlight</key>
<string>#0000001A</string>
<key>selection</key>
<string>#BAD6FD</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>String</string>
<key>scope</key>
<string>string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#C41A16</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Number</string>
<key>scope</key>
<string>constant.numeric</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0086B3</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>keyword</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#A71D5D</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Operator</string>
<key>scope</key>
<string>keyword.operator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#000000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Built-in constant</string>
<key>scope</key>
<string>constant.language</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0086B3</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Exception</string>
<key>scope</key>
<string>support.class.exception</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#990000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function name</string>
<key>scope</key>
<string>entity.name.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#000000</string>
<!-- <key>fontStyle</key>
<string>italic</string> -->
</dict>
</dict>
<dict>
<key>name</key>
<string>Type name</string>
<key>scope</key>
<string>entity.name.type</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold underline</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Arguments</string>
<key>scope</key>
<string>variable.parameter</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Comment</string>
<key>scope</key>
<string>comment</string>
<key>settings</key>
<dict>
<!-- <key>fontStyle</key>
<string>italic</string> -->
<key>foreground</key>
<string>#969896</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid</string>
<key>scope</key>
<string>invalid</string>
<key>settings</key>
<dict>
<!-- <key>background</key>
<string>#E71A114D</string> -->
<key>foreground</key>
<string>#FF0000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Trailing whitespace</string>
<key>scope</key>
<string>invalid.deprecated.trailing-whitespace</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#E71A1100</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Embedded source</string>
<key>scope</key>
<string>text source</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#FAFAFAFC</string>
<key>foreground</key>
<string>#000000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag</string>
<key>scope</key>
<string>meta.tag, declaration.tag</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#AA0D91</string>
</dict>
</dict>
<!-- <dict>
<key>name</key>
<string>Constant</string>
<key>scope</key>
<string>constant, support.constant</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#000000</string>
</dict>
</dict> -->
<dict>
<key>name</key>
<string>Support</string>
<key>scope</key>
<string>support</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#000000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>storage</string>
<key>settings</key>
<dict>
<!-- <key>fontStyle</key>
<string>bold</string> -->
<key>foreground</key>
<string>#AA0D91</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Section name</string>
<key>scope</key>
<string>entity.name.section</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold underline</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Frame title</string>
<key>scope</key>
<string>entity.name.function.frame</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#000000</string>
<!-- <string>#881280</string> -->
</dict>
</dict>
<dict>
<key>name</key>
<string>XML Declaration</string>
<key>scope</key>
<string>meta.tag.preprocessor.xml</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#333333</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>html attribute</string>
<key>scope</key>
<string>entity.other.attribute-name</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<!-- <string>#3366CC</string> -->
<string>#0A8585</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>html tag punctuation</string>
<key>scope</key>
<string>entity.name.tag</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#121289</string>
<!-- <key>fontStyle</key>
<string>bold</string> -->
</dict>
</dict>
<!-- Adding stuff for diff. This works in ST3 -->
<dict>
<key>name</key>
<string>diff header from</string>
<key>scope</key>
<string>meta.diff.header.from-file</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#FFDDDD</string>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#000000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>diff header to</string>
<key>scope</key>
<string>meta.diff.header.to-file</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#DDFFDD</string>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#000000</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>diff inserted</string>
<key>scope</key>
<string>markup.inserted.diff</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#DDFFDD</string>
<key>fontStyle</key>
<string></string>
</dict>
</dict>
<dict>
<key>name</key>
<string>diff deleted</string>
<key>scope</key>
<string>markup.deleted.diff</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#FFDDDD</string>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#000000</string>
</dict>
</dict>
<!-- BracketHighlighter colors -->
<dict>
<key>name</key>
<string>BH Color</string>
<key>scope</key>
<string>brackethighlighter.default</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#FF992244</string>
<key>fontStyle</key>
<string>italic</string>
</dict>
</dict>
</array>
<key>uuid</key>
<string>26786979-843B-4FE2-BCB6-4FCEC6F8FB58</string>
<key>colorSpaceName</key>
<string>sRGB</string>
<key>semanticClass</key>
<string>theme.light.git_hub_clean_white</string>
<key>comment</key>
<string>v1.0 Feb 1, 2015
Made to look as close to GitHub as possible.</string>
</dict>
</plist>

View File

@@ -0,0 +1,643 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>author</key>
<string>GitHub</string>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>selection</key>
<string>#c8c8fa</string>
<key>lineHighlight</key>
<string>#fafbfc</string>
<key>background</key>
<string>#fff</string>
<key>foreground</key>
<string>#24292e</string>
<key>invisibles</key>
<string>#959da5</string>
<key>caret</key>
<string>#24292e</string>
<key>diffRenamed</key>
<string>#fafbfc</string>
<key>diffModified</key>
<string>#f9c513</string>
<key>diffDeleted</key>
<string>#d73a49</string>
<key>diffAdded</key>
<string>#34d058</string>
<key>markdown</key>
<string>#f7f7f7</string>
<key>inactiveSelection</key>
<string>#fafbfc</string>
<key>selectionBorder</key>
<string>#fafbfc</string>
<key>findHighlight</key>
<string>#e36209</string>
<key>findHighlightForeground</key>
<string>#fff8f2</string>
<key>guide</key>
<string>#959da5</string>
<key>activeGuide</key>
<string>#24292e</string>
<key>stackGuide</key>
<string>#959da5</string>
<key>highlight</key>
<string>#444d56</string>
<key>popupCss</key>
<string>&lt;![CDATA[html { background-color: #e0e0e0; } h1, h2, h3, h4, h5, h6 { color: #005cc5; margin-top: 0.2em; margin-bottom: 0.2em; } h1 { font-size: 1.5em; } h2 { font-size: 1.4em; } h3 { font-size: 1.3em; } h4 { font-size: 1.2em; } h5 { font-size: 1.1em; } h6 { font-size: 1em; } blockquote { color: #22863a; display: block; font-style: italic; } pre { display: block; } a { color: #032f62; font-style: underline; } body { color: #24292e; background-color: #fff; margin: 1px; font-size: 1em; padding: 0.2em; } .danger { color: #b31d28; } .important, .attention { color: #6f42c1; } .caution, .warning { color: #e36209; } .note { color: #735c0f; }]]&gt;</string>
<key>highlightForeground</key>
<string>#444d56</string>
<key>tagsOptions</key>
<string>underline</string>
<key>bracketContentsOptions</key>
<string>underline</string>
<key>bracketContentsForeground</key>
<string>#24292e</string>
<key>bracketsOptions</key>
<string>underline</string>
<key>bracketsForeground</key>
<string>#24292e</string>
<key>gutterForeground</key>
<string>#24292e</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>comment, punctuation.definition.comment, string.comment</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#6a737d</string>
</dict>
<key>name</key>
<string>Comment</string>
</dict>
<dict>
<key>scope</key>
<string>constant, entity.name.constant, variable.other.constant, variable.language</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#005cc5</string>
</dict>
<key>name</key>
<string>Constant</string>
</dict>
<dict>
<key>scope</key>
<string>keyword.operator.symbole, keyword.other.mark</string>
<key>name</key>
<string>Clojure workaround; don't highlight these separately from their enclosing scope</string>
<key>settings</key>
<dict/>
</dict>
<dict>
<key>scope</key>
<string>entity, entity.name</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#6f42c1</string>
</dict>
<key>name</key>
<string>Entity</string>
</dict>
<dict>
<key>scope</key>
<string>variable.parameter.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#24292e</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>entity.name.tag</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#22863a</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>keyword</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#d73a49</string>
</dict>
<key>name</key>
<string>Keyword</string>
</dict>
<dict>
<key>scope</key>
<string>storage, storage.type</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#d73a49</string>
</dict>
<key>name</key>
<string>Storage</string>
</dict>
<dict>
<key>scope</key>
<string>storage.modifier.package, storage.modifier.import, storage.type.java</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#24292e</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>string, punctuation.definition.string, string punctuation.section.embedded source</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#032f62</string>
</dict>
<key>name</key>
<string>String</string>
</dict>
<dict>
<key>name</key>
<string>Ada workaround; don't highlight imports as strings</string>
<key>scope</key>
<string>string.unquoted.import.ada</string>
<key>settings</key>
<dict/>
</dict>
<dict>
<key>scope</key>
<string>support</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#005cc5</string>
</dict>
<key>name</key>
<string>Support</string>
</dict>
<dict>
<key>scope</key>
<string>meta.property-name</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#005cc5</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>variable</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#e36209</string>
</dict>
<key>name</key>
<string>Variable</string>
</dict>
<dict>
<key>scope</key>
<string>variable.other</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#24292e</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>invalid.broken</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold italic underline</string>
<key>foreground</key>
<string>#b31d28</string>
</dict>
<key>name</key>
<string>Invalid - Broken</string>
</dict>
<dict>
<key>scope</key>
<string>invalid.deprecated</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold italic underline</string>
<key>foreground</key>
<string>#b31d28</string>
</dict>
<key>name</key>
<string>Invalid Deprecated</string>
</dict>
<dict>
<key>scope</key>
<string>invalid.illegal</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic underline</string>
<key>background</key>
<string>#b31d28</string>
<key>foreground</key>
<string>#fafbfc</string>
</dict>
<key>name</key>
<string>Invalid Illegal</string>
</dict>
<dict>
<key>scope</key>
<string>carriage-return</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic underline</string>
<key>background</key>
<string>#d73a49</string>
<key>foreground</key>
<string>#fafbfc</string>
<key>content</key>
<string>^M</string>
</dict>
<key>name</key>
<string>Carriage Return</string>
</dict>
<dict>
<key>scope</key>
<string>invalid.unimplemented</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold italic underline</string>
<key>foreground</key>
<string>#b31d28</string>
</dict>
<key>name</key>
<string>Invalid - Unimplemented</string>
</dict>
<dict>
<key>scope</key>
<string>message.error</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#b31d28</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>string source</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#24292e</string>
</dict>
<key>name</key>
<string>String embedded-source</string>
</dict>
<dict>
<key>scope</key>
<string>string variable</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#005cc5</string>
</dict>
<key>name</key>
<string>String variable</string>
</dict>
<dict>
<key>scope</key>
<string>source.regexp, string.regexp</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#032f62</string>
</dict>
<key>name</key>
<string>String.regexp</string>
</dict>
<dict>
<key>scope</key>
<string>string.regexp.character-class, string.regexp constant.character.escape, string.regexp source.ruby.embedded, string.regexp string.regexp.arbitrary-repitition</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#032f62</string>
</dict>
<key>name</key>
<string>String.regexp.«special»</string>
</dict>
<dict>
<key>scope</key>
<string>string.regexp constant.character.escape</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#22863a</string>
</dict>
<key>name</key>
<string>String.regexp constant.character.escape</string>
</dict>
<dict>
<key>scope</key>
<string>support.constant</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#005cc5</string>
</dict>
<key>name</key>
<string>Support.constant</string>
</dict>
<dict>
<key>scope</key>
<string>support.variable</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#005cc5</string>
</dict>
<key>name</key>
<string>Support.variable</string>
</dict>
<dict>
<key>scope</key>
<string>meta.module-reference</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#005cc5</string>
</dict>
<key>name</key>
<string>meta module-reference</string>
</dict>
<dict>
<key>scope</key>
<string>markup.list</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#735c0f</string>
</dict>
<key>name</key>
<string>Markup.list</string>
</dict>
<dict>
<key>scope</key>
<string>markup.heading, markup.heading entity.name</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#005cc5</string>
</dict>
<key>name</key>
<string>Markup.heading</string>
</dict>
<dict>
<key>scope</key>
<string>markup.quote</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#22863a</string>
</dict>
<key>name</key>
<string>Markup.quote</string>
</dict>
<dict>
<key>scope</key>
<string>markup.italic</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#24292e</string>
</dict>
<key>name</key>
<string>Markup.italic</string>
</dict>
<dict>
<key>scope</key>
<string>markup.bold</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#24292e</string>
</dict>
<key>name</key>
<string>Markup.bold</string>
</dict>
<dict>
<key>scope</key>
<string>markup.raw</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string/>
<key>foreground</key>
<string>#005cc5</string>
</dict>
<key>name</key>
<string>Markup.raw</string>
</dict>
<dict>
<key>scope</key>
<string>markup.deleted, meta.diff.header.from-file, punctuation.definition.deleted</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#ffeef0</string>
<key>foreground</key>
<string>#b31d28</string>
</dict>
<key>name</key>
<string>Markup.deleted</string>
</dict>
<dict>
<key>scope</key>
<string>markup.inserted, meta.diff.header.to-file, punctuation.definition.inserted</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#f0fff4</string>
<key>foreground</key>
<string>#22863a</string>
</dict>
<key>name</key>
<string>Markup.inserted</string>
</dict>
<dict>
<key>scope</key>
<string>markup.changed, punctuation.definition.changed</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#ffebda</string>
<key>foreground</key>
<string>#e36209</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>markup.ignored, markup.untracked</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#f6f8fa</string>
<key>background</key>
<string>#005cc5</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>meta.diff.range</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#6f42c1</string>
<key>fontStyle</key>
<string>bold</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>meta.diff.header</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#005cc5</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>meta.separator</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#005cc5</string>
</dict>
<key>name</key>
<string>Meta.separator</string>
</dict>
<dict>
<key>name</key>
<string>Output</string>
<key>scope</key>
<string>meta.output</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#005cc5</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>brackethighlighter.tag, brackethighlighter.curly, brackethighlighter.round, brackethighlighter.square, brackethighlighter.angle, brackethighlighter.quote</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#586069</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>brackethighlighter.unmatched</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#b31d28</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>sublimelinter.mark.error</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#b31d28</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>sublimelinter.mark.warning</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#e36209</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>sublimelinter.gutter-mark</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#959da5</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>constant.other.reference.link, string.other.link</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#032f62</string>
<key>fontStyle</key>
<string>underline</string>
</dict>
</dict>
</array>
<key>comment</key>
<string>GitHub Light syntax theme</string>
<key>name</key>
<string>GitHub Light</string>
<key>semanticClass</key>
<string>theme.light.github</string>
<key>filename</key>
<string>github-light</string>
<key>uuid</key>
<string>A1C4DFA0-7031-11E4-9803-0800200C9A66</string>
</dict>
</plist>

369
report/themes/ILM.tmTheme Normal file
View File

@@ -0,0 +1,369 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!-- Created by: ilm techno solutions -->
<!-- ============================================ -->
<!-- code: https://github.com/codex8/Colorsublime-Themes -->
<plist version="1.0">
<dict>
<key>name</key>
<string>ILM</string>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>background</key>
<string>#FFFFFF</string>
<key>caret</key>
<string>#000000</string>
<key>foreground</key>
<string>#000000</string>
<key>invisibles</key>
<string>#BFBFBF</string>
<key>lineHighlight</key>
<string>#FFFBD1</string>
<key>selection</key>
<string>#BDD5FC</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Comment</string>
<key>scope</key>
<string>comment</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#BCC8BA</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>String</string>
<key>scope</key>
<string>string</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#5D90CD</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Number</string>
<key>scope</key>
<string>constant.numeric</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#46A609</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Built-in constant</string>
<key>scope</key>
<string>constant.language</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#39946A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>User-defined constant</string>
<key>scope</key>
<string>constant.character, constant.other</string>
<key>settings</key>
<dict>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variable</string>
<key>scope</key>
<string>variable.language, variable.other</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#2b991b</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>keyword, support.constant.property-value, constant.other.color</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string> bold</string>
<key>foreground</key>
<string>#ef5a19</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword -&gt; Unit</string>
<key>scope</key>
<string>keyword.other.unit</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#96DC5F</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword -&gt; Operator</string>
<key>scope</key>
<string>keyword.operator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#655465</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>storage</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#C52727</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Class name</string>
<key>scope</key>
<string>entity.name.class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string> bold</string>
<key>foreground</key>
<string>#27a6b4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Inherited class</string>
<key>scope</key>
<string>entity.other.inherited-class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#858585</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function name</string>
<key>scope</key>
<string>entity.name.function</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string> bold</string>
<key>foreground</key>
<string>#5319b5</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function argument</string>
<key>scope</key>
<string>variable.parameter</string>
<key>settings</key>
<dict>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag name</string>
<key>scope</key>
<string>entity.name.tag</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#606060</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>HTML Entity</string>
<key>scope</key>
<string>constant.character.entity</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#BF78CC</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JS Support Class</string>
<key>scope</key>
<string>support.class.js</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#BF78CC</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag attribute</string>
<key>scope</key>
<string>entity.other.attribute-name</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#606060</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>CSS Selector</string>
<key>scope</key>
<string>meta.selector.css, entity.name.tag.css, entity.other.attribute-name.id.css, entity.other.attribute-name.class.css</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#C52727</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>CSS Property</string>
<key>scope</key>
<string>meta.property-name.css</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#484848</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library function</string>
<key>scope</key>
<string>support.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#C52727</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library constant</string>
<key>scope</key>
<string>support.constant</string>
<key>settings</key>
<dict>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library class&#x2f;type</string>
<key>scope</key>
<string>support.type, support.class</string>
<key>settings</key>
<dict>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library variable</string>
<key>scope</key>
<string>support.other.variable</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid</string>
<key>scope</key>
<string>invalid</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#FF002A</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation&#x2f;Widgets</string>
<key>scope</key>
<string>punctuation.section.embedded</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#C52727</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation (Tags)</string>
<key>scope</key>
<string>punctuation.definition.tag</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#606060</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword -&gt; CSS</string>
<key>scope</key>
<string>constant.other.color.rgb-value.css, support.constant.property-value.css</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#BF78CC</string>
</dict>
</dict>
</array>
<key>uuid</key>
<string>47536290-6FC1-4B09-A08F-B219909E1A69</string>
<key>colorSpaceName</key>
<string>sRGB</string>
<key>semanticClass</key>
<string>theme.ILM</string>
<key>author</key>
<string>sameer</string>
<key>comment</key>
<string>https://github.com/codex8/Colorsublime-Themes</string>
</dict>
</plist>

View File

@@ -0,0 +1,369 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!-- Created by: ilm techno solutions -->
<!-- ============================================ -->
<!-- code: https://github.com/codex8/Colorsublime-Themes -->
<plist version="1.0">
<dict>
<key>name</key>
<string>ILM 2</string>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>background</key>
<string>#FFFFFF</string>
<key>caret</key>
<string>#000000</string>
<key>foreground</key>
<string>#000000</string>
<key>invisibles</key>
<string>#BFBFBF</string>
<key>lineHighlight</key>
<string>#FFFBD1</string>
<key>selection</key>
<string>#BDD5FC</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Comment</string>
<key>scope</key>
<string>comment</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#c5c8baff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>String</string>
<key>scope</key>
<string>string</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#5dcdbfff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Number</string>
<key>scope</key>
<string>constant.numeric</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#a69d09ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Built-in constant</string>
<key>scope</key>
<string>constant.language</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#459439ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>User-defined constant</string>
<key>scope</key>
<string>constant.character, constant.other</string>
<key>settings</key>
<dict>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variable</string>
<key>scope</key>
<string>variable.language, variable.other</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#7f991bff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>keyword, support.constant.property-value, constant.other.color</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string> bold</string>
<key>foreground</key>
<string>#ef1967ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword -&gt; Unit</string>
<key>scope</key>
<string>keyword.other.unit</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#dccf5fff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword -&gt; Operator</string>
<key>scope</key>
<string>keyword.operator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#5a5465ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>storage</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#c52790ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Class name</string>
<key>scope</key>
<string>entity.name.class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string> bold</string>
<key>foreground</key>
<string>#27b464ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Inherited class</string>
<key>scope</key>
<string>entity.other.inherited-class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#858585ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function name</string>
<key>scope</key>
<string>entity.name.function</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string> bold</string>
<key>foreground</key>
<string>#1947b5ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function argument</string>
<key>scope</key>
<string>variable.parameter</string>
<key>settings</key>
<dict>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag name</string>
<key>scope</key>
<string>entity.name.tag</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#606060ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>HTML Entity</string>
<key>scope</key>
<string>constant.character.entity</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8778ccff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JS Support Class</string>
<key>scope</key>
<string>support.class.js</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8778ccff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag attribute</string>
<key>scope</key>
<string>entity.other.attribute-name</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#606060ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>CSS Selector</string>
<key>scope</key>
<string>meta.selector.css, entity.name.tag.css, entity.other.attribute-name.id.css, entity.other.attribute-name.class.css</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#c52790ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>CSS Property</string>
<key>scope</key>
<string>meta.property-name.css</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#484848ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library function</string>
<key>scope</key>
<string>support.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#c52790ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library constant</string>
<key>scope</key>
<string>support.constant</string>
<key>settings</key>
<dict>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library class&#x2f;type</string>
<key>scope</key>
<string>support.type, support.class</string>
<key>settings</key>
<dict>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library variable</string>
<key>scope</key>
<string>support.other.variable</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid</string>
<key>scope</key>
<string>invalid</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#ff00d4ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation&#x2f;Widgets</string>
<key>scope</key>
<string>punctuation.section.embedded</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#c52790ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation (Tags)</string>
<key>scope</key>
<string>punctuation.definition.tag</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#606060ff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword -&gt; CSS</string>
<key>scope</key>
<string>constant.other.color.rgb-value.css, support.constant.property-value.css</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8778ccff</string>
</dict>
</dict>
</array>
<key>uuid</key>
<string>47536290-6FC1-4B09-A08F-B219909E1A69</string>
<key>colorSpaceName</key>
<string>sRGB</string>
<key>semanticClass</key>
<string>theme.light.ILM light</string>
<key>author</key>
<string>sameer</string>
<key>comment</key>
<string>sam0hack</string>
</dict>
</plist>

View File

@@ -0,0 +1,619 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!-- Generated by: TmTheme-Editor -->
<!-- ============================================ -->
<!-- app: http://tmtheme-editor.herokuapp.com -->
<!-- code: https://github.com/aziz/tmTheme-Editor -->
<plist version="1.0">
<dict>
<key>author</key>
<string>Umut Topuzoğlu</string>
<key>name</key>
<string>Bluloco Light</string>
<key>semanticClass</key>
<string>theme.light.bluloco_light</string>
<key>colorSpaceName</key>
<string>sRGB</string>
<key>gutterSettings</key>
<dict>
<key>background</key>
<string>#353b45</string>
<key>divider</key>
<string>#353b45</string>
<key>foreground</key>
<string>#a0a1a7</string>
<key>selectionBackground</key>
<string>#d2ecff</string>
<key>selectionForeground</key>
<string>#565c64</string>
</dict>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>background</key>
<string>#f9f9f9</string>
<key>caret</key>
<string>#f31459</string>
<key>foreground</key>
<string>#383a42</string>
<key>invisibles</key>
<string>#a0a1a7</string>
<key>lineHighlight</key>
<string>#f1f1f1</string>
<key>selection</key>
<string>#d2ecff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Text</string>
<key>scope</key>
<string>variable.parameter.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#383a42</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Comments</string>
<key>scope</key>
<string>comment, punctuation.definition.comment, string.comment</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#a0a1a7</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation</string>
<key>scope</key>
<string>punctuation.definition.variable, punctuation.definition.parameters, punctuation.definition.array, punctuation.definition.function, meta.brace, punctuation.terminator.statement, meta.delimiter.object.comma, punctuation.definition.entity, punctuation.definition,punctuation.definition.string.begin.markdown, punctuation.definition.string.end.markdown, punctuation.separator.key-value, punctuation.separator.dictionary, punctuation.terminator, meta.delimiter.comma, punctuation.separator.comma,punctuation.accessor,punctuation.separator.array,punctuation.section.property-list.begin.bracket.curly, punctuation.section.property-list.end.bracket.curly, punctuation.separator.statement</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#7a82da</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Delimiters</string>
<key>scope</key>
<string>none</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#383a42</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Operators</string>
<key>scope</key>
<string>keyword.operator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#7a82da</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keywords</string>
<key>scope</key>
<string>keyword, variable.language</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0098dd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variables</string>
<key>scope</key>
<string>variable</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#383a42</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Functions</string>
<key>scope</key>
<string>entity.name.function, meta.require, support.function.any-method, meta.function-call</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#23974a</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Classes</string>
<key>scope</key>
<string>support.class, entity.name.class, entity.name.type.class,meta.class.instance,meta.class.inheritance, entity.other.inherited-class, entity.name.type</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#d52753</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Methods</string>
<key>scope</key>
<string>keyword.other.special-method</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#23974a</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>storage,constant.language</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0098dd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Support</string>
<key>scope</key>
<string>support.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#23974a</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Strings, Inherited Class</string>
<key>scope</key>
<string>string, constant.other.symbol, punctuation.definition.string,support.constant.property-value, string.quoted.double.shell</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#c5a332</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Integers</string>
<key>scope</key>
<string>constant.numeric</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ce33c0</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Floats</string>
<key>scope</key>
<string>none</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ce33c0</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Boolean</string>
<key>scope</key>
<string>none</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0098dd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Constants</string>
<key>scope</key>
<string>constant</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#823ff1</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tags</string>
<key>scope</key>
<string>entity.name.tag, punctuation.definition.tag</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#275fe4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Attribute IDs</string>
<key>scope</key>
<string>entity.other.attribute-name</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#df631c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Selector</string>
<key>scope</key>
<string>meta.selector</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#7a82da</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Values</string>
<key>scope</key>
<string>none</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ce33c0</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Headings</string>
<key>scope</key>
<string>markup.heading, punctuation.definition.heading, entity.name.section, markup.heading.setext</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#c5a332</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Units</string>
<key>scope</key>
<string>keyword.other.unit</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#c5a332</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Bold</string>
<key>scope</key>
<string>markup.bold, punctuation.definition.bold</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#d52753</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Italic</string>
<key>scope</key>
<string>markup.italic, punctuation.definition.italic</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#df631c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Code</string>
<key>scope</key>
<string>markup.raw.inline</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#c5a332</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Link Text</string>
<key>scope</key>
<string>string.other.link</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#275fe4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Link Url</string>
<key>scope</key>
<string>meta.link</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0098dd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Lists</string>
<key>scope</key>
<string>beginning.punctuation.definition.list</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#a05a48</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Quotes</string>
<key>scope</key>
<string>markup.quote</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#823ff1</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Separator</string>
<key>scope</key>
<string>meta.separator</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#d2ecff</string>
<key>foreground</key>
<string>#383a42</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Inserted</string>
<key>scope</key>
<string>markup.inserted</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#23974a</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Deleted</string>
<key>scope</key>
<string>markup.deleted</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#d52753</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Changed</string>
<key>scope</key>
<string>markup.changed</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0098dd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Colors</string>
<key>scope</key>
<string>constant.other.color, support.constant.color</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#c5a332</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Regular Expressions</string>
<key>scope</key>
<string>string.regexp</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#a05a48</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Escape Characters</string>
<key>scope</key>
<string>constant.character.escape</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#df631c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Embedded</string>
<key>scope</key>
<string>punctuation.section.embedded, variable.interpolation</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0098dd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Illegal</string>
<key>scope</key>
<string>invalid</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ff0000</string>
<key>background</key>
<string>#d2ecff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Support Constant</string>
<key>scope</key>
<string>support.constant</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#a05a48</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>New Operator</string>
<key>scope</key>
<string>keyword.operator.new</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0098dd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Css ID</string>
<key>scope</key>
<string>entity.other.attribute-name.id</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#d52753</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function Parameters</string>
<key>scope</key>
<string>meta.function-call.arguments</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#383a42</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Object Properties</string>
<key>scope</key>
<string>meta.object-literal.key, meta.object.member, support.type.property-name, entity.name.tag.yaml, constant.other.key,constant.other.object.key.js,string.unquoted.label.js</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#a05a48</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup Code</string>
<key>scope</key>
<string>markup.inline.raw, markup.fenced_code.block, markup.raw.block</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#a05a48</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup Link Image</string>
<key>scope</key>
<string>markup.underline.link.image</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#23974a</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variable Parameter</string>
<key>scope</key>
<string>variable.parameter</string>
<key>settings</key>
<dict></dict>
</dict>
<dict>
<key>name</key>
<string>Type Primitive</string>
<key>scope</key>
<string>support.type.primitive</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#0098dd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>BASH: Command Substitution</string>
<key>scope</key>
<string>string.interpolated.dollar.shell</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#d52753</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>BASH: Math Operation</string>
<key>scope</key>
<string>string.other.math.shell</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#275fe4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>BASH: Substitution</string>
<key>scope</key>
<string>punctuation.definition.string.begin.shell, punctuation.definition.string.end.shell</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#7a82da</string>
</dict>
</dict>
</array>
<key>uuid</key>
<string>uuid</string>
</dict>
</plist>

43
report/utils.typ Normal file
View File

@@ -0,0 +1,43 @@
#let include-offset(what) = context {
let current-offset = heading.offset
set heading(offset: current-offset + 1)
include what
}
#let quote-block(width: 10cm, who, what) = {
set par(justify: false)
align(
right,
block(
width: width,
inset: (bottom: 1cm),
quote(
attribution: who,
block: true,
what
)
)
)
}
#let _fn-links = state("_fn-links", ())
#let fn-link(lbl, url, body) = context {
link(url, body)
let links = _fn-links.get()
let name = str(lbl)
if name in links {
footnote(lbl)
} else {
[#footnote(link(url)) #lbl]
_fn-links.update(links => links + (name,))
}
}
#let code-ref(lbl, path, body: auto) = {
if body == auto {
body = path
}
let url = "https://git.kb28.ch/HEL/midas/src/branch/main/" + path
fn-link(lbl, url, body)
}

58
summary/exec_summary.typ Normal file
View File

@@ -0,0 +1,58 @@
// ___ ____ ____ _ _ _____ ___
// |_ _/ ___| / ___| | | | | ____|_ _| Informatique et
// | |\___ \| | ___ | |_| | _| | | systèmes de communication
// | | ___) | |__|___| | _ | |___ | | HEI Sion · HES-SO Valais / mui 24-26
// |___|____/ \____| |_| |_|_____|___|
//
// 52 65 61 64 69 6e 67 20 68 65 78 20 66 6f 72 20 66 75 6e 3f 20 49 53 43 20 66 6f 72 65 76 65 72
//
// Adapted from the BFH year book idea at https://www.bfh.ch/dam/jcr:e512ae31-a3ed-4b65-b589-870383d794b0/abschlussarbeiten-bsc-informatik.pdf
#import "@preview/isc-hei-exec-summary:0.8.1" : *
#import "../meta.typ"
// Must be <= 365 characters long.
#let summary = "Midas is cool!" // TODO
#assert(
summary.len() <= 365,
message: "Summary too long: len() > 365"
)
#let content = [
#todo[]
#lorem-pars(500)
#colbreak()
#lorem-pars(500)
]
#show: exec-summary.with(
title: meta.title,
subtitle: meta.subtitle,
language: "en",
authors: meta.authors,
student-picture: image("figs/me.jpg"), // TODO: replace
permanent-email: meta.permanent-email,
video-url: meta.video-url,
picture-web-opt-out: meta.picture-web-opt-out,
email-web-opt-out: meta.email-web-opt-out,
summary: summary,
content: content,
thesis-supervisor: meta.thesis-supervisor,
thesis-co-supervisor: meta.thesis-co-supervisor,
thesis-expert: meta.thesis-expert,
academic-year: meta.academic-year,
school: meta.school,
programme: meta.programme,
keywords: meta.keywords,
major : meta.major,
bind: right, // Bind the left side of the page
footer: none, //align(right, text(0.9em)[This is some content for the footer])
)

BIN
summary/figs/me.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 KiB