Simplifying testing

This commit is contained in:
retropikzel 2025-02-28 13:01:07 +02:00
parent 8a2bb63dbf
commit b08f0c54a7
56 changed files with 1862 additions and 8676 deletions

2
.gitignore vendored
View File

@ -32,4 +32,4 @@ retropikzel/pffi/*/compiled
tmp
dockerfiles/build
.scheme_testrunner
snow
core

View File

@ -1,9 +0,0 @@
ARG SCHEME=
FROM schemers/${SCHEME}
RUN apt-get update && apt-get install -y git make build-essential libffi-dev
RUN git clone https://git.sr.ht/~retropikzel/compile-r7rs && cd compile-r7rs && make install
COPY libtest.c /
RUN gcc -o libtest.so -shared -fPIC libtest.c && cp libtest.so /usr/local/lib/
RUN gcc -fPIC -c libtest.c && ar rcs libtest.a libtest.o && cp libtest.a /usr/local/lib

View File

@ -1,7 +0,0 @@
To run tests on different architecture than you are using, install podman and add the docker
registry to it's configuration. Add the line
unqualified-search-registries = ["docker.io"]
to file: /etc/containers/registries.conf

View File

@ -1,6 +0,0 @@
## Error early
Always load with RTLD_NOW if possible so loading happens at start of program.
Always to to find the function when pffi-define is run, not when the function itself is run so
any errors will happen on the program start.

137
Jenkinsfile vendored
View File

@ -1,7 +1,7 @@
pipeline {
agent {
dockerfile {
filename 'Dockerfile.jenkins'
filename 'dockerfiles/jenkins'
dir '.'
args '--privileged -v /var/run/docker.sock:/var/run/docker.sock'
}
@ -12,69 +12,166 @@ pipeline {
}
stages {
stage('Chibi') {
stage('chibi') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make test-chibi-docker-jenkins-jenkins'
sh 'make SCHEME=chibi test-script-docker'
}
}
}
stage('Chicken-5') {
stage('chicken') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make test-chicken-5-docker-jenkins'
sh 'make SCHEME=chicken test-script-docker'
}
}
}
stage('Cyclone') {
stage('cyclone') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make test-cyclone-docker-jenkins'
sh 'make SCHEME=cyclone test-script-docker'
}
}
}
stage('Gambit') {
stage('gambit') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make test-gambit-docker-jenkins'
sh 'make SCHEME=gambit test-script-docker'
}
}
}
stage('Guile') {
stage('gauche') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make test-guile-docker-jenkins'
sh 'make SCHEME=gauche test-script-docker'
}
}
}
stage('Sagittarius') {
stage('gerbil') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make test-sagittarius-docker-jenkins'
sh 'make SCHEME=gerbil test-script-docker'
}
}
}
stage('Racket') {
stage('guile') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make test-racket-docker-jenkins'
sh 'make SCHEME=guile test-script-docker'
}
}
}
stage('Kawa') {
stage('kawa') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make test-kawa-docker-jenkins'
sh 'make SCHEME=kawa test-script-docker'
}
}
}
stage('STklos') {
stage('mosh') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make test-stklos-docker-jenkins'
sh 'make SCHEME=mosh test-script-docker'
}
}
}
stage('racket') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=racket test-script-docker'
}
}
}
stage('racket-wine') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=racket-wine test-script-docker'
}
}
}
stage('sagittarius') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=sagittarius test-script-docker'
}
}
}
stage('stklos') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=stklos test-script-docker'
}
}
}
stage('skint') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=skint test-script-docker'
}
}
}
stage('tr7i') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=tr7i test-script-docker'
}
}
}
stage('ypsilon') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=ypsilon test-script-docker'
}
}
}
stage('chicken') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=chicken test-compile-docker'
}
}
}
stage('cyclone') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=cyclone test-compile-docker'
}
}
}
stage('gambit') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=gambit test-compile-docker'
}
}
}
stage('gauche') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=gauche test-compile-docker'
}
}
}
stage('gerbil') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=gerbil test-compile-docker'
}
}
}
stage('kawa') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=kawa test-compile-docker'
}
}
}
stage('racket') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME=racket test-compile-docker'
}
}
}
}
}

View File

@ -3,6 +3,9 @@ CC=gcc
DOCKER=docker run -it -v ${PWD}:/workdir
DOCKER_INIT=cd /workdir && make clean &&
jenkinsfile:
gosh -r7 -I ./snow build.scm
libtest.so: libtest.c
${CC} -o libtest.so -shared -fPIC libtest.c
@ -13,9 +16,19 @@ libtest.a: libtest.c
test-script: libtest.so
SCHEME=${SCHEME} script-r7rs -I . test.scm
test-script-docker:
sudo docker build -f dockerfiles/test . --build-arg SCHEME=${SCHEME} --tag=pffi-${SCHEME}
sudo docker run -v ${PWD}:/workdir pffi-${SCHEME} bash -c "cd /workdir && make libtest.so && SCHEME=${SCHEME} script-r7rs -I . test.scm"
test-compile: libtest.so libtest.a
SCHEME=${SCHEME} compile-r7rs-library retropikzel/pffi.sld
SCHEME=${SCHEME} compile-r7rs -I . test.scm && ./test
test-compile-docker: libtest.so libtest.a
sudo docker build -f dockerfiles/test . --build-arg SCHEME=${SCHEME} --tag=pffi-${SCHEME}
sudo docker run -v ${PWD}:/workdir pffi-${SCHEME} bash -c "cd /workdir && SCHEME=${SCHEME} compile-r7rs-library retropikzel/pffi.sld"
sudo docker run -v ${PWD}:/workdir pffi-${SCHEME} bash -c "cd /workdir && SCHEME=${SCHEME} compile-r7rs -I . test.scm && ./test"
CHIBI=chibi-scheme -A .
test-chibi-docker:
docker build -f Dockerfile --build-arg SCHEME=chibi --tag=r7rs-pffi-chibi .
@ -194,6 +207,7 @@ clean:
find . -name "*.o[1-9]" -delete
find . -name "*.so" -delete
find . -name "*.a" -delete
find . -name "*.class" -delete
@rm -rf test
@rm -rf tmp
find . -name "core.1" -delete

59
build.scm Normal file
View File

@ -0,0 +1,59 @@
(import (scheme base)
(scheme write)
(scheme file)
(scheme process-context)
(arvyy mustache))
(define slurp-loop
(lambda (line result)
(if (eof-object? line)
result
(slurp-loop (read-line) (string-append result line (string #\newline))))))
(define slurp
(lambda (path)
(with-input-from-file
path
(lambda ()
(slurp-loop (read-line) "")))))
(define script-implementations
(vector "chibi"
"chicken"
"cyclone"
"gambit"
"gauche"
;"gauche-wine" TODO
"gerbil"
"guile"
"kawa"
;"meevax" TODO
"mosh"
"racket"
"racket-wine"
"sagittarius"
;"sagittarius-wine" TODO
"stklos"
"skint"
"tr7i"
"ypsilon"))
(define compiler-implementations
(vector "chicken"
"cyclone"
"gambit"
"gauche"
"gerbil"
"kawa"
"racket"
;"racket-wine" TODO
))
;; Jenkinsfile
(call-with-output-file
"Jenkinsfile"
(lambda (out)
(execute (compile (slurp "templates/Jenkinsfile"))
(list (cons 'script-implementations script-implementations)
(cons 'compiler-implementations compiler-implementations))
out)))

View File

@ -1,9 +0,0 @@
((packager . "retropikzel")
(name . "r7rs-pffi")
(version . "v0-4-4")
(type . "library")
(description . "Portable Foreign Function Interface for R7RS schemes")
(license . "LGPL")
(dependencies ())
(development-dependencies ())
)

View File

@ -1,3 +0,0 @@
# Portable Foreign Function Interface for R7RS schemes
Foreign function interface that is supported on multiple R7RS Sceheme implementations.

View File

@ -1,231 +0,0 @@
# Reference
# Types
Types are given as symbols, for example 'int8 or 'pointer.
- int8
- uint8
- int16
- uint16
- int32
- uint32
- int64
- uint64
- char
- unsigned-char
- short
- unsigned-short
- int
- unsigned-int
- long
- unsigned-long
- float
- double
- pointer
# Procedures or macros
On some implementations these are procedures, on some macros.
The arguments are in form
- NAME - TYPE
The return value is in form
- TYPE
## pffi-shared-object-auto-load
Arguments:
- headers - (list string ...)
- C headers of the library
- For example (list "curl/curl.h")
- object-name - symbol
- The name of the dynamic library file you want to load
- Without the "lib" in front of it
- Without the ".so" or ".dll" at the end
- additional-versions - (list string...)
- For example (list ".0" ".1")
- additional-paths - (list string...)
- Any additional paths you want to search for the library
- For example (list "./mylibs")
Returns:
- object
- Shared object, the type depends on the implementation
## pffi-shared-object-load
It is recommended to use the pffi-shared-object-auto-load instead of this
directly.
Arguments:
- headers - (list string ...)
- Headers that need to be included
- Example (list "curl/curl.h")
- path - string
- The full path to the shared object you want to load, including any "lib" infront and .so/.dll at the end
- Example "libcurl.so"
Returns:
- object
- Shared object, the type depends on the implementation
## pffi-define
Defines new foreign procedure.
Arguments:
- scheme-name - symbol
- The name of the procedure used on scheme side
- shared-object - object
- The shared object
- Use pffi-shared-object-auto-load or pffi-shared-object-load to get this
- c-name - symbol
- The name of the C function
- return-type - symbol
- The return type of the C function
- arguments-types - (list symbol ...)
- The C function argument types
- Need to be given in form (list 'type 'type)
## pffi-define-callback
Defines new callback function.
Arguments:
- scheme-name
- The name of the function used on scheme side
- return-type - symbol
- The return type of the callback
- arguments-types - (list symbol ...)
- The callback function argument types
- procedure - procedure
- Procedure used as callback function
- Argument count must match the argument-types count
## pffi-size-of
Get the size of type.
Arguments:
- type - symbol
- The type you want the size of
Returns:
- number
- The size of the given type
## pffi-pointer-allocate
Allocates a pointer of given size.
Arguments:
- size - number
- The size of the pointer you want to allocate
Returns:
- object
- A pointer of given size
## pffi-pointer-null
Create a null pointer.
Returns:
- object
- Null pointer
## pffi-string->pointer
Arguments:
- string-content - string
- The string you want to transform into pointer
Returns:
- object
- Pointer of the given string
## pffi-pointer->string
Arguments:
- pointer - object
- The pointer you want to transform to string
Returns:
- string
- String from the given pointer
## pffi-pointer-free
Arguments:
- pointer - object
- The pointer you want to free
## pffi-pointer?
Arguments:
- object - object
- The object you want to check wether it is a pointer or not
Returns:
- boolean
- Returns true if given object is pointer, otherwise false
## pffi-pointer-set!
Arguments:
- pointer - object
- The pointer you want to modify
- type - symbol
- The type of value that will be put into the pointer
- offset -number
- The location of the value inside the pointer
- For example: (+ (pffi-size-of 'int) (pffi-size-of 'pointer)) or 0
- value - object
- The value to be placed into the object
## pffi-pointer-get
Arguments:
- pointer - object
- The pointer you want to get the value from
- type - symbol
- The type of value you want to get
- For example: 'int
- offset - number
- The location of the value inside the pointer
- For example: (+ (pffi-size-of 'int) (pffi-size-of 'pointer)) or 0
Returns:
- object
- The value in the poiner in the given offset as given type

View File

@ -1 +0,0 @@
(prelude: :scheme/r7rs)

View File

@ -1,4 +0,0 @@
#!/usr/bin/env bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk use 22.0.2-tem

BIN
kawa.jar

Binary file not shown.

View File

@ -1 +0,0 @@
site_name: r7rs-pffi

View File

@ -1,145 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="/img/favicon.ico">
<title>r7rs-pffi</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/font-awesome.min.css" rel="stylesheet">
<link href="/css/base.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css">
<script src="/js/jquery-1.10.2.min.js" defer></script>
<script src="/js/bootstrap.min.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body>
<div class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="/.">r7rs-pffi</a>
<!-- Expander button -->
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbar-collapse">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Expanded navigation -->
<div id="navbar-collapse" class="navbar-collapse collapse">
<!-- Main navigation -->
<ul class="nav navbar-nav">
<li class="navitem">
<a href="/." class="nav-link">Portable Foreign Function Interface for R7RS schemes</a>
</li>
<li class="navitem">
<a href="/reference/" class="nav-link">Reference</a>
</li>
</ul>
<ul class="nav navbar-nav ml-auto">
<li class="nav-item">
<a href="#" class="nav-link" data-toggle="modal" data-target="#mkdocs_search_modal">
<i class="fa fa-search"></i> Search
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="row-fluid">
<div id="main-content" class="span12">
<h1 id="404-page-not-found" style="text-align: center">404</h1>
<p style="text-align: center"><strong>Page not found</strong></p>
</div>
</div>
</div>
</div>
<footer class="col-md-12">
<hr>
<p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a>.</p>
</footer>
<script>
var base_url = "/",
shortcuts = {"help": 191, "next": 78, "previous": 80, "search": 83};
</script>
<script src="/js/base.js" defer></script>
<script src="/search/main.js" defer></script>
<div class="modal" id="mkdocs_search_modal" tabindex="-1" role="dialog" aria-labelledby="searchModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="searchModalLabel">Search</h4>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
</div>
<div class="modal-body">
<p>
From here you can search these documents. Enter
your search terms below.
</p>
<form>
<div class="form-group">
<input type="search" class="form-control" placeholder="Search..." id="mkdocs-search-query" title="Type search term here">
</div>
</form>
<div id="mkdocs-search-results"></div>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div><div class="modal" id="mkdocs_keyboard_modal" tabindex="-1" role="dialog" aria-labelledby="keyboardModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="keyboardModalLabel">Keyboard Shortcuts</h4>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
</div>
<div class="modal-body">
<table class="table">
<thead>
<tr>
<th style="width: 20%;">Keys</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td class="help shortcut"><kbd>?</kbd></td>
<td>Open this help</td>
</tr>
<tr>
<td class="next shortcut"><kbd>n</kbd></td>
<td>Next page</td>
</tr>
<tr>
<td class="prev shortcut"><kbd>p</kbd></td>
<td>Previous page</td>
</tr>
<tr>
<td class="search shortcut"><kbd>s</kbd></td>
<td>Search</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,313 +0,0 @@
html {
/* csslint ignore:start */
/* The nav header is 3.5rem high, plus 20px for the margin-top of the
main container. */
scroll-padding-top: calc(3.5rem + 20px);
/* csslint ignore:end */
}
/* Replacement for `body { background-attachment: fixed; }`, which has
performance issues when scrolling on large displays. See #1394. */
body::before {
content: ' ';
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: #f8f8f8;
background: url(../img/grid.png) repeat-x;
will-change: transform;
z-index: -1;
}
body > .container {
margin-top: 20px;
min-height: 400px;
}
.navbar.fixed-top { /* csslint allow: adjoining-classes */
/* csslint ignore:start */
position: -webkit-sticky;
position: sticky;
/* csslint ignore:end */
}
.source-links {
float: right;
}
.col-md-9 img {
max-width: 100%;
display: inline-block;
padding: 4px;
line-height: 1.428571429;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
margin: 20px auto 30px auto;
}
h1 {
color: #444;
font-weight: 400;
font-size: 42px;
}
h2, h3, h4, h5, h6 {
color: #444;
font-weight: 300;
}
hr {
border-top: 1px solid #aaa;
}
pre, .rst-content tt {
max-width: 100%;
background: #fff;
border: solid 1px #e1e4e5;
color: #333;
overflow-x: auto;
}
code.code-large, .rst-content tt.code-large {
font-size: 90%;
}
code {
padding: 2px 5px;
background: #fff;
border: solid 1px #e1e4e5;
color: #333;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
display: block;
background: transparent;
border: none;
white-space: pre;
word-wrap: normal;
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 12px;
}
kbd {
padding: 2px 4px;
font-size: 90%;
color: #fff;
background-color: #333;
border-radius: 3px;
-webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);
box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);
}
a code {
color: #2FA4E7;
}
a:hover code, a:focus code {
color: #157AB5;
}
footer {
margin-top: 30px;
margin-bottom: 10px;
text-align: center;
font-weight: 200;
}
.modal-dialog {
margin-top: 60px;
}
/*
* Side navigation
*
* Scrollspy and affixed enhanced navigation to highlight sections and secondary
* sections of docs content.
*/
.bs-sidebar.affix { /* csslint allow: adjoining-classes */
/* csslint ignore:start */
position: -webkit-sticky;
position: sticky;
/* csslint ignore:end */
/* The nav header is 3.5rem high, plus 20px for the margin-top of the
main container. */
top: calc(3.5rem + 20px);
}
.bs-sidebar.card { /* csslint allow: adjoining-classes */
padding: 0;
max-height: 90%;
overflow-y: auto;
}
/* Toggle (vertically flip) sidebar collapse icon */
.bs-sidebar .navbar-toggler span {
-moz-transform: scale(1, -1);
-webkit-transform: scale(1, -1);
-o-transform: scale(1, -1);
-ms-transform: scale(1, -1);
transform: scale(1, -1);
}
.bs-sidebar .navbar-toggler.collapsed span { /* csslint allow: adjoining-classes */
-moz-transform: scale(1, 1);
-webkit-transform: scale(1, 1);
-o-transform: scale(1, 1);
-ms-transform: scale(1, 1);
transform: scale(1, 1);
}
/* First level of nav */
.bs-sidebar > .navbar-collapse > .nav {
padding-top: 10px;
padding-bottom: 10px;
border-radius: 5px;
width: 100%;
}
/* All levels of nav */
.bs-sidebar .nav > li > a {
display: block;
padding: 5px 20px;
z-index: 1;
}
.bs-sidebar .nav > li > a:hover,
.bs-sidebar .nav > li > a:focus {
text-decoration: none;
border-right: 1px solid;
}
.bs-sidebar .nav > li > a.active,
.bs-sidebar .nav > li > a.active:hover,
.bs-sidebar .nav > li > a.active:focus {
font-weight: bold;
background-color: transparent;
border-right: 1px solid;
}
.bs-sidebar .nav .nav .nav {
margin-left: 1em;
}
.bs-sidebar .nav > li > a {
font-weight: bold;
}
.bs-sidebar .nav .nav > li > a {
font-weight: normal;
}
.headerlink {
font-family: FontAwesome;
font-size: 14px;
display: none;
padding-left: .5em;
}
h1:hover .headerlink, h2:hover .headerlink, h3:hover .headerlink, h4:hover .headerlink, h5:hover .headerlink, h6:hover .headerlink{
display:inline-block;
}
.admonition {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
text-align: left;
}
.admonition.note { /* csslint allow: adjoining-classes */
color: #3a87ad;
background-color: #d9edf7;
border-color: #bce8f1;
}
.admonition.warning { /* csslint allow: adjoining-classes */
color: #c09853;
background-color: #fcf8e3;
border-color: #fbeed5;
}
.admonition.danger { /* csslint allow: adjoining-classes */
color: #b94a48;
background-color: #f2dede;
border-color: #eed3d7;
}
.admonition-title {
font-weight: bold;
text-align: left;
}
@media (max-width: 991.98px) {
.navbar-collapse.show { /* csslint allow: adjoining-classes */
overflow-y: auto;
max-height: calc(100vh - 3.5rem);
}
}
.dropdown-item.open { /* csslint allow: adjoining-classes */
color: #fff;
background-color: #2FA4E7;
}
.dropdown-submenu > .dropdown-menu {
margin: 0 0 0 1.5rem;
padding: 0;
border-width: 0;
}
.dropdown-submenu > a::after {
display: block;
content: " ";
float: right;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 5px 0 5px 5px;
border-left-color: #ccc;
margin-top: 5px;
margin-right: -10px;
}
.dropdown-submenu:hover > a::after {
border-left-color: #fff;
}
@media (min-width: 992px) {
.dropdown-menu {
overflow-y: auto;
max-height: calc(100vh - 3.5rem);
}
.dropdown-submenu {
position: relative;
}
.dropdown-submenu > .dropdown-menu {
/* csslint ignore:start */
position: fixed !important;
/* csslint ignore:end */
margin-top: -9px;
margin-left: -2px;
border-width: 1px;
padding: 0.5rem 0;
}
.dropdown-submenu.pull-left { /* csslint allow: adjoining-classes */
float: none;
}
.dropdown-submenu.pull-left > .dropdown-menu { /* csslint allow: adjoining-classes */
left: -100%;
margin-left: 10px;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 420 B

View File

@ -1,344 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="None">
<link rel="shortcut icon" href="img/favicon.ico">
<title>r7rs-pffi</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/font-awesome.min.css" rel="stylesheet">
<link href="css/base.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css">
<script src="js/jquery-1.10.2.min.js" defer></script>
<script src="js/bootstrap.min.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body class="homepage">
<div class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href=".">r7rs-pffi</a>
<!-- Expander button -->
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbar-collapse">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Expanded navigation -->
<div id="navbar-collapse" class="navbar-collapse collapse">
<!-- Main navigation -->
<ul class="nav navbar-nav">
<li class="navitem active">
<a href="." class="nav-link">Portable Foreign Function Interface for R7RS schemes</a>
</li>
<li class="navitem">
<a href="reference/" class="nav-link">Reference</a>
</li>
</ul>
<ul class="nav navbar-nav ml-auto">
<li class="nav-item">
<a href="#" class="nav-link" data-toggle="modal" data-target="#mkdocs_search_modal">
<i class="fa fa-search"></i> Search
</a>
</li>
<li class="nav-item">
<a rel="prev" class="nav-link disabled">
<i class="fa fa-arrow-left"></i> Previous
</a>
</li>
<li class="nav-item">
<a rel="next" href="reference/" class="nav-link">
Next <i class="fa fa-arrow-right"></i>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-3"><div class="navbar-light navbar-expand-md bs-sidebar hidden-print affix" role="complementary">
<div class="navbar-header">
<button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#toc-collapse" title="Table of Contents">
<span class="fa fa-angle-down"></span>
</button>
</div>
<div id="toc-collapse" class="navbar-collapse collapse card bg-light">
<ul class="nav flex-column">
<li class="nav-item" data-level="1"><a href="#portable-foreign-function-interface-for-r7rs-schemes" class="nav-link">Portable Foreign Function Interface for R7RS schemes</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="1"><a href="#goals" class="nav-link">Goals</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="1"><a href="#non-goals" class="nav-link">Non goals</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="1"><a href="#support-tiers" class="nav-link">Support tiers</a>
<ul class="nav flex-column">
<li class="nav-item" data-level="2"><a href="#tier-1" class="nav-link">Tier 1</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#tier-2" class="nav-link">Tier 2</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#tier-3" class="nav-link">Tier 3</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#tier-4" class="nav-link">Tier 4</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#tier-5" class="nav-link">Tier 5</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#tier-6" class="nav-link">Tier 6</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div></div>
<div class="col-md-9" role="main">
<h1 id="portable-foreign-function-interface-for-r7rs-schemes">Portable Foreign Function Interface for R7RS schemes</h1>
<p>Foreign function interface that is supported on multiple R7RS Sceheme implementations.</p>
<p>Note that this software is in <strong>alpha</strong> stage. That said the interface should not be changing anymore.</p>
<p>Any help in form of constructive advice and bug reports are appreciated.</p>
<p><a href="https://retropikzel.neocities.org/r7rs-pffi/">Documentation</a> or run mkdocs serve or see docs/.</p>
<p><a href="https://todo.sr.ht/~retropikzel/r7rs-pffi">Issue tracker</a></p>
<p><a href="https://sr.ht/~retropikzel/r7rs-pffi/lists">Maling lists</a></p>
<p>For documentation see <a href="retropikzel.neocities.org/r7rs-pffi">retropikzel.neocities.org/r7rs-pffi</a>
or run mkdocs serve or see or docs/ directory.</p>
<h1 id="goals">Goals</h1>
<ul>
<li>Support only R7RS implementations</li>
<li>Needs to have cond-expand and library support atleast (propably much more)</li>
<li>Same interface on all implementations</li>
<li>Some things that are procedures on one implementation are macros on other,
but they must behave the same</li>
</ul>
<h1 id="non-goals">Non goals</h1>
<ul>
<li>To support all R7RS implementations</li>
<li>To have every possible FFI feature</li>
<li>Compiling of C code at any point<ul>
<li>That is no stubs, no C code generated by the library and so on</li>
</ul>
</li>
</ul>
<h1 id="support-tiers">Support tiers</h1>
<h2 id="tier-1">Tier 1</h2>
<ul>
<li><a href="https://www.call-cc.org/">Chicken</a><ul>
<li>Still needs work</li>
</ul>
</li>
<li><a href="https://www.gnu.org/software/guile/">Guile</a><ul>
<li>Good support, recommended</li>
</ul>
</li>
<li><a href="https://www.gnu.org/software/kawa/index.html">Kawa</a><ul>
<li>Needs at least java version 22</li>
<li>Needs jvm flags:<ul>
<li>--add-exports java.base/jdk.internal.foreign.abi=ALL-UNNAMED</li>
<li>--add-exports java.base/jdk.internal.foreign.layout=ALL-UNNAMED</li>
<li>--add-exports java.base/jdk.internal.foreign=ALL-UNNAMED</li>
<li>--enable-native-access=ALL-UNNAMED</li>
</ul>
</li>
<li>Good support (otherwise), recommended</li>
</ul>
</li>
<li><a href="https://bitbucket.org/ktakashi/sagittarius-scheme/wiki/Home">Sagittarius</a><ul>
<li>Good support, recommended</li>
</ul>
</li>
<li><a href="https://racket-lang.org/">Racket</a><ul>
<li>Good support, recommended</li>
</ul>
</li>
<li><a href="https://gambitscheme.org">Gambit</a><ul>
<li>Still needs work</li>
</ul>
</li>
</ul>
<h2 id="tier-2">Tier 2</h2>
<p>These implementations do not have callback support on their FFI. If I'm wrong please let me know!</p>
<ul>
<li><a href="https://stklos.net/">STKlos</a><ul>
<li>Still needs work</li>
</ul>
</li>
<li><a href="https://justinethier.github.io/cyclone/">Cyclone</a><ul>
<li>Still needs work</li>
</ul>
</li>
</ul>
<h2 id="tier-3">Tier 3</h2>
<p>Support waiting for the implementation.</p>
<ul>
<li><a href="https://lips.js.org/">LIPS</a><ul>
<li>Waiting for implementation to have cond-expand and library support</li>
<li>Will only work on nodejs</li>
</ul>
</li>
<li><a href="https://www.biwascheme.org/">Biwascheme</a><ul>
<li>Waiting for implementation to have cond-expand and library support</li>
<li>Will only work on nodejs</li>
</ul>
</li>
</ul>
<h2 id="tier-4">Tier 4</h2>
<p>Support needs to be investigated.</p>
<ul>
<li><a href="https://cons.io/">Gerbil</a></li>
<li><a href="http://www.littlewingpinball.com/doc/en/ypsilon/">Ypsilon</a></li>
<li><a href="https://larcenists.org/">Larceny</a></li>
<li><a href="https://mosh.monaos.org">Mosh</a></li>
<li><a href="https://github.com/false-schemers/skint">Skint</a></li>
</ul>
<h2 id="tier-5">Tier 5</h2>
<p>Support maybe possible/dreaming about.</p>
<ul>
<li><a href="https://gitlab.com/mbabich/airship-scheme">Airship</a></li>
<li><a href="https://gambitscheme.org/">Other gambit targets</a></li>
<li>Gambit compiles to different targets other than C too, for example Javascript. It would be cool
and interesting to see if this FFI could also support some of those</li>
</ul>
<h2 id="tier-6">Tier 6</h2>
<p>Not supported currently, and may never be.</p>
<ul>
<li><a href="https://synthcode.com/scheme/chibi">Chibi</a><ul>
<li>FFI requires C code</li>
</ul>
</li>
<li><a href="https://www.gnu.org/software/mit-scheme/">MIT-Scheme</a><ul>
<li>FFI requires C code</li>
</ul>
</li>
<li><a href="https://gitlab.com/jobol/tr7">tr7</a><ul>
<li>FFI requires C code</li>
</ul>
</li>
<li><a href="https://practical-scheme.net/gauche/">Gauche</a><ul>
<li>FFI requires C code</li>
</ul>
</li>
<li><a href="https://scheme.fail://ccrma.stanford.edu/software/snd/snd/s7.html">s7</a><ul>
<li>No library support</li>
<li>Might have other things missing too</li>
</ul>
</li>
<li><a href="https://scheme.fail/">Loko</a><ul>
<li>Desires no C interop, I can respect that</li>
</ul>
</li>
</ul></div>
</div>
</div>
<footer class="col-md-12">
<hr>
<p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a>.</p>
</footer>
<script>
var base_url = ".",
shortcuts = {"help": 191, "next": 78, "previous": 80, "search": 83};
</script>
<script src="js/base.js" defer></script>
<script src="search/main.js" defer></script>
<div class="modal" id="mkdocs_search_modal" tabindex="-1" role="dialog" aria-labelledby="searchModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="searchModalLabel">Search</h4>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
</div>
<div class="modal-body">
<p>
From here you can search these documents. Enter
your search terms below.
</p>
<form>
<div class="form-group">
<input type="search" class="form-control" placeholder="Search..." id="mkdocs-search-query" title="Type search term here">
</div>
</form>
<div id="mkdocs-search-results"></div>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div><div class="modal" id="mkdocs_keyboard_modal" tabindex="-1" role="dialog" aria-labelledby="keyboardModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="keyboardModalLabel">Keyboard Shortcuts</h4>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
</div>
<div class="modal-body">
<table class="table">
<thead>
<tr>
<th style="width: 20%;">Keys</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td class="help shortcut"><kbd>?</kbd></td>
<td>Open this help</td>
</tr>
<tr>
<td class="next shortcut"><kbd>n</kbd></td>
<td>Next page</td>
</tr>
<tr>
<td class="prev shortcut"><kbd>p</kbd></td>
<td>Previous page</td>
</tr>
<tr>
<td class="search shortcut"><kbd>s</kbd></td>
<td>Search</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>
</body>
</html>
<!--
MkDocs version : 1.1.2
Build Date UTC : 2024-09-03 12:25:23.288914+00:00
-->

View File

@ -1,283 +0,0 @@
function getSearchTerm() {
var sPageURL = window.location.search.substring(1);
var sURLVariables = sPageURL.split('&');
for (var i = 0; i < sURLVariables.length; i++) {
var sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] == 'q') {
return sParameterName[1];
}
}
}
function applyTopPadding() {
// Update various absolute positions to match where the main container
// starts. This is necessary for handling multi-line nav headers, since
// that pushes the main container down.
var offset = $('body > .container').offset();
$('html').css('scroll-padding-top', offset.top + 'px');
$('.bs-sidebar.affix').css('top', offset.top + 'px');
}
$(document).ready(function() {
applyTopPadding();
var search_term = getSearchTerm(),
$search_modal = $('#mkdocs_search_modal'),
$keyboard_modal = $('#mkdocs_keyboard_modal');
if (search_term) {
$search_modal.modal();
}
// make sure search input gets autofocus everytime modal opens.
$search_modal.on('shown.bs.modal', function() {
$search_modal.find('#mkdocs-search-query').focus();
});
// Close search modal when result is selected
// The links get added later so listen to parent
$('#mkdocs-search-results').click(function(e) {
if ($(e.target).is('a')) {
$search_modal.modal('hide');
}
});
// Populate keyboard modal with proper Keys
$keyboard_modal.find('.help.shortcut kbd')[0].innerHTML = keyCodes[shortcuts.help];
$keyboard_modal.find('.prev.shortcut kbd')[0].innerHTML = keyCodes[shortcuts.previous];
$keyboard_modal.find('.next.shortcut kbd')[0].innerHTML = keyCodes[shortcuts.next];
$keyboard_modal.find('.search.shortcut kbd')[0].innerHTML = keyCodes[shortcuts.search];
// Keyboard navigation
document.addEventListener("keydown", function(e) {
if ($(e.target).is(':input')) return true;
var key = e.which || e.keyCode || window.event && window.event.keyCode;
var page;
switch (key) {
case shortcuts.next:
page = $('.navbar a[rel="next"]:first').prop('href');
break;
case shortcuts.previous:
page = $('.navbar a[rel="prev"]:first').prop('href');
break;
case shortcuts.search:
e.preventDefault();
$keyboard_modal.modal('hide');
$search_modal.modal('show');
$search_modal.find('#mkdocs-search-query').focus();
break;
case shortcuts.help:
$search_modal.modal('hide');
$keyboard_modal.modal('show');
break;
default: break;
}
if (page) {
$keyboard_modal.modal('hide');
window.location.href = page;
}
});
$('table').addClass('table table-striped table-hover');
// Improve the scrollspy behaviour when users click on a TOC item.
$(".bs-sidenav a").on("click", function() {
var clicked = this;
setTimeout(function() {
var active = $('.nav li.active a');
active = active[active.length - 1];
if (clicked !== active) {
$(active).parent().removeClass("active");
$(clicked).parent().addClass("active");
}
}, 50);
});
function showInnerDropdown(item) {
var popup = $(item).next('.dropdown-menu');
popup.addClass('show');
$(item).addClass('open');
// First, close any sibling dropdowns.
var container = $(item).parent().parent();
container.find('> .dropdown-submenu > a').each(function(i, el) {
if (el !== item) {
hideInnerDropdown(el);
}
});
var popupMargin = 10;
var maxBottom = $(window).height() - popupMargin;
var bounds = item.getBoundingClientRect();
popup.css('left', bounds.right + 'px');
if (bounds.top + popup.height() > maxBottom &&
bounds.top > $(window).height() / 2) {
popup.css({
'top': (bounds.bottom - popup.height()) + 'px',
'max-height': (bounds.bottom - popupMargin) + 'px',
});
} else {
popup.css({
'top': bounds.top + 'px',
'max-height': (maxBottom - bounds.top) + 'px',
});
}
}
function hideInnerDropdown(item) {
var popup = $(item).next('.dropdown-menu');
popup.removeClass('show');
$(item).removeClass('open');
popup.scrollTop(0);
popup.find('.dropdown-menu').scrollTop(0).removeClass('show');
popup.find('.dropdown-submenu > a').removeClass('open');
}
$('.dropdown-submenu > a').on('click', function(e) {
if ($(this).next('.dropdown-menu').hasClass('show')) {
hideInnerDropdown(this);
} else {
showInnerDropdown(this);
}
e.stopPropagation();
e.preventDefault();
});
$('.dropdown-menu').parent().on('hide.bs.dropdown', function(e) {
$(this).find('.dropdown-menu').scrollTop(0);
$(this).find('.dropdown-submenu > a').removeClass('open');
$(this).find('.dropdown-menu .dropdown-menu').removeClass('show');
});
});
$(window).on('resize', applyTopPadding);
$('body').scrollspy({
target: '.bs-sidebar',
offset: 100
});
/* Prevent disabled links from causing a page reload */
$("li.disabled a").click(function() {
event.preventDefault();
});
// See https://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
// We only list common keys below. Obscure keys are omitted and their use is discouraged.
var keyCodes = {
8: 'backspace',
9: 'tab',
13: 'enter',
16: 'shift',
17: 'ctrl',
18: 'alt',
19: 'pause/break',
20: 'caps lock',
27: 'escape',
32: 'spacebar',
33: 'page up',
34: 'page down',
35: 'end',
36: 'home',
37: '&larr;',
38: '&uarr;',
39: '&rarr;',
40: '&darr;',
45: 'insert',
46: 'delete',
48: '0',
49: '1',
50: '2',
51: '3',
52: '4',
53: '5',
54: '6',
55: '7',
56: '8',
57: '9',
65: 'a',
66: 'b',
67: 'c',
68: 'd',
69: 'e',
70: 'f',
71: 'g',
72: 'h',
73: 'i',
74: 'j',
75: 'k',
76: 'l',
77: 'm',
78: 'n',
79: 'o',
80: 'p',
81: 'q',
82: 'r',
83: 's',
84: 't',
85: 'u',
86: 'v',
87: 'w',
88: 'x',
89: 'y',
90: 'z',
91: 'Left Windows Key / Left ⌘',
92: 'Right Windows Key',
93: 'Windows Menu / Right ⌘',
96: 'numpad 0',
97: 'numpad 1',
98: 'numpad 2',
99: 'numpad 3',
100: 'numpad 4',
101: 'numpad 5',
102: 'numpad 6',
103: 'numpad 7',
104: 'numpad 8',
105: 'numpad 9',
106: 'multiply',
107: 'add',
109: 'subtract',
110: 'decimal point',
111: 'divide',
112: 'f1',
113: 'f2',
114: 'f3',
115: 'f4',
116: 'f5',
117: 'f6',
118: 'f7',
119: 'f8',
120: 'f9',
121: 'f10',
122: 'f11',
123: 'f12',
124: 'f13',
125: 'f14',
126: 'f15',
127: 'f16',
128: 'f17',
129: 'f18',
130: 'f19',
131: 'f20',
132: 'f21',
133: 'f22',
134: 'f23',
135: 'f24',
144: 'num lock',
145: 'scroll lock',
186: '&semi;',
187: '&equals;',
188: '&comma;',
189: '&hyphen;',
190: '&period;',
191: '&quest;',
192: '&grave;',
219: '&lsqb;',
220: '&bsol;',
221: '&rsqb;',
222: '&apos;',
};

View File

@ -1,378 +0,0 @@
/*!
* Bootstrap v4.6.0 (https://getbootstrap.com/)
* Copyright 2011-2020 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery,t.Popper)}(this,function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=/* */i(e),a=/* */i(n);function s(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function l(t,e,n){return e&&s(t.prototype,e),n&&s(t,n),t}function r(){return(r=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(t[i]=n[i])}return t}).apply(this,arguments)}
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.6.0): util.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Private TransitionEnd Helpers
* ------------------------------------------------------------------------
*/
var u="transitionend";function d(t){var e=this,n=!1;return o.default(this).one(c.TRANSITION_END,function(){n=!0}),setTimeout(function(){n||c.triggerTransitionEnd(e)},t),this}
/**
* --------------------------------------------------------------------------
* Public Util Api
* --------------------------------------------------------------------------
*/
var c={TRANSITION_END:"bsTransitionEnd",getUID:function(t){do{t+=~~(1e6*Math.random());// "~~" acts like a faster Math.floor() here
}while(document.getElementById(t));return t},getSelectorFromElement:function(t){var e=t.getAttribute("data-target");if(!e||"#"===e){var n=t.getAttribute("href");e=n&&"#"!==n?n.trim():""}try{return document.querySelector(e)?e:null}catch(t){return null}},getTransitionDurationFromElement:function(t){if(!t)return 0;// Get transition-duration of the element
var e=o.default(t).css("transition-duration"),n=o.default(t).css("transition-delay"),i=parseFloat(e),a=parseFloat(n);// Return 0 if element or transition duration is not found
return i||a?(// If multiple durations are defined, take the first
e=e.split(",")[0],n=n.split(",")[0],1e3*(parseFloat(e)+parseFloat(n))):0},reflow:function(t){return t.offsetHeight},triggerTransitionEnd:function(t){o.default(t).trigger(u)},supportsTransitionEnd:function(){return Boolean(u)},isElement:function(t){return(t[0]||t).nodeType},typeCheckConfig:function(t,e,n){for(var i in n)if(Object.prototype.hasOwnProperty.call(n,i)){var o=n[i],a=e[i],s=a&&c.isElement(a)?"element":null==(l=a)?""+l:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(o).test(s))throw new Error(t.toUpperCase()+': Option "'+i+'" provided type "'+s+'" but expected type "'+o+'".')}// Shoutout AngusCroll (https://goo.gl/pxwQGp)
var l},findShadowRoot:function(t){if(!document.documentElement.attachShadow)return null;// Can find the shadow root otherwise it'll return the document
if("function"==typeof t.getRootNode){var e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:// when we don't find a shadow root
t.parentNode?c.findShadowRoot(t.parentNode):null},jQueryDetection:function(){if(void 0===o.default)throw new TypeError("Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.");var t=o.default.fn.jquery.split(" ")[0].split(".");if(t[0]<2&&t[1]<9||1===t[0]&&9===t[1]&&t[2]<1||t[0]>=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};c.jQueryDetection(),o.default.fn.emulateTransitionEnd=d,o.default.event.special[c.TRANSITION_END]={bindType:u,delegateType:u,handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments);// eslint-disable-line prefer-rest-params
}};
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var f=o.default.fn.alert,h=/* */function(){function t(t){this._element=t}// Getters
var e=t.prototype;
// Public
return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,"bs.alert"),this._element=null}// Private
,e._getRootElement=function(t){var e=c.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=c.getTransitionDurationFromElement(t);o.default(t).one(c.TRANSITION_END,function(n){return e._destroyElement(t,n)}).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()}// Static
,t._jQueryInterface=function(e){return this.each(function(){var n=o.default(this),i=n.data("bs.alert");i||(i=new t(this),n.data("bs.alert",i)),"close"===e&&i[e](this)})},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},l(t,null,[{key:"VERSION",get:function(){return"4.6.0"}}]),t}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',h._handleDismiss(new h)),
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
o.default.fn.alert=h._jQueryInterface,o.default.fn.alert.Constructor=h,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=f,h._jQueryInterface};
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var g=o.default.fn.button,m=/* */function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}// Getters
var e=t.prototype;
// Public
return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector('input:not([type="hidden"])');if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains("active"))t=!1;else{var a=n.querySelector(".active");a&&o.default(a).removeClass("active")}t&&(
// if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input
"checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains("active")),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains("active")),t&&o.default(this._element).toggleClass("active"))},e.dispose=function(){o.default.removeData(this._element,"bs.button"),this._element=null}// Static
,t._jQueryInterface=function(e,n){return this.each(function(){var i=o.default(this),a=i.data("bs.button");a||(a=new t(this),i.data("bs.button",a)),a.shouldAvoidTriggerChange=n,"toggle"===e&&a[e]()})},l(t,null,[{key:"VERSION",get:function(){return"4.6.0"}}]),t}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
o.default(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(".btn")[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();// work around Firefox bug #1540995
else{var i=e.querySelector('input:not([type="hidden"])');if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))// work around Firefox bug #1540995
return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||m._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(t){var e=o.default(t.target).closest(".btn")[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))}),o.default(window).on("load.bs.button.data-api",function(){for(
// ensure correct active class is set to match the controls' actual values/states
// find all checkboxes/readio buttons inside data-toggle groups
var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e<n;e++){var i=t[e],o=i.querySelector('input:not([type="hidden"])');o.checked||o.hasAttribute("checked")?i.classList.add("active"):i.classList.remove("active")}// find all button toggles
for(var a=0,s=(t=[].slice.call(document.querySelectorAll('[data-toggle="button"]'))).length;a<s;a++){var l=t[a];"true"===l.getAttribute("aria-pressed")?l.classList.add("active"):l.classList.remove("active")}}),
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
o.default.fn.button=m._jQueryInterface,o.default.fn.button.Constructor=m,o.default.fn.button.noConflict=function(){return o.default.fn.button=g,m._jQueryInterface};
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var p="carousel",_=".bs.carousel",v=o.default.fn[p],b={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},E=".carousel-indicators",w={TOUCH:"touch",PEN:"pen"},T=/* */function(){function t(t,e){this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._element=t,this._indicatorsElement=this._element.querySelector(E),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}// Getters
var e=t.prototype;
// Public
return e.next=function(){this._isSliding||this._slide("next")},e.nextWhenVisible=function(){var t=o.default(this._element);// Don't call next when the page isn't visible
// or the carousel or its parent isn't visible
!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide("prev")},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(c.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(".active.carousel-item");var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one("slid.bs.carousel",function(){return e.to(t)});else{if(n===t)return this.pause(),void this.cycle();var i=t>n?"next":"prev";this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(_),o.default.removeData(this._element,"bs.carousel"),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null}// Private
,e._getConfig=function(t){return t=r({},b,t),c.typeCheckConfig(p,t,y),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,// swipe left
e>0&&this.prev(),// swipe right
e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",function(e){return t._keydown(e)}),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",function(e){return t.pause(e)}).on("mouseleave.bs.carousel",function(e){return t.cycle(e)}),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&w[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&w[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(
// If it's a touch-enabled device, mouseenter/leave are fired as
// part of the mouse compatibility events on first tap - the carousel
// would stop cycling until user tapped out of it;
// here, we listen for touchend, explicitly pause the carousel
// (as if it's the second time we tap on it, mouseenter compat event
// is NOT fired) and after a timeout (to allow for mouse compatibility
// events to fire) we explicitly restart cycling
t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout(function(e){return t.cycle(e)},500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",function(t){return t.preventDefault()}),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",function(t){return e(t)}),o.default(this._element).on("pointerup.bs.carousel",function(t){return n(t)}),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",function(t){return e(t)}),o.default(this._element).on("touchmove.bs.carousel",function(e){return function(e){
// ensure swiping with one touch and not pinching
e.originalEvent.touches&&e.originalEvent.touches.length>1?t.touchDeltaX=0:t.touchDeltaX=e.originalEvent.touches[0].clientX-t.touchStartX}(e)}),o.default(this._element).on("touchend.bs.carousel",function(t){return n(t)}))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n="next"===t,i="prev"===t,o=this._getItemIndex(e),a=this._items.length-1;if((i&&0===o||n&&o===a)&&!this._config.wrap)return e;var s=(o+("prev"===t?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(".active.carousel-item")),a=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(a),a},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass("active");var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass("active")}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(".active.carousel-item");if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,a,s=this,l=this._element.querySelector(".active.carousel-item"),r=this._getItemIndex(l),u=e||l&&this._getItemByDirection(t,l),d=this._getItemIndex(u),f=Boolean(this._interval);if("next"===t?(n="carousel-item-left",i="carousel-item-next",a="left"):(n="carousel-item-right",i="carousel-item-prev",a="right"),u&&o.default(u).hasClass("active"))this._isSliding=!1;else if(!this._triggerSlideEvent(u,a).isDefaultPrevented()&&l&&u){this._isSliding=!0,f&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event("slid.bs.carousel",{relatedTarget:u,direction:a,from:r,to:d});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),c.reflow(u),o.default(l).addClass(n),o.default(u).addClass(n);var g=c.getTransitionDurationFromElement(l);o.default(l).one(c.TRANSITION_END,function(){o.default(u).removeClass(n+" "+i).addClass("active"),o.default(l).removeClass("active "+i+" "+n),s._isSliding=!1,setTimeout(function(){return o.default(s._element).trigger(h)},0)}).emulateTransitionEnd(g)}else o.default(l).removeClass("active"),o.default(u).addClass("active"),this._isSliding=!1,o.default(this._element).trigger(h);f&&this.cycle()}}// Static
,t._jQueryInterface=function(e){return this.each(function(){var n=o.default(this).data("bs.carousel"),i=r({},b,o.default(this).data());"object"==typeof e&&(i=r({},i,e));var a="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data("bs.carousel",n)),"number"==typeof e)n.to(e);else if("string"==typeof a){if(void 0===n[a])throw new TypeError('No method named "'+a+'"');n[a]()}else i.interval&&i.ride&&(n.pause(),n.cycle())})},t._dataApiClickHandler=function(e){var n=c.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var a=r({},o.default(i).data(),o.default(this).data()),s=this.getAttribute("data-slide-to");s&&(a.interval=!1),t._jQueryInterface.call(o.default(i),a),s&&o.default(i).data("bs.carousel").to(s),e.preventDefault()}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.0"}},{key:"Default",get:function(){return b}}]),t}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",T._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e<n;e++){var i=o.default(t[e]);T._jQueryInterface.call(i,i.data())}}),
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
o.default.fn[p]=T._jQueryInterface,o.default.fn[p].Constructor=T,o.default.fn[p].noConflict=function(){return o.default.fn[p]=v,T._jQueryInterface};
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var C="collapse",S=o.default.fn[C],N={toggle:!0,parent:""},D={toggle:"boolean",parent:"(string|element)"},k='[data-toggle="collapse"]',A=/* */function(){function t(t,e){this._isTransitioning=!1,this._element=t,this._config=this._getConfig(e),this._triggerArray=[].slice.call(document.querySelectorAll('[data-toggle="collapse"][href="#'+t.id+'"],[data-toggle="collapse"][data-target="#'+t.id+'"]'));for(var n=[].slice.call(document.querySelectorAll(k)),i=0,o=n.length;i<o;i++){var a=n[i],s=c.getSelectorFromElement(a),l=[].slice.call(document.querySelectorAll(s)).filter(function(e){return e===t});null!==s&&l.length>0&&(this._selector=s,this._triggerArray.push(a))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}// Getters
var e=t.prototype;
// Public
return e.toggle=function(){o.default(this._element).hasClass("show")?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!this._isTransitioning&&!o.default(this._element).hasClass("show")&&(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter(function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains("collapse")})).length&&(e=null),!(e&&(n=o.default(e).not(this._selector).data("bs.collapse"))&&n._isTransitioning))){var a=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(a),!a.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data("bs.collapse",null));var s=this._getDimension();o.default(this._element).removeClass("collapse").addClass("collapsing"),this._element.style[s]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass("collapsed").attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(s[0].toUpperCase()+s.slice(1)),r=c.getTransitionDurationFromElement(this._element);o.default(this._element).one(c.TRANSITION_END,function(){o.default(i._element).removeClass("collapsing").addClass("collapse show"),i._element.style[s]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")}).emulateTransitionEnd(r),this._element.style[s]=this._element[l]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass("show")){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",c.reflow(this._element),o.default(this._element).addClass("collapsing").removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var a=0;a<i;a++){var s=this._triggerArray[a],l=c.getSelectorFromElement(s);if(null!==l)o.default([].slice.call(document.querySelectorAll(l))).hasClass("show")||o.default(s).addClass("collapsed").attr("aria-expanded",!1)}this.setTransitioning(!0);this._element.style[n]="";var r=c.getTransitionDurationFromElement(this._element);o.default(this._element).one(c.TRANSITION_END,function(){t.setTransitioning(!1),o.default(t._element).removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")}).emulateTransitionEnd(r)}}},e.setTransitioning=function(t){this._isTransitioning=t},e.dispose=function(){o.default.removeData(this._element,"bs.collapse"),this._config=null,this._parent=null,this._element=null,this._triggerArray=null,this._isTransitioning=null}// Private
,e._getConfig=function(t){return(t=r({},N,t)).toggle=Boolean(t.toggle),// Coerce string values
c.typeCheckConfig(C,t,D),t},e._getDimension=function(){return o.default(this._element).hasClass("width")?"width":"height"},e._getParent=function(){var e,n=this;c.isElement(this._config.parent)?(e=this._config.parent,// It's a jQuery object
void 0!==this._config.parent.jquery&&(e=this._config.parent[0])):e=document.querySelector(this._config.parent);var i='[data-toggle="collapse"][data-parent="'+this._config.parent+'"]',a=[].slice.call(e.querySelectorAll(i));return o.default(a).each(function(e,i){n._addAriaAndCollapsedClass(t._getTargetFromElement(i),[i])}),e},e._addAriaAndCollapsedClass=function(t,e){var n=o.default(t).hasClass("show");e.length&&o.default(e).toggleClass("collapsed",!n).attr("aria-expanded",n)}// Static
,t._getTargetFromElement=function(t){var e=c.getSelectorFromElement(t);return e?document.querySelector(e):null},t._jQueryInterface=function(e){return this.each(function(){var n=o.default(this),i=n.data("bs.collapse"),a=r({},N,n.data(),"object"==typeof e&&e?e:{});if(!i&&a.toggle&&"string"==typeof e&&/show|hide/.test(e)&&(a.toggle=!1),i||(i=new t(this,a),n.data("bs.collapse",i)),"string"==typeof e){if(void 0===i[e])throw new TypeError('No method named "'+e+'"');i[e]()}})},l(t,null,[{key:"VERSION",get:function(){return"4.6.0"}},{key:"Default",get:function(){return N}}]),t}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
o.default(document).on("click.bs.collapse.data-api",k,function(t){
// preventDefault only for <a> elements (which change the URL) not inside the collapsible element
"A"===t.currentTarget.tagName&&t.preventDefault();var e=o.default(this),n=c.getSelectorFromElement(this),i=[].slice.call(document.querySelectorAll(n));o.default(i).each(function(){var t=o.default(this),n=t.data("bs.collapse")?"toggle":e.data();A._jQueryInterface.call(t,n)})}),
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
o.default.fn[C]=A._jQueryInterface,o.default.fn[C].Constructor=A,o.default.fn[C].noConflict=function(){return o.default.fn[C]=S,A._jQueryInterface};
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var I="dropdown",j=o.default.fn[I],O=new RegExp("38|40|27"),x={offset:0,flip:!0,boundary:"scrollParent",reference:"toggle",display:"dynamic",popperConfig:null},P={offset:"(number|string|function)",flip:"boolean",boundary:"(string|element)",reference:"(string|element)",display:"string",popperConfig:"(null|object)"},R=/* */function(){function t(t,e){this._element=t,this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar(),this._addEventListeners()}// Getters
var e=t.prototype;
// Public
return e.toggle=function(){if(!this._element.disabled&&!o.default(this._element).hasClass("disabled")){var e=o.default(this._menu).hasClass("show");t._clearMenus(),e||this.show(!0)}},e.show=function(e){if(void 0===e&&(e=!1),!(this._element.disabled||o.default(this._element).hasClass("disabled")||o.default(this._menu).hasClass("show"))){var n={relatedTarget:this._element},i=o.default.Event("show.bs.dropdown",n),s=t._getParentFromElement(this._element);if(o.default(s).trigger(i),!i.isDefaultPrevented()){// Totally disable Popper for Dropdowns in Navbar
if(!this._inNavbar&&e){
/**
* Check for Popper dependency
* Popper - https://popper.js.org
*/
if(void 0===a.default)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");var l=this._element;"parent"===this._config.reference?l=s:c.isElement(this._config.reference)&&(l=this._config.reference,// Check if it's jQuery element
void 0!==this._config.reference.jquery&&(l=this._config.reference[0])),// If boundary is not `scrollParent`, then set position to `static`
// to allow the menu to "escape" the scroll parent's boundaries
// https://github.com/twbs/bootstrap/issues/24251
"scrollParent"!==this._config.boundary&&o.default(s).addClass("position-static"),this._popper=new a.default(l,this._menu,this._getPopperConfig())}// If this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
"ontouchstart"in document.documentElement&&0===o.default(s).closest(".navbar-nav").length&&o.default(document.body).children().on("mouseover",null,o.default.noop),this._element.focus(),this._element.setAttribute("aria-expanded",!0),o.default(this._menu).toggleClass("show"),o.default(s).toggleClass("show").trigger(o.default.Event("shown.bs.dropdown",n))}}},e.hide=function(){if(!this._element.disabled&&!o.default(this._element).hasClass("disabled")&&o.default(this._menu).hasClass("show")){var e={relatedTarget:this._element},n=o.default.Event("hide.bs.dropdown",e),i=t._getParentFromElement(this._element);o.default(i).trigger(n),n.isDefaultPrevented()||(this._popper&&this._popper.destroy(),o.default(this._menu).toggleClass("show"),o.default(i).toggleClass("show").trigger(o.default.Event("hidden.bs.dropdown",e)))}},e.dispose=function(){o.default.removeData(this._element,"bs.dropdown"),o.default(this._element).off(".bs.dropdown"),this._element=null,this._menu=null,null!==this._popper&&(this._popper.destroy(),this._popper=null)},e.update=function(){this._inNavbar=this._detectNavbar(),null!==this._popper&&this._popper.scheduleUpdate()}// Private
,e._addEventListeners=function(){var t=this;o.default(this._element).on("click.bs.dropdown",function(e){e.preventDefault(),e.stopPropagation(),t.toggle()})},e._getConfig=function(t){return t=r({},this.constructor.Default,o.default(this._element).data(),t),c.typeCheckConfig(I,t,this.constructor.DefaultType),t},e._getMenuElement=function(){if(!this._menu){var e=t._getParentFromElement(this._element);e&&(this._menu=e.querySelector(".dropdown-menu"))}return this._menu},e._getPlacement=function(){var t=o.default(this._element.parentNode),e="bottom-start";// Handle dropup
return t.hasClass("dropup")?e=o.default(this._menu).hasClass("dropdown-menu-right")?"top-end":"top-start":t.hasClass("dropright")?e="right-start":t.hasClass("dropleft")?e="left-start":o.default(this._menu).hasClass("dropdown-menu-right")&&(e="bottom-end"),e},e._detectNavbar=function(){return o.default(this._element).closest(".navbar").length>0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets,t._element)||{}),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};// Disable Popper if we have a static display
return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),r({},t,this._config.popperConfig)}// Static
,t._jQueryInterface=function(e){return this.each(function(){var n=o.default(this).data("bs.dropdown");if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data("bs.dropdown",n)),"string"==typeof e){if(void 0===n[e])throw new TypeError('No method named "'+e+'"');n[e]()}})},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll('[data-toggle="dropdown"]')),i=0,a=n.length;i<a;i++){var s=t._getParentFromElement(n[i]),l=o.default(n[i]).data("bs.dropdown"),r={relatedTarget:n[i]};if(e&&"click"===e.type&&(r.clickEvent=e),l){var u=l._menu;if(o.default(s).hasClass("show")&&!(e&&("click"===e.type&&/input|textarea/i.test(e.target.tagName)||"keyup"===e.type&&9===e.which)&&o.default.contains(s,e.target))){var d=o.default.Event("hide.bs.dropdown",r);o.default(s).trigger(d),d.isDefaultPrevented()||(// If this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),n[i].setAttribute("aria-expanded","false"),l._popper&&l._popper.destroy(),o.default(u).removeClass("show"),o.default(s).removeClass("show").trigger(o.default.Event("hidden.bs.dropdown",r)))}}}},t._getParentFromElement=function(t){var e,n=c.getSelectorFromElement(t);return n&&(e=document.querySelector(n)),e||t.parentNode}// eslint-disable-next-line complexity
,t._dataApiKeydownHandler=function(e){
// If not input/textarea:
// - And not a key in REGEXP_KEYDOWN => not a dropdown command
// If input/textarea:
// - If space key => not a dropdown command
// - If key is other than escape
// - If key is not up or down => not a dropdown command
// - If trigger inside the menu => not a dropdown command
if((/input|textarea/i.test(e.target.tagName)?!(32===e.which||27!==e.which&&(40!==e.which&&38!==e.which||o.default(e.target).closest(".dropdown-menu").length)):O.test(e.which))&&!this.disabled&&!o.default(this).hasClass("disabled")){var n=t._getParentFromElement(this),i=o.default(n).hasClass("show");if(i||27!==e.which){if(e.preventDefault(),e.stopPropagation(),!i||27===e.which||32===e.which)return 27===e.which&&o.default(n.querySelector('[data-toggle="dropdown"]')).trigger("focus"),void o.default(this).trigger("click");var a=[].slice.call(n.querySelectorAll(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)")).filter(function(t){return o.default(t).is(":visible")});if(0!==a.length){var s=a.indexOf(e.target);38===e.which&&s>0&&
// Up
s--,40===e.which&&s<a.length-1&&
// Down
s++,s<0&&(s=0),a[s].focus()}}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.0"}},{key:"Default",get:function(){return x}},{key:"DefaultType",get:function(){return P}}]),t}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
o.default(document).on("keydown.bs.dropdown.data-api",'[data-toggle="dropdown"]',R._dataApiKeydownHandler).on("keydown.bs.dropdown.data-api",".dropdown-menu",R._dataApiKeydownHandler).on("click.bs.dropdown.data-api keyup.bs.dropdown.data-api",R._clearMenus).on("click.bs.dropdown.data-api",'[data-toggle="dropdown"]',function(t){t.preventDefault(),t.stopPropagation(),R._jQueryInterface.call(o.default(this),"toggle")}).on("click.bs.dropdown.data-api",".dropdown form",function(t){t.stopPropagation()}),
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
o.default.fn[I]=R._jQueryInterface,o.default.fn[I].Constructor=R,o.default.fn[I].noConflict=function(){return o.default.fn[I]=j,R._jQueryInterface};
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var L=o.default.fn.modal,q={backdrop:!0,keyboard:!0,focus:!0,show:!0},F={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean",show:"boolean"},Q=".modal-dialog",B=/* */function(){function t(t,e){this._config=this._getConfig(e),this._element=t,this._dialog=t.querySelector(Q),this._backdrop=null,this._isShown=!1,this._isBodyOverflowing=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollbarWidth=0}// Getters
var e=t.prototype;
// Public
return e.toggle=function(t){return this._isShown?this.hide():this.show(t)},e.show=function(t){var e=this;if(!this._isShown&&!this._isTransitioning){o.default(this._element).hasClass("fade")&&(this._isTransitioning=!0);var n=o.default.Event("show.bs.modal",{relatedTarget:t});o.default(this._element).trigger(n),this._isShown||n.isDefaultPrevented()||(this._isShown=!0,this._checkScrollbar(),this._setScrollbar(),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),o.default(this._element).on("click.dismiss.bs.modal",'[data-dismiss="modal"]',function(t){return e.hide(t)}),o.default(this._dialog).on("mousedown.dismiss.bs.modal",function(){o.default(e._element).one("mouseup.dismiss.bs.modal",function(t){o.default(t.target).is(e._element)&&(e._ignoreBackdropClick=!0)})}),this._showBackdrop(function(){return e._showElement(t)}))}},e.hide=function(t){var e=this;if(t&&t.preventDefault(),this._isShown&&!this._isTransitioning){var n=o.default.Event("hide.bs.modal");if(o.default(this._element).trigger(n),this._isShown&&!n.isDefaultPrevented()){this._isShown=!1;var i=o.default(this._element).hasClass("fade");if(i&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),o.default(document).off("focusin.bs.modal"),o.default(this._element).removeClass("show"),o.default(this._element).off("click.dismiss.bs.modal"),o.default(this._dialog).off("mousedown.dismiss.bs.modal"),i){var a=c.getTransitionDurationFromElement(this._element);o.default(this._element).one(c.TRANSITION_END,function(t){return e._hideModal(t)}).emulateTransitionEnd(a)}else this._hideModal()}}},e.dispose=function(){[window,this._element,this._dialog].forEach(function(t){return o.default(t).off(".bs.modal")}),
/**
* `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API`
* Do not move `document` in `htmlElements` array
* It will remove `EVENT_CLICK_DATA_API` event that should remain
*/
o.default(document).off("focusin.bs.modal"),o.default.removeData(this._element,"bs.modal"),this._config=null,this._element=null,this._dialog=null,this._backdrop=null,this._isShown=null,this._isBodyOverflowing=null,this._ignoreBackdropClick=null,this._isTransitioning=null,this._scrollbarWidth=null},e.handleUpdate=function(){this._adjustDialog()}// Private
,e._getConfig=function(t){return t=r({},q,t),c.typeCheckConfig("modal",t,F),t},e._triggerBackdropTransition=function(){var t=this,e=o.default.Event("hidePrevented.bs.modal");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._element.scrollHeight>document.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add("modal-static");var i=c.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(c.TRANSITION_END),o.default(this._element).one(c.TRANSITION_END,function(){t._element.classList.remove("modal-static"),n||o.default(t._element).one(c.TRANSITION_END,function(){t._element.style.overflowY=""}).emulateTransitionEnd(t._element,i)}).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass("fade"),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||
// Don't move modal's DOM position
document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&c.reflow(this._element),o.default(this._element).addClass("show"),this._config.focus&&this._enforceFocus();var a=o.default.Event("shown.bs.modal",{relatedTarget:t}),s=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(a)};if(n){var l=c.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(c.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._enforceFocus=function(){var t=this;o.default(document).off("focusin.bs.modal").on("focusin.bs.modal",function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()})},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on("keydown.dismiss.bs.modal",function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()}):this._isShown||o.default(this._element).off("keydown.dismiss.bs.modal")},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on("resize.bs.modal",function(e){return t.handleUpdate(e)}):o.default(window).off("resize.bs.modal")},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop(function(){o.default(document.body).removeClass("modal-open"),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger("hidden.bs.modal")})},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass("fade")?"fade":"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on("click.dismiss.bs.modal",function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())}),n&&c.reflow(this._backdrop),o.default(this._backdrop).addClass("show"),!t)return;if(!n)return void t();var i=c.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(c.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass("show");var a=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass("fade")){var s=c.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(c.TRANSITION_END,a).emulateTransitionEnd(s)}else a()}else t&&t()}// ----------------------------------------------------------------------
// the following methods are used to handle overflowing modals
// todo (fat): these should probably be refactored out of modal.js
// ----------------------------------------------------------------------
,e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)<window.innerWidth,this._scrollbarWidth=this._getScrollbarWidth()},e._setScrollbar=function(){var t=this;if(this._isBodyOverflowing){
// Note: DOMNode.style.paddingRight returns the actual value or '' if not set
// while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
var e=[].slice.call(document.querySelectorAll(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top")),n=[].slice.call(document.querySelectorAll(".sticky-top"));// Adjust fixed content padding
o.default(e).each(function(e,n){var i=n.style.paddingRight,a=o.default(n).css("padding-right");o.default(n).data("padding-right",i).css("padding-right",parseFloat(a)+t._scrollbarWidth+"px")}),// Adjust sticky content margin
o.default(n).each(function(e,n){var i=n.style.marginRight,a=o.default(n).css("margin-right");o.default(n).data("margin-right",i).css("margin-right",parseFloat(a)-t._scrollbarWidth+"px")});// Adjust body padding
var i=document.body.style.paddingRight,a=o.default(document.body).css("padding-right");o.default(document.body).data("padding-right",i).css("padding-right",parseFloat(a)+this._scrollbarWidth+"px")}o.default(document.body).addClass("modal-open")},e._resetScrollbar=function(){
// Restore fixed content padding
var t=[].slice.call(document.querySelectorAll(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top"));o.default(t).each(function(t,e){var n=o.default(e).data("padding-right");o.default(e).removeData("padding-right"),e.style.paddingRight=n||""});// Restore sticky content
var e=[].slice.call(document.querySelectorAll(".sticky-top"));o.default(e).each(function(t,e){var n=o.default(e).data("margin-right");void 0!==n&&o.default(e).css("margin-right",n).removeData("margin-right")});// Restore body padding
var n=o.default(document.body).data("padding-right");o.default(document.body).removeData("padding-right"),document.body.style.paddingRight=n||""},e._getScrollbarWidth=function(){
// thx d.walsh
var t=document.createElement("div");t.className="modal-scrollbar-measure",document.body.appendChild(t);var e=t.getBoundingClientRect().width-t.clientWidth;return document.body.removeChild(t),e}// Static
,t._jQueryInterface=function(e,n){return this.each(function(){var i=o.default(this).data("bs.modal"),a=r({},q,o.default(this).data(),"object"==typeof e&&e?e:{});if(i||(i=new t(this,a),o.default(this).data("bs.modal",i)),"string"==typeof e){if(void 0===i[e])throw new TypeError('No method named "'+e+'"');i[e](n)}else a.show&&i.show(n)})},l(t,null,[{key:"VERSION",get:function(){return"4.6.0"}},{key:"Default",get:function(){return q}}]),t}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
o.default(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(t){var e,n=this,i=c.getSelectorFromElement(this);i&&(e=document.querySelector(i));var a=o.default(e).data("bs.modal")?"toggle":r({},o.default(e).data(),o.default(this).data());"A"!==this.tagName&&"AREA"!==this.tagName||t.preventDefault();var s=o.default(e).one("show.bs.modal",function(t){t.isDefaultPrevented()||s.one("hidden.bs.modal",function(){o.default(n).is(":visible")&&n.focus()})});B._jQueryInterface.call(o.default(e),a,this)}),
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
o.default.fn.modal=B._jQueryInterface,o.default.fn.modal.Constructor=B,o.default.fn.modal.noConflict=function(){return o.default.fn.modal=L,B._jQueryInterface};
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.6.0): tools/sanitizer.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
var H=["background","cite","href","itemtype","longdesc","poster","src","xlink:href"],U={
// Global attributes allowed on any supplied element below.
"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},M=/^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/gi,W=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i;function V(t,e,n){if(0===t.length)return t;if(n&&"function"==typeof n)return n(t);for(var i=(new window.DOMParser).parseFromString(t,"text/html"),o=Object.keys(e),a=[].slice.call(i.body.querySelectorAll("*")),s=function(t,n){var i=a[t],s=i.nodeName.toLowerCase();if(-1===o.indexOf(i.nodeName.toLowerCase()))return i.parentNode.removeChild(i),"continue";var l=[].slice.call(i.attributes),r=[].concat(e["*"]||[],e[s]||[]);l.forEach(function(t){(function(t,e){var n=t.nodeName.toLowerCase();if(-1!==e.indexOf(n))return-1===H.indexOf(n)||Boolean(t.nodeValue.match(M)||t.nodeValue.match(W));// Check if a regular expression validates the attribute.
for(var i=e.filter(function(t){return t instanceof RegExp}),o=0,a=i.length;o<a;o++)if(n.match(i[o]))return!0;return!1})(t,r)||i.removeAttribute(t.nodeName)})},l=0,r=a.length;l<r;l++)s(l);return i.body.innerHTML}
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/var z="tooltip",K=o.default.fn.tooltip,X=new RegExp("(^|\\s)bs-tooltip\\S+","g"),Y=["sanitize","whiteList","sanitizeFn"],$={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},J={AUTO:"auto",TOP:"top",RIGHT:"right",BOTTOM:"bottom",LEFT:"left"},G={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:U,popperConfig:null},Z={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},tt=/* */function(){function t(t,e){if(void 0===a.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");// private
this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,// Protected
this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}// Getters
var e=t.prototype;
// Public
return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass("show"))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=c.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var s=this.getTipElement(),l=c.getUID(this.constructor.NAME);s.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&o.default(s).addClass("fade");var r="function"==typeof this.config.placement?this.config.placement.call(this,s,this.element):this.config.placement,u=this._getAttachment(r);this.addAttachmentClass(u);var d=this._getContainer();o.default(s).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(s).appendTo(d),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new a.default(this.element,s,this._getPopperConfig(u)),o.default(s).addClass("show"),o.default(s).addClass(this.config.customClass),// If this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var f=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),"out"===e&&t._leave(null,t)};if(o.default(this.tip).hasClass("fade")){var h=c.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(c.TRANSITION_END,f).emulateTransitionEnd(h)}else f()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),a=function(){"show"!==e._hoverState&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass("show"),// If this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass("fade")){var s=c.getTransitionDurationFromElement(n);o.default(n).one(c.TRANSITION_END,a).emulateTransitionEnd(s)}else a();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()}// Protected
,e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=V(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):
// Content is a DOM node or a jQuery
this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t}// Private
,e._getPopperConfig=function(t){var e=this;return r({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t.config.offset(e.offsets,t.element)||{}),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:c.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return J[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach(function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,function(e){return t.toggle(e)});else if("manual"!==e){var n="hover"===e?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i="hover"===e?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,function(e){return t._enter(e)}).on(i,t.config.selector,function(e){return t._leave(e)})}}),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?"focus":"hover"]=!0),o.default(e.getTipElement()).hasClass("show")||"show"===e._hoverState?e._hoverState="show":(clearTimeout(e._timeout),e._hoverState="show",e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){"show"===e._hoverState&&e.show()},e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?"focus":"hover"]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState="out",e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){"out"===e._hoverState&&e.hide()},e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach(function(t){-1!==Y.indexOf(t)&&delete e[t]}),"number"==typeof(t=r({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),c.typeCheckConfig(z,t,this.constructor.DefaultType),t.sanitize&&(t.template=V(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(X);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass("fade"),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)}// Static
,t._jQueryInterface=function(e){return this.each(function(){var n=o.default(this),i=n.data("bs.tooltip"),a="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,a),n.data("bs.tooltip",i)),"string"==typeof e)){if(void 0===i[e])throw new TypeError('No method named "'+e+'"');i[e]()}})},l(t,null,[{key:"VERSION",get:function(){return"4.6.0"}},{key:"Default",get:function(){return G}},{key:"NAME",get:function(){return z}},{key:"DATA_KEY",get:function(){return"bs.tooltip"}},{key:"Event",get:function(){return Z}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return $}}]),t}();
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
o.default.fn.tooltip=tt._jQueryInterface,o.default.fn.tooltip.Constructor=tt,o.default.fn.tooltip.noConflict=function(){return o.default.fn.tooltip=K,tt._jQueryInterface};
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var et="popover",nt=o.default.fn.popover,it=new RegExp("(^|\\s)bs-popover\\S+","g"),ot=r({},tt.Default,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'}),at=r({},tt.DefaultType,{content:"(string|element|function)"}),st={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},lt=/* */function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,e.__proto__=n;var a=i.prototype;
// Overrides
return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},a.setContent=function(){var t=o.default(this.getTipElement());// We use append for html objects to maintain js events
this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")}// Private
,a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(it);null!==e&&e.length>0&&t.removeClass(e.join(""))}// Static
,i._jQueryInterface=function(t){return this.each(function(){var e=o.default(this).data("bs.popover"),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data("bs.popover",e)),"string"==typeof t)){if(void 0===e[t])throw new TypeError('No method named "'+t+'"');e[t]()}})},l(i,null,[{key:"VERSION",
// Getters
get:function(){return"4.6.0"}},{key:"Default",get:function(){return ot}},{key:"NAME",get:function(){return et}},{key:"DATA_KEY",get:function(){return"bs.popover"}},{key:"Event",get:function(){return st}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return at}}]),i}(tt);
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
o.default.fn.popover=lt._jQueryInterface,o.default.fn.popover.Constructor=lt,o.default.fn.popover.noConflict=function(){return o.default.fn.popover=nt,lt._jQueryInterface};
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var rt="scrollspy",ut=o.default.fn[rt],dt={offset:10,method:"auto",target:""},ct={offset:"number",method:"string",target:"(string|element)"},ft="scroll.bs.scrollspy",ht=".nav-link",gt=".list-group-item",mt=".dropdown-item",pt=/* */function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" "+ht+","+this._config.target+" "+gt+","+this._config.target+" "+mt,this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on(ft,function(t){return n._process(t)}),this.refresh(),this._process()}// Getters
var e=t.prototype;
// Public
return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":"position",n="auto"===this._config.method?e:this._config.method,i="position"===n?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map(function(t){var e,a=c.getSelectorFromElement(t);if(a&&(e=document.querySelector(a)),e){var s=e.getBoundingClientRect();if(s.width||s.height)
// TODO (fat): remove sketch reliance on jQuery position/offset
return[o.default(e)[n]().top+i,a]}return null}).filter(function(t){return t}).sort(function(t,e){return t[0]-e[0]}).forEach(function(e){t._offsets.push(e[0]),t._targets.push(e[1])})},e.dispose=function(){o.default.removeData(this._element,"bs.scrollspy"),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null}// Private
,e._getConfig=function(t){if("string"!=typeof(t=r({},dt,"object"==typeof t&&t?t:{})).target&&c.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=c.getUID(rt),o.default(t.target).attr("id",e)),t.target="#"+e}return c.typeCheckConfig(rt,t,ct),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t<this._offsets[0]&&this._offsets[0]>0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;){this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&(void 0===this._offsets[o+1]||t<this._offsets[o+1])&&this._activate(this._targets[o])}}},e._activate=function(t){this._activeTarget=t,this._clear();var e=this._selector.split(",").map(function(e){return e+'[data-target="'+t+'"],'+e+'[href="'+t+'"]'}),n=o.default([].slice.call(document.querySelectorAll(e.join(","))));n.hasClass("dropdown-item")?(n.closest(".dropdown").find(".dropdown-toggle").addClass("active"),n.addClass("active")):(
// Set triggered link as active
n.addClass("active"),// Set triggered links parents as active
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
n.parents(".nav, .list-group").prev(ht+", "+gt).addClass("active"),// Handle special case when .nav-link is inside .nav-item
n.parents(".nav, .list-group").prev(".nav-item").children(ht).addClass("active")),o.default(this._scrollElement).trigger("activate.bs.scrollspy",{relatedTarget:t})},e._clear=function(){[].slice.call(document.querySelectorAll(this._selector)).filter(function(t){return t.classList.contains("active")}).forEach(function(t){return t.classList.remove("active")})}// Static
,t._jQueryInterface=function(e){return this.each(function(){var n=o.default(this).data("bs.scrollspy");if(n||(n=new t(this,"object"==typeof e&&e),o.default(this).data("bs.scrollspy",n)),"string"==typeof e){if(void 0===n[e])throw new TypeError('No method named "'+e+'"');n[e]()}})},l(t,null,[{key:"VERSION",get:function(){return"4.6.0"}},{key:"Default",get:function(){return dt}}]),t}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
o.default(window).on("load.bs.scrollspy.data-api",function(){for(var t=[].slice.call(document.querySelectorAll('[data-spy="scroll"]')),e=t.length;e--;){var n=o.default(t[e]);pt._jQueryInterface.call(n,n.data())}}),
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
o.default.fn[rt]=pt._jQueryInterface,o.default.fn[rt].Constructor=pt,o.default.fn[rt].noConflict=function(){return o.default.fn[rt]=ut,pt._jQueryInterface};
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var _t=o.default.fn.tab,vt=/* */function(){function t(t){this._element=t}// Getters
var e=t.prototype;
// Public
return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&o.default(this._element).hasClass("active")||o.default(this._element).hasClass("disabled"))){var e,n,i=o.default(this._element).closest(".nav, .list-group")[0],a=c.getSelectorFromElement(this._element);if(i){var s="UL"===i.nodeName||"OL"===i.nodeName?"> li > .active":".active";n=(n=o.default.makeArray(o.default(i).find(s)))[n.length-1]}var l=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),r=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(l),o.default(this._element).trigger(r),!r.isDefaultPrevented()&&!l.isDefaultPrevented()){a&&(e=document.querySelector(a)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,"bs.tab"),this._element=null}// Private
,e._activate=function(t,e,n){var i=this,a=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(".active"):o.default(e).find("> li > .active"))[0],s=n&&a&&o.default(a).hasClass("fade"),l=function(){return i._transitionComplete(t,a,n)};if(a&&s){var r=c.getTransitionDurationFromElement(a);o.default(a).removeClass("show").one(c.TRANSITION_END,l).emulateTransitionEnd(r)}else l()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass("active");var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass("active"),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}if(o.default(t).addClass("active"),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),c.reflow(t),t.classList.contains("fade")&&t.classList.add("show"),t.parentNode&&o.default(t.parentNode).hasClass("dropdown-menu")){var a=o.default(t).closest(".dropdown")[0];if(a){var s=[].slice.call(a.querySelectorAll(".dropdown-toggle"));o.default(s).addClass("active")}t.setAttribute("aria-expanded",!0)}n&&n()}// Static
,t._jQueryInterface=function(e){return this.each(function(){var n=o.default(this),i=n.data("bs.tab");if(i||(i=new t(this),n.data("bs.tab",i)),"string"==typeof e){if(void 0===i[e])throw new TypeError('No method named "'+e+'"');i[e]()}})},l(t,null,[{key:"VERSION",get:function(){return"4.6.0"}}]),t}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',function(t){t.preventDefault(),vt._jQueryInterface.call(o.default(this),"show")}),
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
o.default.fn.tab=vt._jQueryInterface,o.default.fn.tab.Constructor=vt,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=_t,vt._jQueryInterface};
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var bt="toast",yt=o.default.fn.toast,Et={animation:"boolean",autohide:"boolean",delay:"number"},wt={animation:!0,autohide:!0,delay:500},Tt=/* */function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}// Getters
var e=t.prototype;
// Public
return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove("showing"),t._element.classList.add("show"),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout(function(){t.hide()},t._config.delay))};if(this._element.classList.remove("hide"),c.reflow(this._element),this._element.classList.add("showing"),this._config.animation){var i=c.getTransitionDurationFromElement(this._element);o.default(this._element).one(c.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains("show")){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains("show")&&this._element.classList.remove("show"),o.default(this._element).off("click.dismiss.bs.toast"),o.default.removeData(this._element,"bs.toast"),this._element=null,this._config=null}// Private
,e._getConfig=function(t){return t=r({},wt,o.default(this._element).data(),"object"==typeof t&&t?t:{}),c.typeCheckConfig(bt,t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on("click.dismiss.bs.toast",'[data-dismiss="toast"]',function(){return t.hide()})},e._close=function(){var t=this,e=function(){t._element.classList.add("hide"),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove("show"),this._config.animation){var n=c.getTransitionDurationFromElement(this._element);o.default(this._element).one(c.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null}// Static
,t._jQueryInterface=function(e){return this.each(function(){var n=o.default(this),i=n.data("bs.toast");if(i||(i=new t(this,"object"==typeof e&&e),n.data("bs.toast",i)),"string"==typeof e){if(void 0===i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}})},l(t,null,[{key:"VERSION",get:function(){return"4.6.0"}},{key:"DefaultType",get:function(){return Et}},{key:"Default",get:function(){return wt}}]),t}();
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
o.default.fn.toast=Tt._jQueryInterface,o.default.fn.toast.Constructor=Tt,o.default.fn.toast.noConflict=function(){return o.default.fn.toast=yt,Tt._jQueryInterface},t.Alert=h,t.Button=m,t.Carousel=T,t.Collapse=A,t.Dropdown=R,t.Modal=B,t.Popover=lt,t.Scrollspy=pt,t.Tab=vt,t.Toast=Tt,t.Tooltip=tt,t.Util=c,Object.defineProperty(t,"__esModule",{value:!0})});
//# sourceMappingURL=bootstrap.js.map
//# sourceMappingURL=bootstrap.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,521 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="../img/favicon.ico">
<title>Reference - r7rs-pffi</title>
<link href="../css/bootstrap.min.css" rel="stylesheet">
<link href="../css/font-awesome.min.css" rel="stylesheet">
<link href="../css/base.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css">
<script src="../js/jquery-1.10.2.min.js" defer></script>
<script src="../js/bootstrap.min.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body>
<div class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="..">r7rs-pffi</a>
<!-- Expander button -->
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbar-collapse">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Expanded navigation -->
<div id="navbar-collapse" class="navbar-collapse collapse">
<!-- Main navigation -->
<ul class="nav navbar-nav">
<li class="navitem">
<a href=".." class="nav-link">Portable Foreign Function Interface for R7RS schemes</a>
</li>
<li class="navitem active">
<a href="./" class="nav-link">Reference</a>
</li>
</ul>
<ul class="nav navbar-nav ml-auto">
<li class="nav-item">
<a href="#" class="nav-link" data-toggle="modal" data-target="#mkdocs_search_modal">
<i class="fa fa-search"></i> Search
</a>
</li>
<li class="nav-item">
<a rel="prev" href=".." class="nav-link">
<i class="fa fa-arrow-left"></i> Previous
</a>
</li>
<li class="nav-item">
<a rel="next" class="nav-link disabled">
Next <i class="fa fa-arrow-right"></i>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-3"><div class="navbar-light navbar-expand-md bs-sidebar hidden-print affix" role="complementary">
<div class="navbar-header">
<button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#toc-collapse" title="Table of Contents">
<span class="fa fa-angle-down"></span>
</button>
</div>
<div id="toc-collapse" class="navbar-collapse collapse card bg-light">
<ul class="nav flex-column">
<li class="nav-item" data-level="1"><a href="#reference" class="nav-link">Reference</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="1"><a href="#types" class="nav-link">Types</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="1"><a href="#procedures-or-macros" class="nav-link">Procedures or macros</a>
<ul class="nav flex-column">
<li class="nav-item" data-level="2"><a href="#pffi-shared-object-auto-load" class="nav-link">pffi-shared-object-auto-load</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-shared-object-load" class="nav-link">pffi-shared-object-load</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-define" class="nav-link">pffi-define</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-define-callback" class="nav-link">pffi-define-callback</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-size-of" class="nav-link">pffi-size-of</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-pointer-allocate" class="nav-link">pffi-pointer-allocate</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-pointer-null" class="nav-link">pffi-pointer-null</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-string-pointer" class="nav-link">pffi-string-&gt;pointer</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-pointer-string" class="nav-link">pffi-pointer-&gt;string</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-pointer-free" class="nav-link">pffi-pointer-free</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-pointer" class="nav-link">pffi-pointer?</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-pointer-set" class="nav-link">pffi-pointer-set!</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-pointer-get" class="nav-link">pffi-pointer-get</a>
<ul class="nav flex-column">
</ul>
</li>
<li class="nav-item" data-level="2"><a href="#pffi-pointer-deref" class="nav-link">pffi-pointer-deref</a>
<ul class="nav flex-column">
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div></div>
<div class="col-md-9" role="main">
<h1 id="reference">Reference</h1>
<h1 id="types">Types</h1>
<p>Types are given as symbols, for example 'int8 or 'pointer.</p>
<ul>
<li>int8</li>
<li>uint8</li>
<li>int16</li>
<li>uint16</li>
<li>int32</li>
<li>uint32</li>
<li>int64</li>
<li>uint64</li>
<li>char</li>
<li>unsigned-char</li>
<li>short</li>
<li>unsigned-short</li>
<li>int</li>
<li>unsigned-int</li>
<li>long</li>
<li>unsigned-long</li>
<li>float</li>
<li>double</li>
<li>string</li>
<li>pointer</li>
</ul>
<h1 id="procedures-or-macros">Procedures or macros</h1>
<p>On some implementations these are procedures, on some macros.</p>
<p>The arguments are in form</p>
<ul>
<li>NAME - TYPE</li>
</ul>
<p>The return value is in form</p>
<ul>
<li>TYPE</li>
</ul>
<h2 id="pffi-shared-object-auto-load">pffi-shared-object-auto-load</h2>
<p>Arguments:</p>
<ul>
<li>headers - (list string ...)<ul>
<li>C headers of the library</li>
<li>For example (list "curl/curl.h")</li>
</ul>
</li>
<li>object-name - symbol<ul>
<li>The name of the dynamic library file you want to load</li>
<li>Without the "lib" in front of it</li>
<li>Without the ".so" or ".dll" at the end</li>
</ul>
</li>
<li>additional-versions - (list string...)<ul>
<li>For example (list ".0" ".1")</li>
</ul>
</li>
<li>additional-paths - (list string...)<ul>
<li>Any additional paths you want to search for the library</li>
<li>For example (list "./mylibs")</li>
</ul>
</li>
</ul>
<p>Returns:</p>
<ul>
<li>object<ul>
<li>Shared object, the type depends on the implementation</li>
</ul>
</li>
</ul>
<h2 id="pffi-shared-object-load">pffi-shared-object-load</h2>
<p>It is recommended to use the pffi-shared-object-auto-load instead of this
directly.</p>
<p>Arguments:</p>
<ul>
<li>headers - (list string ...)<ul>
<li>Headers that need to be included</li>
<li>Example (list "curl/curl.h")</li>
</ul>
</li>
<li>path - string<ul>
<li>The full path to the shared object you want to load, including any "lib" infront and .so/.dll at the end</li>
<li>Example "libcurl.so"</li>
</ul>
</li>
</ul>
<p>Returns:</p>
<ul>
<li>object<ul>
<li>Shared object, the type depends on the implementation</li>
</ul>
</li>
</ul>
<h2 id="pffi-define">pffi-define</h2>
<p>Defines new foreign procedure.</p>
<p>Arguments:</p>
<ul>
<li>scheme-name - symbol<ul>
<li>The name of the procedure used on scheme side</li>
</ul>
</li>
<li>shared-object - object<ul>
<li>The shared object</li>
<li>Use pffi-shared-object-auto-load or pffi-shared-object-load to get this</li>
</ul>
</li>
<li>c-name - symbol<ul>
<li>The name of the C function</li>
</ul>
</li>
<li>return-type - symbol<ul>
<li>The return type of the C function</li>
</ul>
</li>
<li>arguments-types - (list symbol ...)<ul>
<li>The C function argument types</li>
<li>Need to be given in form (list 'type 'type)</li>
</ul>
</li>
</ul>
<h2 id="pffi-define-callback">pffi-define-callback</h2>
<p>Defines new callback function.</p>
<p>Arguments:</p>
<ul>
<li>scheme-name<ul>
<li>The name of the function used on scheme side</li>
</ul>
</li>
<li>return-type - symbol<ul>
<li>The return type of the callback</li>
</ul>
</li>
<li>arguments-types - (list symbol ...)<ul>
<li>The callback function argument types</li>
</ul>
</li>
<li>procedure - procedure<ul>
<li>Procedure used as callback function</li>
<li>Argument count must match the argument-types count</li>
</ul>
</li>
</ul>
<h2 id="pffi-size-of">pffi-size-of</h2>
<p>Get the size of type.</p>
<p>Arguments:</p>
<ul>
<li>type - symbol<ul>
<li>The type you want the size of</li>
</ul>
</li>
</ul>
<p>Returns:</p>
<ul>
<li>number<ul>
<li>The size of the given type</li>
</ul>
</li>
</ul>
<h2 id="pffi-pointer-allocate">pffi-pointer-allocate</h2>
<p>Allocates a pointer of given size.</p>
<p>Arguments:</p>
<ul>
<li>size - number<ul>
<li>The size of the pointer you want to allocate</li>
</ul>
</li>
</ul>
<p>Returns:</p>
<ul>
<li>object<ul>
<li>A pointer of given size</li>
</ul>
</li>
</ul>
<h2 id="pffi-pointer-null">pffi-pointer-null</h2>
<p>Create a null pointer.</p>
<p>Returns:
- object
- Null pointer</p>
<h2 id="pffi-string-pointer">pffi-string-&gt;pointer</h2>
<p>Arguments:</p>
<ul>
<li>string-content - string<ul>
<li>The string you want to transform into pointer</li>
</ul>
</li>
</ul>
<p>Returns:</p>
<ul>
<li>object<ul>
<li>Pointer of the given string</li>
</ul>
</li>
</ul>
<h2 id="pffi-pointer-string">pffi-pointer-&gt;string</h2>
<p>Arguments:</p>
<ul>
<li>pointer - object<ul>
<li>The pointer you want to transform to string</li>
</ul>
</li>
</ul>
<p>Returns:</p>
<ul>
<li>string<ul>
<li>String from the given pointer</li>
</ul>
</li>
</ul>
<h2 id="pffi-pointer-free">pffi-pointer-free</h2>
<p>Arguments:</p>
<ul>
<li>pointer - object<ul>
<li>The pointer you want to free</li>
</ul>
</li>
</ul>
<h2 id="pffi-pointer">pffi-pointer?</h2>
<p>Arguments:</p>
<ul>
<li>object - object<ul>
<li>The object you want to check wether it is a pointer or not</li>
</ul>
</li>
</ul>
<p>Returns:</p>
<ul>
<li>boolean<ul>
<li>Returns true if given object is pointer, otherwise false</li>
</ul>
</li>
</ul>
<h2 id="pffi-pointer-set">pffi-pointer-set!</h2>
<p>Arguments:</p>
<ul>
<li>pointer - object<ul>
<li>The pointer you want to modify</li>
</ul>
</li>
<li>type - symbol<ul>
<li>The type of value that will be put into the pointer</li>
</ul>
</li>
<li>offset -number<ul>
<li>The location of the value inside the pointer</li>
<li>For example: (+ (pffi-size-of 'int) (pffi-size-of 'pointer)) or 0</li>
</ul>
</li>
<li>value - object<ul>
<li>The value to be placed into the object</li>
</ul>
</li>
</ul>
<h2 id="pffi-pointer-get">pffi-pointer-get</h2>
<p>Arguments:</p>
<ul>
<li>pointer - object<ul>
<li>The pointer you want to get the value from</li>
</ul>
</li>
<li>type - symbol<ul>
<li>The type of value you want to get</li>
<li>For example: 'int</li>
</ul>
</li>
<li>offset - number<ul>
<li>The location of the value inside the pointer</li>
<li>For example: (+ (pffi-size-of 'int) (pffi-size-of 'pointer)) or 0</li>
</ul>
</li>
</ul>
<p>Returns:</p>
<ul>
<li>object<ul>
<li>The value in the poiner in the given offset as given type</li>
</ul>
</li>
</ul>
<h2 id="pffi-pointer-deref">pffi-pointer-deref</h2>
<p>Arguments:</p>
<ul>
<li>pointer<ul>
<li>The pointer to dereference</li>
</ul>
</li>
</ul>
<p>Returns:</p>
<ul>
<li>object<ul>
<li>Whatever the pointer holds</li>
</ul>
</li>
</ul></div>
</div>
</div>
<footer class="col-md-12">
<hr>
<p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a>.</p>
</footer>
<script>
var base_url = "..",
shortcuts = {"help": 191, "next": 78, "previous": 80, "search": 83};
</script>
<script src="../js/base.js" defer></script>
<script src="../search/main.js" defer></script>
<div class="modal" id="mkdocs_search_modal" tabindex="-1" role="dialog" aria-labelledby="searchModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="searchModalLabel">Search</h4>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
</div>
<div class="modal-body">
<p>
From here you can search these documents. Enter
your search terms below.
</p>
<form>
<div class="form-group">
<input type="search" class="form-control" placeholder="Search..." id="mkdocs-search-query" title="Type search term here">
</div>
</form>
<div id="mkdocs-search-results"></div>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div><div class="modal" id="mkdocs_keyboard_modal" tabindex="-1" role="dialog" aria-labelledby="keyboardModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="keyboardModalLabel">Keyboard Shortcuts</h4>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
</div>
<div class="modal-body">
<table class="table">
<thead>
<tr>
<th style="width: 20%;">Keys</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td class="help shortcut"><kbd>?</kbd></td>
<td>Open this help</td>
</tr>
<tr>
<td class="next shortcut"><kbd>n</kbd></td>
<td>Next page</td>
</tr>
<tr>
<td class="prev shortcut"><kbd>p</kbd></td>
<td>Previous page</td>
</tr>
<tr>
<td class="search shortcut"><kbd>s</kbd></td>
<td>Search</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +0,0 @@
function getSearchTermFromLocation() {
var sPageURL = window.location.search.substring(1);
var sURLVariables = sPageURL.split('&');
for (var i = 0; i < sURLVariables.length; i++) {
var sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] == 'q') {
return decodeURIComponent(sParameterName[1].replace(/\+/g, '%20'));
}
}
}
function joinUrl (base, path) {
if (path.substring(0, 1) === "/") {
// path starts with `/`. Thus it is absolute.
return path;
}
if (base.substring(base.length-1) === "/") {
// base ends with `/`
return base + path;
}
return base + "/" + path;
}
function formatResult (location, title, summary) {
return '<article><h3><a href="' + joinUrl(base_url, location) + '">'+ title + '</a></h3><p>' + summary +'</p></article>';
}
function displayResults (results) {
var search_results = document.getElementById("mkdocs-search-results");
while (search_results.firstChild) {
search_results.removeChild(search_results.firstChild);
}
if (results.length > 0){
for (var i=0; i < results.length; i++){
var result = results[i];
var html = formatResult(result.location, result.title, result.summary);
search_results.insertAdjacentHTML('beforeend', html);
}
} else {
search_results.insertAdjacentHTML('beforeend', "<p>No results found</p>");
}
}
function doSearch () {
var query = document.getElementById('mkdocs-search-query').value;
if (query.length > min_search_length) {
if (!window.Worker) {
displayResults(search(query));
} else {
searchWorker.postMessage({query: query});
}
} else {
// Clear results for short queries
displayResults([]);
}
}
function initSearch () {
var search_input = document.getElementById('mkdocs-search-query');
if (search_input) {
search_input.addEventListener("keyup", doSearch);
}
var term = getSearchTermFromLocation();
if (term) {
search_input.value = term;
doSearch();
}
}
function onWorkerMessage (e) {
if (e.data.allowSearch) {
initSearch();
} else if (e.data.results) {
var results = e.data.results;
displayResults(results);
} else if (e.data.config) {
min_search_length = e.data.config.min_search_length-1;
}
}
if (!window.Worker) {
console.log('Web Worker API not supported');
// load index in main thread
$.getScript(joinUrl(base_url, "search/worker.js")).done(function () {
console.log('Loaded worker');
init();
window.postMessage = function (msg) {
onWorkerMessage({data: msg});
};
}).fail(function (jqxhr, settings, exception) {
console.error('Could not load worker.js');
});
} else {
// Wrap search in a web worker
var searchWorker = new Worker(joinUrl(base_url, "search/worker.js"));
searchWorker.postMessage({init: true});
searchWorker.onmessage = onWorkerMessage;
}

File diff suppressed because one or more lines are too long

View File

@ -1,130 +0,0 @@
var base_path = 'function' === typeof importScripts ? '.' : '/search/';
var allowSearch = false;
var index;
var documents = {};
var lang = ['en'];
var data;
function getScript(script, callback) {
console.log('Loading script: ' + script);
$.getScript(base_path + script).done(function () {
callback();
}).fail(function (jqxhr, settings, exception) {
console.log('Error: ' + exception);
});
}
function getScriptsInOrder(scripts, callback) {
if (scripts.length === 0) {
callback();
return;
}
getScript(scripts[0], function() {
getScriptsInOrder(scripts.slice(1), callback);
});
}
function loadScripts(urls, callback) {
if( 'function' === typeof importScripts ) {
importScripts.apply(null, urls);
callback();
} else {
getScriptsInOrder(urls, callback);
}
}
function onJSONLoaded () {
data = JSON.parse(this.responseText);
var scriptsToLoad = ['lunr.js'];
if (data.config && data.config.lang && data.config.lang.length) {
lang = data.config.lang;
}
if (lang.length > 1 || lang[0] !== "en") {
scriptsToLoad.push('lunr.stemmer.support.js');
if (lang.length > 1) {
scriptsToLoad.push('lunr.multi.js');
}
for (var i=0; i < lang.length; i++) {
if (lang[i] != 'en') {
scriptsToLoad.push(['lunr', lang[i], 'js'].join('.'));
}
}
}
loadScripts(scriptsToLoad, onScriptsLoaded);
}
function onScriptsLoaded () {
console.log('All search scripts loaded, building Lunr index...');
if (data.config && data.config.separator && data.config.separator.length) {
lunr.tokenizer.separator = new RegExp(data.config.separator);
}
if (data.index) {
index = lunr.Index.load(data.index);
data.docs.forEach(function (doc) {
documents[doc.location] = doc;
});
console.log('Lunr pre-built index loaded, search ready');
} else {
index = lunr(function () {
if (lang.length === 1 && lang[0] !== "en" && lunr[lang[0]]) {
this.use(lunr[lang[0]]);
} else if (lang.length > 1) {
this.use(lunr.multiLanguage.apply(null, lang)); // spread operator not supported in all browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Browser_compatibility
}
this.field('title');
this.field('text');
this.ref('location');
for (var i=0; i < data.docs.length; i++) {
var doc = data.docs[i];
this.add(doc);
documents[doc.location] = doc;
}
});
console.log('Lunr index built, search ready');
}
allowSearch = true;
postMessage({config: data.config});
postMessage({allowSearch: allowSearch});
}
function init () {
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", onJSONLoaded);
var index_path = base_path + '/search_index.json';
if( 'function' === typeof importScripts ){
index_path = 'search_index.json';
}
oReq.open("GET", index_path);
oReq.send();
}
function search (query) {
if (!allowSearch) {
console.error('Assets for search still loading');
return;
}
var resultDocuments = [];
var results = index.search(query);
for (var i=0; i < results.length; i++){
var result = results[i];
doc = documents[result.ref];
doc.summary = doc.text.substring(0, 200);
resultDocuments.push(doc);
}
return resultDocuments;
}
if( 'function' === typeof importScripts ) {
onmessage = function (e) {
if (e.data.init) {
init();
} else if (e.data.query) {
postMessage({ results: search(e.data.query) });
} else {
console.error("Worker - Unrecognized message: " + e);
}
};
}

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><url>
<loc>None</loc>
<lastmod>2024-09-03</lastmod>
<changefreq>daily</changefreq>
</url><url>
<loc>None</loc>
<lastmod>2024-09-03</lastmod>
<changefreq>daily</changefreq>
</url>
</urlset>

Binary file not shown.

View File

@ -0,0 +1,106 @@
(define (default-writer obj out)
(when obj
(display obj out)))
(define default-lookup
(compose-lookups
alist-lookup))
(define default-collection
(compose-collections
vector-collection
stream-collection))
(define (port->string port)
(define str
(let loop ((chunks '())
(chunk (read-string 2000 port)))
(if (eof-object? chunk)
(apply string-append (reverse chunks))
(loop (cons chunk chunks)
(read-string 2000 port)))))
(close-input-port port)
str)
(define (template-get-partials template)
(define partials
(let loop ((template template)
(parts '()))
(cond
((null? template) parts)
(else (let ((t (car template))
(rest (cdr template)))
(cond
((partial? t) (loop rest
(cons (partial-name t) parts)))
((section? t) (loop rest
(append (template-get-partials (section-content t))
parts)))
(else (loop rest
parts))))))))
(delete-duplicates! partials))
(define compile
(case-lambda
((template) (compile/without-partials template))
((root partial-locator) (compile/with-partials root partial-locator))))
(define (compile/without-partials template)
(compile/with-partials #f (lambda (partial)
(if partial
#f
template))))
(define (compile/with-partials root partial-locator)
;; returns 2 values: missing partials (found in part) and compiled part template
(define (compile-part part resolved-partials)
(define source (partial-locator part))
(define in (cond
((not source) "")
((string? source) source)
((port? source) (port->string source))
(else (error "Partial locator returned unrecognized type"))))
(define template (parse (read-tokens in)))
(define partials (template-get-partials template))
(define missing-partials (lset-difference string=? partials resolved-partials))
(values missing-partials template))
(let loop ((unresolved (list root))
(resolved-map '())
(resolved-lst '()))
(cond
((null? unresolved) (cons root resolved-map))
(else (let ((part (car unresolved)))
(define-values (unresolved* template)
(compile-part part resolved-lst))
(loop (append unresolved* (cdr unresolved))
(cons (cons part template) resolved-map)
(cons part resolved-lst)))))))
(define current-lookup (make-parameter default-lookup))
(define current-collection (make-parameter default-collection))
(define current-writer (make-parameter default-writer))
(define execute
(case-lambda
((compilation data)
(let ((out (open-output-string)))
(execute compilation data out)
(get-output-string out)))
((compilation data out)
(define root (car compilation))
(define partials (cdr compilation))
(define template (cdr (assoc root partials)))
(define lookup (current-lookup))
(define collection* (current-collection))
(define writer (current-writer))
(executor-execute template
(list data)
partials
out
lookup
(collection-pred-proc collection*)
(collection-empty?-proc collection*)
(collection-for-each-proc collection*)
writer))))

View File

@ -0,0 +1,73 @@
(define-library
(arvyy mustache-test)
(import (scheme base)
(scheme write)
(arvyy mustache)
(srfi 41))
(export run-tests)
(cond-expand
(chibi
(import (rename (except (chibi test) test-equal)
(test test-equal))))
((library (srfi 64))
(import (srfi 64)))
(else (error "No testing library found")))
(begin
(define-syntax test-mustache
(syntax-rules ()
((_ name data template expected)
(test-equal name expected (execute (compile "foo" (lambda args template)) data)))
((_ name data partials template expected)
(let* ((partials* (cons (cons "root" template) partials))
(fn (lambda (n)
(cond
((assoc n partials*) => cdr)
(else #f)))))
(test-equal name expected (execute (compile "root" fn) data)))))))
(include "mustache-test/comments.scm"
"mustache-test/delimiters.scm"
"mustache-test/implementation-specific.scm"
"mustache-test/interpolation.scm"
"mustache-test/inverted.scm"
"mustache-test/partials.scm"
"mustache-test/sections.scm")
(begin
(define (run-tests)
(test-begin "mustache")
(test-group
"comments"
(run-tests/comments))
(test-group
"delimiters"
(run-tests/delimiters))
(test-group
"interpolation"
(run-tests/interpolation))
(test-group
"inverted"
(run-tests/inverted))
(test-group
"partials"
(run-tests/partials))
(test-group
"sections"
(run-tests/sections))
(test-group
"implementation-specific"
(run-tests/implementation-specific))
(test-end))))

View File

@ -0,0 +1,56 @@
(define (run-tests/comments)
(test-mustache "Inline"
'()
"12345{{! Comment Block! }}67890"
"1234567890")
(test-mustache "Multiline"
'()
"12345{{!\n This is a\n multi-line comment...\n}}67890"
"1234567890")
(test-mustache "Standalone"
'()
"Begin.\n{{! Comment Block! }}\nEnd."
"Begin.\nEnd.")
(test-mustache "Indented Standalone"
'()
"Begin.\n {{! Comment Block! }}\nEnd."
"Begin.\nEnd.")
(test-mustache "Standalone Line Endings"
'()
"\r\n{{! Standalone Comment }}\r\n"
"\r\n")
(test-mustache "Standalone Without Previous Line"
'()
" {{! I'm Still Standalone }}\n!"
"!")
(test-mustache "Standalone Without Newline"
'()
"!\n {{! I'm Still Standalone }}"
"!\n")
(test-mustache "Multiline Standalone"
'()
"Begin.\n{{!\nSomething's going on here...\n}}\nEnd."
"Begin.\nEnd.")
(test-mustache "Indented Multiline Standalone"
'()
"Begin.\n {{!\n Something's going on here...\n }}\nEnd."
"Begin.\nEnd.")
(test-mustache "Indented Inline"
'()
" 12 {{! 34 }}\n"
" 12 \n")
(test-mustache "Surrounding Whitespace"
'()
"12345 {{! Comment Block! }} 67890"
"12345 67890"))

View File

@ -0,0 +1,75 @@
(define (run-tests/delimiters)
(test-mustache "Pair Behavior"
'((text . "Hey!"))
"{{=<% %>=}}(<%text%>)"
"(Hey!)")
(test-mustache "Special Characters"
'((text . "It worked!"))
"({{=[ ]=}}[text])"
"(It worked!)")
(test-mustache "Sections"
'((section . #t)
(data . "I got interpolated."))
"[\n{{#section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= | | =}}\n|#section|\n {{data}}\n |data|\n|/section|\n]\n"
"[\n I got interpolated.\n |data|\n\n {{data}}\n I got interpolated.\n]\n")
(test-mustache "Inverted Sections"
'((section . #f)
(data . "I got interpolated."))
"[\n{{^section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= | | =}}\n|^section|\n {{data}}\n |data|\n|/section|\n]\n"
"[\n I got interpolated.\n |data|\n\n {{data}}\n I got interpolated.\n]\n")
(test-mustache "Partial Inheritence"
'((value . "yes"))
'(("include" . ".{{value}}."))
"[ {{>include}} ]\n{{= | | =}}\n[ |>include| ]\n"
"[ .yes. ]\n[ .yes. ]\n")
(test-mustache "Post-Partial Behavior"
'((value . "yes"))
'(("include" . ".{{value}}. {{= | | =}} .|value|."))
"[ {{>include}} ]\n[ .{{value}}. .|value|. ]\n"
"[ .yes. .yes. ]\n[ .yes. .|value|. ]\n")
(test-mustache "Surrounding Whitespace"
'()
"| {{=@ @=}} |"
"| |")
(test-mustache "Outlying Whitespace (Inline)"
'()
" | {{=@ @=}}\n"
" | \n")
(test-mustache "Standalone Tag"
'()
"Begin.\n{{=@ @=}}\nEnd.\n"
"Begin.\nEnd.\n")
(test-mustache "Indented Standalone Tag"
'()
"Begin.\n {{=@ @=}}\nEnd.\n"
"Begin.\nEnd.\n")
(test-mustache "Standalone Line Endings"
'()
"|\r\n{{= @ @ =}}\r\n|"
"|\r\n|")
(test-mustache "Standalone Without Previous Line"
'()
" {{=@ @=}}\n="
"=")
(test-mustache "Standalone Without Newline"
'()
"=\n {{=@ @=}}"
"=\n")
(test-mustache "Pair with Padding"
'()
"|{{= @ @ =}}|"
"||"))

View File

@ -0,0 +1,71 @@
(define-record-type <foo> (foo bar) foo? (bar foo-bar))
(define (run-tests/implementation-specific)
(define (foo-lookup obj name found not-found)
(cond
((not (foo? obj)) (not-found))
((string=? "bar" name) (found (foo-bar obj)))
(else (not-found))))
(define alist+foo (compose-lookups alist-lookup foo-lookup))
(define (write-foo obj out)
(write-string "(foo " out)
(display (foo-bar obj) out)
(write-string ")" out))
(define-record-type <num-lst> (num-lst count) num-lst? (count num-lst-count))
(define num-lst-collection
(collection
num-lst?
(lambda (obj) (= 0 (num-lst-count obj)))
(lambda (proc obj)
(define target (num-lst-count obj))
(let loop ((i 0))
(when (< i target)
(begin
(proc i)
(loop (+ 1 i))))))))
(parameterize
((current-writer (lambda (obj out)
(cond
((not obj) #t)
((foo? obj) (write-foo obj out))
(else (display obj out))))))
(test-mustache "Custom writer"
`((obj . ,(foo "baz")))
"Test {{obj}}"
"Test (foo baz)"))
(parameterize
((current-lookup alist+foo))
(test-mustache "Custom lookup"
`((a . ((bar . "baz1")))
(b . ,(foo "baz2")))
"{{a.bar}}, {{b.bar}}"
"baz1, baz2"))
(parameterize
((current-collection num-lst-collection))
(test-mustache "Custom collection"
`((a . ,(num-lst 3)))
"{{#a}}{{.}};{{/a}}"
"0;1;2;"))
(parameterize
((current-collection list-collection)
(current-lookup foo-lookup))
(test-mustache "List collection"
(foo '(0 1 2))
"{{#bar}}{{.}};{{/bar}}"
"0;1;2;"))
(parameterize
((current-collection stream-collection)
(current-lookup foo-lookup))
(test-mustache "Stream collection"
(foo (list->stream '(0 1 2)))
"{{#bar}}{{.}};{{/bar}}"
"0;1;2;")))

View File

@ -0,0 +1,199 @@
(define (run-tests/interpolation)
(test-mustache "No Interpolation"
'()
"Hello from {Mustache}!"
"Hello from {Mustache}!")
(test-mustache "Basic Interpolation"
'((subject . "world"))
"Hello, {{subject}}!"
"Hello, world!")
(test-mustache "HTML Escaping"
'((forbidden . "& \" < >"))
"These characters should be HTML escaped: {{forbidden}}"
"These characters should be HTML escaped: &amp; &quot; &lt; &gt;")
(test-mustache "Triple Mustache"
'((forbidden . "& \" < >"))
"These characters should not be HTML escaped: {{{forbidden}}}"
"These characters should not be HTML escaped: & \" < >")
(test-mustache "Ampersand"
'((forbidden . "& \" < >"))
"These characters should not be HTML escaped: {{&forbidden}}"
"These characters should not be HTML escaped: & \" < >")
(test-mustache "Basic Integer Interpolation"
'((mph . 85))
"\"{{mph}} miles an hour!\""
"\"85 miles an hour!\"")
(test-mustache "Triple Mustache Integer Interpolation"
'((mph . 85))
"\"{{{mph}}} miles an hour!\""
"\"85 miles an hour!\"")
(test-mustache "Ampersand Mustache Integer Interpolation"
'((mph . 85))
"\"{{&mph}} miles an hour!\""
"\"85 miles an hour!\"")
(test-mustache "Basic Decimal Interpolation"
'((power . 1.210))
"\"{{power}} jiggawatts!\""
"\"1.21 jiggawatts!\"")
(test-mustache "Triple Mustache Decimal Interpolation"
'((power . 1.210))
"\"{{{power}}} jiggawatts!\""
"\"1.21 jiggawatts!\"")
(test-mustache "Ampersand Mustache Decimal Interpolation"
'((power . 1.210))
"\"{{&power}} jiggawatts!\""
"\"1.21 jiggawatts!\"")
(test-mustache "Basic Null Interpolation"
'((cannot . #f))
"I ({{cannot}}) be seen!"
"I () be seen!")
(test-mustache "Triple Mustache Null Interpolation"
'((cannot . #f))
"I ({{{cannot}}}) be seen!"
"I () be seen!")
(test-mustache "Ampersand Null Interpolation"
'((cannot . #f))
"I ({{&cannot}}) be seen!"
"I () be seen!")
(test-mustache "Basic Context Miss Interpolation"
'()
"I ({{cannot}}) be seen!"
"I () be seen!")
(test-mustache "Triple Mustache Context Miss Interpolation"
'()
"I ({{{cannot}}}) be seen!"
"I () be seen!")
(test-mustache "Ampersand Context Miss Interpolation"
'()
"I ({{&cannot}}) be seen!"
"I () be seen!")
(test-mustache "Dotted Names - Basic Interpolation"
'((person . ((name . "Joe"))))
"\"{{person.name}}\" == \"{{#person}}{{name}}{{/person}}\""
"\"Joe\" == \"Joe\"")
(test-mustache "Dotted Names - Triple Mustache Interpolation"
'((person . ((name . "Joe"))))
"\"{{{person.name}}}\" == \"{{#person}}{{{name}}}{{/person}}\""
"\"Joe\" == \"Joe\"")
(test-mustache "Dotted Names - Ampersand Interpolation"
'((person . ((name . "Joe"))))
"\"{{&person.name}}\" == \"{{#person}}{{&name}}{{/person}}\""
"\"Joe\" == \"Joe\"")
(test-mustache "Dotted Names - Arbitrary Depth"
'((a . ((b . ((c . ((d . ((e . ((name . "Phil"))))))))))))
"\"{{a.b.c.d.e.name}}\" == \"Phil\""
"\"Phil\" == \"Phil\"")
(test-mustache "Dotted Names - Broken Chains"
'((a . ()))
"\"{{a.b.c}}\" == \"\""
"\"\" == \"\"")
(test-mustache "Dotted Names - Broken Chain Resolution"
'((a . ((b . ())))
(c . ((name . "Jim"))))
"\"{{a.b.c.name}}\" == \"\""
"\"\" == \"\"")
(test-mustache "Dotted Names - Initial Resolution"
'((a . ((b . ((c . ((d . ((e . ((name . "Phil")))))))))))
(b . ((c . ((d . ((e . ((name . "Wrong"))))))))))
"\"{{#a}}{{b.c.d.e.name}}{{/a}}\" == \"Phil\""
"\"Phil\" == \"Phil\"")
(test-mustache "Dotted Names - Context Precedence"
'((a . ((b . ())))
(b . ((c . "ERROR"))))
"{{#a}}{{b.c}}{{/a}}"
"")
(test-mustache "Implicit Iterators - Basic Interpolation"
"world"
"Hello, {{.}}!"
"Hello, world!")
(test-mustache "Implicit Iterators - HTML Escaping"
"& \" < >"
"These characters should be HTML escaped: {{.}}"
"These characters should be HTML escaped: &amp; &quot; &lt; &gt;")
(test-mustache "Implicit Iterators - Triple Mustache"
"& \" < >"
"These characters should not be HTML escaped: {{{.}}}"
"These characters should not be HTML escaped: & \" < >")
(test-mustache "Implicit Iterators - Ampersand"
"& \" < >"
"These characters should not be HTML escaped: {{&.}}"
"These characters should not be HTML escaped: & \" < >")
(test-mustache "Implicit Iterators - Basic Integer Interpolation"
85
"\"{{.}} miles an hour!\""
"\"85 miles an hour!\"")
(test-mustache "Interpolation - Surrounding Whitespace"
'((string . "---"))
"| {{string}} |"
"| --- |")
(test-mustache "Triple Mustache - Surrounding Whitespace"
'((string . "---"))
"| {{{string}}} |"
"| --- |")
(test-mustache "Ampersand - Surrounding Whitespace"
'((string . "---"))
"| {{&string}} |"
"| --- |")
(test-mustache "Interpolation - Standalone"
'((string . "---"))
" {{string}}\n"
" ---\n")
(test-mustache "Triple Mustache - Standalone"
'((string . "---"))
" {{{string}}}\n"
" ---\n")
(test-mustache "Ampersand - Standalone"
'((string . "---"))
" {{&string}}\n"
" ---\n")
(test-mustache "Interpolation With Padding"
'((string . "---"))
"|{{ string }}|"
"|---|")
(test-mustache "Triple Mustache With Padding"
'((string . "---"))
"|{{{ string }}}|"
"|---|")
(test-mustache "Ampersand With Padding"
'((string . "---"))
"|{{& string }}|"
"|---|"))

View File

@ -0,0 +1,147 @@
(define (run-tests/inverted)
(test-mustache "Falsey"
'((boolean . #f))
"\"{{^boolean}}This should be rendered.{{/boolean}}\""
"\"This should be rendered.\"")
(test-mustache "Truthy"
'((boolean . #t))
"\"{{^boolean}}This should not be rendered.{{/boolean}}\""
"\"\"")
;; "Null is falsey" test is skipped; no meaningful value for null
(test-mustache "Context"
'((context . ((name . "Joe"))))
"\"{{^context}}Hi {{name}}.{{/context}}\""
"\"\"")
(test-mustache "List"
'(list . #(((n . 1))
((n . 2))
((n . 3))))
"\"{{^list}}{{n}}{{/list}}\""
"\"\"")
(test-mustache "Empty List"
'(list . #())
"\"{{^list}}Yay lists!{{/list}}\""
"\"Yay lists!\"")
(test-mustache "Doubled"
'((bool . #f) (two . "second"))
"
{{^bool}}
* first
{{/bool}}
* {{two}}
{{^bool}}
* third
{{/bool}}
"
"
* first
* second
* third
")
(test-mustache "Nested (Falsey)"
'((bool . #f))
"| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"
"| A B C D E |")
(test-mustache "Nested (Truthy)"
'((bool . #t))
"| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"
"| A E |")
(test-mustache "Context Misses"
'(())
"[{{^missing}}Cannot find key 'missing'!{{/missing}}]"
"[Cannot find key 'missing'!]")
(test-mustache "Dotted Names - Truthy"
'((a . ((b . ((c . #t))))))
"\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"\""
"\"\" == \"\"")
(test-mustache "Dotted Names - Falsey"
'((a . ((b . ((c . #f))))))
"\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"Not Here\""
"\"Not Here\" == \"Not Here\"")
(test-mustache "Dotted Names - Broken Chains"
'((a . ()))
"\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"Not Here\""
"\"Not Here\" == \"Not Here\"")
(test-mustache "Surrounding Whitespace"
'((boolean . #f))
" | {{^boolean}}\t|\t{{/boolean}} | \n"
" | \t|\t | \n")
(test-mustache "Internal Whitespace"
'((boolean . #f))
" | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n"
" | \n | \n")
(test-mustache "Indented Inline Sections"
'((boolean . #f))
" {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n"
" NO\n WAY\n")
(test-mustache "Standalone Lines"
'((boolean . #f))
"
|
| This Is
{{^boolean}}
|
{{/boolean}}
| A Line
"
"
|
| This Is
|
| A Line
")
(test-mustache "Standalone Indented Lines"
'((boolean . #f))
"
|
| This Is
{{^boolean}}
|
{{/boolean}}
| A Line
"
"
|
| This Is
|
| A Line
")
(test-mustache "Standalone Line Endings"
'((boolean . #f))
"|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|"
"|\r\n|")
(test-mustache "Standalone Without Previous Line"
'((boolean . #f))
" {{^boolean}}\n^{{/boolean}}\n/"
"^\n/")
(test-mustache "Standalone Without Newline"
'((boolean . #f))
"^{{^boolean}}\n/\n {{/boolean}}"
"^\n/\n")
(test-mustache "Padding"
'((boolean . #f))
"|{{^ boolean }}={{/ boolean }}|"
"|=|"))

View File

@ -0,0 +1,46 @@
(define (run-tests/partials)
(test-mustache "Basic Behavior"
'()
'(("text" . "from partial"))
"\"{{>text}}\""
"\"from partial\"")
(test-mustache "Failed Lookup"
'()
'()
"\"{{>text}}\""
"\"\"")
(test-mustache "Context"
'((text . "content"))
'(("partial" . "*{{text}}*"))
"\"{{>partial}}\""
"\"*content*\"")
(test-mustache "Recursion"
'((content . "X")
(nodes . #(((content . "Y")
(nodes . #())))))
'(("node" . "{{content}}<{{#nodes}}{{>node}}{{/nodes}}>"))
"{{>node}}"
"X<Y<>>")
(test-mustache "Surrounding Whitespace"
'()
'(("partial" . "\t|\t"))
"| {{>partial}} |"
"| \t|\t |")
(test-mustache "Inline Indentation"
'((data . "|"))
'(("partial" . ">\n>"))
" {{data}} {{> partial}}\n"
" | >\n>\n")
(test-mustache "Standalone Line Endings"
'()
'(("partial" . ">"))
"|\r\n{{>partial}}\r\n|"
"|\r\n>|"))

View File

@ -0,0 +1,84 @@
(define (run-tests/sections)
(test-mustache "Truthy"
'((boolean . #t))
"\"{{#boolean}}This should be rendered.{{/boolean}}\""
"\"This should be rendered.\"")
(test-mustache "Falsey"
'((boolean . #f))
"\"{{#boolean}}This should not be rendered.{{/boolean}}\""
"\"\"")
;; "Null is falsey" test is skipped; no meaningful value for null
(test-mustache "Context"
'((context . ((name . "Joe"))))
"\"{{#context}}Hi {{name}}.{{/context}}\""
"\"Hi Joe.\"")
(test-mustache "Parent contexts"
'((a . "foo")
(b . "wrong")
(sec . ((b . "bar")))
(c . ((d . "baz"))))
"\"{{#sec}}{{a}}, {{b}}, {{c.d}}{{/sec}}\""
"\"foo, bar, baz\"")
(test-mustache "Variable test"
'((foo . "bar"))
"\"{{#foo}}{{.}} is {{foo}}{{/foo}}\""
"\"bar is bar\"")
(test-mustache "List Contexts"
'((tops . #(((tname . ((upper . "A")
(lower . "a")))
(middles . #(((mname . "1")
(bottoms . #(((bname . "x"))
((bname . "y")))))))))))
"{{#tops}}{{#middles}}{{tname.lower}}{{mname}}.{{#bottoms}}{{tname.upper}}{{mname}}{{bname}}.{{/bottoms}}{{/middles}}{{/tops}}"
"a1.A1x.A1y.")
(test-mustache "Deeply Nested Contexts"
'((a . ((one . 1)))
(b . ((two . 2)))
(c . ((three . 3)
(d . ((four . 4)
(five . 5))))))
"
{{#a}}
{{one}}
{{#b}}
{{one}}{{two}}{{one}}
{{#c}}
{{one}}{{two}}{{three}}{{two}}{{one}}
{{#d}}
{{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}
{{#five}}
{{one}}{{two}}{{three}}{{four}}{{five}}{{four}}{{three}}{{two}}{{one}}
{{one}}{{two}}{{three}}{{four}}{{.}}6{{.}}{{four}}{{three}}{{two}}{{one}}
{{one}}{{two}}{{three}}{{four}}{{five}}{{four}}{{three}}{{two}}{{one}}
{{/five}}
{{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}
{{/d}}
{{one}}{{two}}{{three}}{{two}}{{one}}
{{/c}}
{{one}}{{two}}{{one}}
{{/b}}
{{one}}
{{/a}}
"
"
1
121
12321
1234321
123454321
12345654321
123454321
1234321
12321
121
1
"
))

27
snow/arvyy/mustache.sld Normal file
View File

@ -0,0 +1,27 @@
(define-library
(arvyy mustache)
(import (scheme base)
(scheme case-lambda)
(scheme write)
(arvyy mustache lookup)
(arvyy mustache collection)
(prefix (arvyy mustache executor) executor-)
(arvyy mustache parser)
(arvyy mustache tokenizer)
(srfi 1))
(export
execute
compile
current-lookup
current-collection
current-writer
compose-lookups
alist-lookup
collection
compose-collections
vector-collection
list-collection
stream-collection)
(include "mustache-impl.scm"))

View File

@ -0,0 +1,64 @@
(define-library
(arvyy mustache collection)
(import (scheme base)
(srfi 41))
(export
collection
collection-pred-proc
collection-empty?-proc
collection-for-each-proc
compose-collections
vector-collection
stream-collection
list-collection)
(begin
(define-record-type <collection>
(collection pred-proc empty?-proc for-each-proc)
collection?
(pred-proc collection-pred-proc)
(empty?-proc collection-empty?-proc)
(for-each-proc collection-for-each-proc))
(define vector-collection
(collection vector?
(lambda (v) (= 0 (vector-length v)))
vector-for-each))
(define list-collection
(collection list?
null?
for-each))
(define stream-collection
(collection stream?
stream-null?
stream-for-each))
(define (compose-collections . collections)
(define (find-collection object)
(let loop ((collections collections))
(cond
((null? collections)
#f)
(((collection-pred-proc (car collections)) object)
(car collections))
(else (loop (cdr collections))))))
(collection
;; predicate
(lambda (object)
(cond
((find-collection object) #t)
(else #f)))
;; empty proc
(lambda (object)
(cond
((find-collection object) => (lambda (c) ((collection-empty?-proc c) object)))
(else (error "Collection not found"))))
;; for-each proc
(lambda (proc object)
(cond
((find-collection object) => (lambda (c) ((collection-for-each-proc c) proc object)))
(else (error "Collection not found"))))))))

View File

@ -0,0 +1,94 @@
(define (html-escape writer value)
(define str-value
(let ((out (open-output-string)))
(writer value out)
(get-output-string out)))
(define out (open-output-string))
(string-for-each
(lambda (char)
(case char
((#\&) (write-string "&amp;" out))
((#\<) (write-string "&lt;" out))
((#\>) (write-string "&gt;" out))
((#\") (write-string "&quot;" out))
(else (write-char char out))))
str-value)
(get-output-string out))
(define (lookup-in-stack-single name objs-stack lookup)
(let loop ((objs objs-stack))
(if (null? objs)
(values objs #f)
(lookup (car objs)
name
(lambda (value) (values objs value))
(lambda () (loop (cdr objs)))))))
(define (lookup-in-stack name-lst objs-stack lookup)
(define-values (objs value)
(lookup-in-stack-single (car name-lst) objs-stack lookup))
(cond
((not value) #f)
((null? (cdr name-lst)) value)
(else (lookup-in-stack (cdr name-lst)
(list value)
lookup))))
(define (execute template objs-stack partials out lookup collection? collection-empty? collection-for-each writer)
(define (execute-h template indent objs-stack)
(for-each
(lambda (fragment)
(cond
((string? fragment)
(write-string fragment out))
((new-line? fragment)
(begin
(write-string (new-line-content fragment) out)
(write-string (make-string indent #\space) out)))
((interp? fragment)
(let* ((name (interp-ref fragment))
(value (if (equal? '(".") name)
(car objs-stack)
(lookup-in-stack name
objs-stack
lookup))))
(if (interp-escape? fragment)
(write-string (html-escape writer value) out)
(writer value out))))
((section? fragment)
(let ((value (lookup-in-stack (section-ref fragment)
objs-stack
lookup))
(inner-template (section-content fragment)))
(cond
((not value)
(when (section-invert? fragment)
(execute-h inner-template indent objs-stack)))
((not (collection? value))
(unless (section-invert? fragment)
(execute-h inner-template indent (cons value objs-stack))))
(else
(if (section-invert? fragment)
(when (collection-empty? value)
(execute-h inner-template indent objs-stack))
(collection-for-each
(lambda (el)
(execute-h inner-template indent (cons el objs-stack)))
value))))))
((partial? fragment)
(let ()
(define partial-tpl
(cond
((assoc (partial-name fragment) partials) => cdr)
(else #f)))
(when partial-tpl
(execute-h partial-tpl
(+ indent (partial-indent fragment))
objs-stack) )))
(else (error "Unknown fragment"))))
template))
(execute-h template 0 objs-stack))

View File

@ -0,0 +1,6 @@
(define-library
(arvyy mustache executor)
(import (scheme base)
(arvyy mustache parser))
(export execute)
(include "executor-impl.scm"))

View File

@ -0,0 +1,27 @@
(define-library
(arvyy mustache lookup)
(import (scheme base))
(export
compose-lookups
alist-lookup)
(begin
(define (compose-lookups . lookups)
(lambda (obj name found not-found)
(let loop ((lookups lookups))
(if (null? lookups)
(not-found)
(let ((l (car lookups)))
(l obj name found (lambda ()
(loop (cdr lookups)))))))))
(define (alist-lookup obj name found not-found)
(define key (string->symbol name))
(define alist? (and (list? obj)
(or (null? obj)
(pair? (car obj)))))
(if alist?
(cond
((assoc key obj) => (lambda (pair) (found (cdr pair))))
(else (not-found)))
(not-found)))))

View File

@ -0,0 +1,296 @@
(define-record-type <interp>
(interp ref escape?)
interp?
(ref interp-ref)
(escape? interp-escape?) ;; should html be escaped
)
(define-record-type <section>
(section ref invert? content raw-content)
section?
(ref section-ref)
(invert? section-invert?) ;; normal section if false, {{^ section if true
(content section-content) ;; compiled inner content
(raw-content section-raw-content) ;; uncompiled inner content as a string; used for lambdas
)
(define-record-type <partial>
(partial name indent)
partial?
(name partial-name)
(indent partial-indent))
(define-record-type <newline>
(new-line content)
new-line?
(content new-line-content))
(define (parse tokens)
(let* ((tokens (replace-standalone tokens))
(tokens (remove-non-visible tokens))
(tokens (convert-string-tokens tokens))
(tokens (parse-interp+sections tokens)))
tokens))
(define (tpl->string tokens)
(define (->string item out)
(cond
((string? item) (write-string item out))
((new-line? item) (write-string (new-line-content item) out))
((section? item)
(let ((tagname (list->tagname (section-ref item))))
(write-string (if (section-invert? item) "{{^" "{{#") out)
(write-string tagname out)
(write-string "}}" out)
(for-each
(lambda (item*)
(->string item* out))
(section-content item))
(write-string "{{/" out)
(write-string tagname out)
(write-string "}}" out)))
((interp? item)
(let ((tagname (list->tagname (interp-ref item))))
(write-string (if (interp-escape? item) "{{" "{{&") out)
(write-string tagname out)
(write-string "}}" out)))))
(define out (open-output-string))
(for-each
(lambda (item) (->string item out))
tokens)
(get-output-string out))
;;TODO remove this
(define (debug-tokens tokens)
(for-each
(lambda (t)
(cond
((token-str? t) (display (string-append "#<<token-str> " (token-str-content t) "> ")))
((token-nl? t) (display "#<<token-nl>> "))
((token-section-open? t) (display (string-append "#<<token-open> " (token-section-open-tag t) "> ")))
((token-section-close? t) (display "#<<token-close>> "))
((token-ws? t) (display (string-append "#<<token-ws> " (number->string (token-ws-count t)) "> ")))
((token-interp? t) (display (string-append "#<<token-interp> " (token-interp-tag t) "> ")))
(else (display t))))
tokens
)
)
(define (standalone/remove? token)
(or (token-comment? token)
(token-delimchager? token)))
(define (standalone/trim? token)
(or (token-section-open? token)
(token-section-close? token)))
(define (replace-standalone tokens)
(let loop ((tokens tokens)
(result/inv '())
(first #t))
(cond
((null? tokens) (reverse result/inv))
((and first
(or (match-follows tokens standalone/remove? token-ws? token-nl?)
(match-follows tokens standalone/remove? token-nl?)
(match-follows tokens token-ws? standalone/remove? token-ws? token-nl?)
(match-follows tokens token-ws? standalone/remove? token-nl?))) =>
(lambda (tokens*)
(loop tokens*
result/inv
#t)))
((and first
(or (match-follows tokens token-ws? standalone/remove? token-ws? eof-object?)
(match-follows tokens token-ws? standalone/remove? eof-object?)
(match-follows tokens standalone/remove? token-ws? eof-object?)
(match-follows tokens standalone/remove? eof-object?))) =>
(lambda (tokens*)
(loop '()
result/inv
#t)))
((and first
(or (match-follows tokens token-ws? standalone/trim? token-ws? token-nl?)
(match-follows tokens token-ws? standalone/trim? token-nl?)
(match-follows tokens token-ws? standalone/trim? token-ws? eof-object?)
(match-follows tokens token-ws? standalone/trim? eof-object?))) =>
(lambda (tokens*)
(loop tokens*
(append (list (cadr tokens))
result/inv)
#t)))
((and first
(or (match-follows tokens standalone/trim? token-ws? token-nl?)
(match-follows tokens standalone/trim? token-nl?)
(match-follows tokens standalone/trim? token-ws? eof-object?)
(match-follows tokens standalone/trim? eof-object?))) =>
(lambda (tokens*)
(loop tokens*
(append (list (car tokens))
result/inv)
#t)))
((and first
(or (match-follows tokens token-ws? token-partial? token-ws? token-nl?)
(match-follows tokens token-ws? token-partial? token-nl?)
(match-follows tokens token-ws? token-partial? token-ws? eof-object?)
(match-follows tokens token-ws? token-partial? eof-object?))) =>
(lambda (tokens*)
(loop tokens*
(append (list (partial (token-partial-tag (cadr tokens))
(token-ws-count (car tokens))))
result/inv)
#t)))
((and first
(or (match-follows tokens token-partial? token-ws? token-nl?)
(match-follows tokens token-partial? token-nl?)
(match-follows tokens token-partial? token-ws? eof-object?)
(match-follows tokens token-partial? eof-object?))) =>
(lambda (tokens*)
(loop tokens*
(append (list (partial (token-partial-tag (car tokens))
0))
result/inv)
#t)))
((match-follows tokens token-partial?) => (lambda (tokens*)
(loop tokens*
(cons (partial (token-partial-tag (car tokens))
0)
result/inv)
#f)))
(else (loop (cdr tokens)
(cons (car tokens) result/inv)
(token-nl? (car tokens)))))))
(define (convert-string-tokens tokens)
(let loop ((tokens tokens)
(out #f)
(result/inv '()))
(cond
((null? tokens)
(let ((result-final/inv (if out
(cons (get-output-string out)
result/inv)
result/inv)))
(reverse result-final/inv)))
((or (token-str? (car tokens))
(token-ws? (car tokens)))
(let* ((token (car tokens))
(out* (if out
out
(open-output-string)))
(str (if (token-str? token)
(token-str-content token)
(make-string (token-ws-count token) #\space))))
(write-string str out*)
(loop (cdr tokens)
out*
result/inv)))
(else (let* ((token (car tokens))
(value (cond
((token-nl? token) (new-line (list->string (token-nl-chars token))))
(else token)))
(new-result/inv (if out
(cons (get-output-string out)
result/inv)
result/inv)))
(loop (cdr tokens)
#f
(cons value new-result/inv)))))))
(define (parse-interp+sections tokens)
(define (parse-interp+sections* tokens expected-close-tag)
(let loop ((tokens tokens)
(result/inv '()))
(cond
((null? tokens)
(if expected-close-tag
(error "Unexpected eof")
(values '() (reverse result/inv))))
((token-section-close? (car tokens))
(if (equal? expected-close-tag (token-section-close-tag (car tokens)))
(values (cdr tokens) (reverse result/inv))
(error "Closing token mismatch")))
((token-section-open? (car tokens))
(let* ((token (car tokens))
(tag (token-section-open-tag token))
(ref (tagname->list tag)))
(define-values (tokens* result*)
(parse-interp+sections* (cdr tokens)
tag))
(define value (section ref
(token-section-open-inverted? token)
result*
#f))
(loop tokens*
(cons value result/inv))))
((token-interp? (car tokens))
(let* ((token (car tokens))
(tag (token-interp-tag token))
(ref (tagname->list tag)))
(define value (interp ref (token-interp-escape? token)))
(loop (cdr tokens)
(cons value result/inv))))
(else (loop (cdr tokens)
(cons (car tokens)
result/inv))))))
(define-values (tokens* result)
(parse-interp+sections* tokens #f))
result)
(define (remove-non-visible tokens)
(filter
(lambda (token)
(not (or (token-comment? token)
(token-delimchager? token))))
tokens))
(define (match-follows in . preds)
(let loop ((in* in)
(preds* preds))
(cond
((null? preds*) in*)
((null? in*) (and (null? (cdr preds*))
(eq? (car preds*) eof-object?)
'()))
(((car preds*) (car in*))
(loop (cdr in*)
(cdr preds*)))
(else #f))))
(define (tagname->list str)
(define (prepend-part parts part)
(when (null? part)
(error "Trailing period in tag name"))
(cons (list->string (reverse part))
parts))
(if (equal? "." str)
'(".")
(let loop ((in (string->list str))
(parts '())
(part '()))
(cond
((null? in)
(reverse (prepend-part parts part)))
((char=? #\. (car in))
(loop (cdr in)
(prepend-part parts part)
'()))
(else (loop (cdr in)
parts
(cons (car in) part)))))))
(define (list->tagname lst)
(apply string-append
(cdr (apply append
(map
(lambda (el) (list "." el))
lst)))))

View File

@ -0,0 +1,14 @@
(define-library
(arvyy mustache parser)
(import (scheme base)
(scheme write)
(scheme cxr)
(arvyy mustache tokenizer)
(srfi 1))
(export
parse
interp? interp-ref interp-escape?
section? section-ref section-invert? section-content section-raw-content
partial? partial-name partial-indent
new-line? new-line-content)
(include "parser-impl.scm"))

View File

@ -0,0 +1,237 @@
(define-record-type <token-ws>
(token-ws count)
token-ws?
(count token-ws-count))
(define-record-type <token-nl>
(token-nl chars)
token-nl?
(chars token-nl-chars))
(define-record-type <token-comment>
(token-comment)
token-comment?)
(define-record-type <token-str>
(token-str content)
token-str?
(content token-str-content))
(define-record-type <token-delimchanger>
(token-delimchager open close)
token-delimchager?
(open token-delimchager-open)
(close token-delimchager-close))
(define-record-type <token-interp>
(token-interp tag escape?)
token-interp?
(tag token-interp-tag)
(escape? token-interp-escape?))
(define-record-type <token-section-open>
(token-section-open tag inverted?)
token-section-open?
(tag token-section-open-tag)
(inverted? token-section-open-inverted?))
(define-record-type <token-section-close>
(token-section-close tag)
token-section-close?
(tag token-section-close-tag))
(define-record-type <token-partial>
(token-partial tag)
token-partial?
(tag token-partial-tag))
(define (read-tokens str)
(let loop ((in (string->list str))
(ws-count 0)
(str-value '())
(open-delim '(#\{ #\{))
(close-delim '(#\} #\}))
(result/inv '()))
(define (resolve-ws/str)
(cond
;; unflushed ws and str info
((and (not (null? str-value))
(> ws-count 0))
(append (list (token-ws ws-count)
(token-str (list->string (reverse str-value))))
result/inv))
;; unflushed str info
((not (null? str-value))
(cons (token-str (list->string (reverse str-value)))
result/inv))
;; unflushed ws info
((> ws-count 0)
(cons (token-ws ws-count)
result/inv))
;; no unflushed info
(else result/inv)))
;; handle when in is null; ie final function return
(define (return)
(define final-result/inv (resolve-ws/str))
(reverse final-result/inv))
;; handle after tag read
(define (continue-after-tag in token)
(loop
in
0
'()
open-delim
close-delim
(cons token (resolve-ws/str))))
(define (process-interp in)
(define-values (in* tag)
(read-tag in close-delim))
(continue-after-tag in* (token-interp tag #t)))
(define (process-triple-mustache in)
(define-values (in* tag)
(read-tag in '(#\} #\} #\})))
(continue-after-tag in* (token-interp tag #f)))
(define (process-ampersand in)
(define-values (in* tag)
(read-tag in close-delim))
(continue-after-tag in* (token-interp tag #f)))
(define (process-inverted in)
(define-values (in* tag)
(read-tag in close-delim))
(continue-after-tag in* (token-section-open tag #t)))
(define (process-section in)
(define-values (in* tag)
(read-tag in close-delim))
(continue-after-tag in* (token-section-open tag #f)))
(define (process-close in)
(define-values (in* tag)
(read-tag in close-delim))
(continue-after-tag in* (token-section-close tag)))
(define (process-partial in)
(define-values (in* tag)
(read-tag in close-delim))
(continue-after-tag in* (token-partial tag)))
(define (process-comment in)
(let loop* ((in in))
(cond
((null? in) (error "Unexpected EOF"))
((match-follows in close-delim) => (lambda (in*)
(continue-after-tag in* (token-comment))))
(else (loop* (cdr in))))))
(define (process-delim-change in)
(let*-values (((in new-open) (read-tag in #f))
((in new-close) (read-tag in (cons #\= close-delim))))
(loop in
0
'()
(string->list new-open)
(string->list new-close)
(cons (token-delimchager new-open new-close)
(resolve-ws/str)))))
(define (process-open-delim in*)
(cond
((match-follows in* '(#\&)) => process-ampersand)
((match-follows in* '(#\^)) => process-inverted)
((match-follows in* '(#\#)) => process-section)
((match-follows in* '(#\/)) => process-close)
((match-follows in* '(#\>)) => process-partial)
((match-follows in* '(#\=)) => process-delim-change)
((match-follows in* '(#\!)) => process-comment)
(else (process-interp in*))))
(define (process-space in*)
(loop in*
(+ 1 ws-count)
str-value
open-delim
close-delim
result/inv))
(define (process-eol in* chars)
(loop in*
0
'()
open-delim
close-delim
(cons (token-nl chars)
(resolve-ws/str))))
(define (process-nl in*)
(process-eol in* '(#\newline)))
(define (process-crnl in*)
(process-eol in* '(#\return #\newline)))
(define (process-char)
(loop (cdr in)
0
(append (list (car in))
(make-list ws-count #\space)
str-value)
open-delim
close-delim
result/inv))
;; loop handler
(cond
((null? in) (return))
((match-follows in '(#\{ #\{ #\{)) => process-triple-mustache)
((match-follows in open-delim) => process-open-delim)
((match-follows in '(#\space)) => process-space)
((match-follows in '(#\newline)) => process-nl)
((match-follows in '(#\return #\newline)) => process-crnl)
(else (process-char)))))
(define (match-follows in chars)
(let loop ((in* in)
(chars* chars))
(cond
((null? chars*) in*)
((null? in*) #f)
((char=? (car in*) (car chars*))
(loop (cdr in*)
(cdr chars*)))
(else #f))))
(define (skip-spaces in)
(cond
((null? in) '())
((char=? (car in) #\space) (skip-spaces (cdr in)))
(else in)))
(define (read-tag in close-delim)
(define-values
(tag in*)
(let loop ((in (skip-spaces in))
(result '()))
(define (return)
(values (list->string (reverse result))
in))
(cond
((null? in) (error "Unexpected EOF"))
((char=? (car in) #\space) (return))
((and close-delim (match-follows in close-delim))
(return))
(else (loop (cdr in)
(cons (car in) result))))))
(cond
((not close-delim) (values in* tag))
((match-follows (skip-spaces in*) close-delim) => (lambda (in**)
(values in** tag)))
(else (error "Bad tag"))))

View File

@ -0,0 +1,15 @@
(define-library
(arvyy mustache tokenizer)
(import (scheme base))
(export
read-tokens
token-ws? token-ws-count
token-nl token-nl? token-nl-chars
token-comment?
token-str? token-str-content
token-delimchager? token-delimchager-open token-delimchager-close
token-interp? token-interp-tag token-interp-escape?
token-section-open? token-section-open-tag token-section-open-inverted?
token-section-close? token-section-close-tag
token-partial? token-partial-tag)
(include "tokenizer-impl.scm"))

34
templates/Jenkinsfile vendored Normal file
View File

@ -0,0 +1,34 @@
pipeline {
agent {
dockerfile {
filename 'dockerfiles/jenkins'
dir '.'
args '--privileged -v /var/run/docker.sock:/var/run/docker.sock'
}
}
options {
buildDiscarder(logRotator(numToKeepStr: '10', artifactNumToKeepStr: '10'))
}
stages {
{{#script-implementations}}
stage('{{.}}') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME={{.}} test-script-docker'
}
}
}
{{/script-implementations}}
{{#compiler-implementations}}
stage('{{.}}') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh 'make SCHEME={{.}} test-compile-docker'
}
}
}
{{/compiler-implementations}}
}
}