diff --git a/.buildinfo b/.buildinfo index f6cda34..5f63159 100644 --- a/.buildinfo +++ b/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 7d2843c3acac22679ddd25e80bc4a6ee +config: 36e6e861293d1ba58caa04777c9a423d tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/about.doctree b/.doctrees/about.doctree new file mode 100644 index 0000000..8da9ff3 Binary files /dev/null and b/.doctrees/about.doctree differ diff --git a/.doctrees/code-of-conduct.doctree b/.doctrees/code-of-conduct.doctree new file mode 100644 index 0000000..8e7c178 Binary files /dev/null and b/.doctrees/code-of-conduct.doctree differ diff --git a/.doctrees/contents/about.doctree b/.doctrees/contents/about.doctree deleted file mode 100644 index c81a646..0000000 Binary files a/.doctrees/contents/about.doctree and /dev/null differ diff --git a/.doctrees/contents/code-of-conduct.doctree b/.doctrees/contents/code-of-conduct.doctree deleted file mode 100644 index fa4cb29..0000000 Binary files a/.doctrees/contents/code-of-conduct.doctree and /dev/null differ diff --git a/.doctrees/contents/contact.doctree b/.doctrees/contents/contact.doctree deleted file mode 100644 index f7df4bb..0000000 Binary files a/.doctrees/contents/contact.doctree and /dev/null differ diff --git a/.doctrees/contents/contribute.doctree b/.doctrees/contents/contribute.doctree deleted file mode 100644 index 380777f..0000000 Binary files a/.doctrees/contents/contribute.doctree and /dev/null differ diff --git a/.doctrees/contents/contribute/changelog.doctree b/.doctrees/contents/contribute/changelog.doctree deleted file mode 100644 index b01352d..0000000 Binary files a/.doctrees/contents/contribute/changelog.doctree and /dev/null differ diff --git a/.doctrees/contents/contribute/contributors.doctree b/.doctrees/contents/contribute/contributors.doctree deleted file mode 100644 index 0a19c29..0000000 Binary files a/.doctrees/contents/contribute/contributors.doctree and /dev/null differ diff --git a/.doctrees/contents/contribute/credit-for-contributions.doctree b/.doctrees/contents/contribute/credit-for-contributions.doctree deleted file mode 100644 index a9cd0b1..0000000 Binary files a/.doctrees/contents/contribute/credit-for-contributions.doctree and /dev/null differ diff --git a/.doctrees/contents/contribute/how-to-contribute.doctree b/.doctrees/contents/contribute/how-to-contribute.doctree deleted file mode 100644 index 42123e9..0000000 Binary files a/.doctrees/contents/contribute/how-to-contribute.doctree and /dev/null differ diff --git a/.doctrees/contents/contribute/style-guide.doctree b/.doctrees/contents/contribute/style-guide.doctree deleted file mode 100644 index cf3c23c..0000000 Binary files a/.doctrees/contents/contribute/style-guide.doctree and /dev/null differ diff --git a/.doctrees/contents/data-hazards.doctree b/.doctrees/contents/data-hazards.doctree index 887d969..cc98adf 100644 Binary files a/.doctrees/contents/data-hazards.doctree and b/.doctrees/contents/data-hazards.doctree differ diff --git a/.doctrees/contents/events.doctree b/.doctrees/contents/events.doctree deleted file mode 100644 index 32f7553..0000000 Binary files a/.doctrees/contents/events.doctree and /dev/null differ diff --git a/.doctrees/contents/events/2021-09-21_workshop.doctree b/.doctrees/contents/events/2021-09-21_workshop.doctree deleted file mode 100644 index 06a2388..0000000 Binary files a/.doctrees/contents/events/2021-09-21_workshop.doctree and /dev/null differ diff --git a/.doctrees/contents/events/bristol-tech-fest.doctree b/.doctrees/contents/events/bristol-tech-fest.doctree deleted file mode 100644 index 67a89a3..0000000 Binary files a/.doctrees/contents/events/bristol-tech-fest.doctree and /dev/null differ diff --git a/.doctrees/contents/events/coworking.doctree b/.doctrees/contents/events/coworking.doctree deleted file mode 100644 index e9f7db7..0000000 Binary files a/.doctrees/contents/events/coworking.doctree and /dev/null differ diff --git a/.doctrees/contents/events/jgi-showcase-events.doctree b/.doctrees/contents/events/jgi-showcase-events.doctree deleted file mode 100644 index 4b61124..0000000 Binary files a/.doctrees/contents/events/jgi-showcase-events.doctree and /dev/null differ diff --git a/.doctrees/contents/events/mozfest2022.doctree b/.doctrees/contents/events/mozfest2022.doctree deleted file mode 100644 index 5aeceab..0000000 Binary files a/.doctrees/contents/events/mozfest2022.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/automates-decision-making.doctree b/.doctrees/contents/hazards/automates-decision-making.doctree deleted file mode 100644 index 33ef2ca..0000000 Binary files a/.doctrees/contents/hazards/automates-decision-making.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/danger-of-misuse.doctree b/.doctrees/contents/hazards/danger-of-misuse.doctree deleted file mode 100644 index c81a8ae..0000000 Binary files a/.doctrees/contents/hazards/danger-of-misuse.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/difficult-to-understand.doctree b/.doctrees/contents/hazards/difficult-to-understand.doctree deleted file mode 100644 index 46bb699..0000000 Binary files a/.doctrees/contents/hazards/difficult-to-understand.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/direct-harm.doctree b/.doctrees/contents/hazards/direct-harm.doctree deleted file mode 100644 index 7f3046a..0000000 Binary files a/.doctrees/contents/hazards/direct-harm.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/general-hazard.doctree b/.doctrees/contents/hazards/general-hazard.doctree deleted file mode 100644 index 0e104cd..0000000 Binary files a/.doctrees/contents/hazards/general-hazard.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/hazard-template.doctree b/.doctrees/contents/hazards/hazard-template.doctree deleted file mode 100644 index b8fdaae..0000000 Binary files a/.doctrees/contents/hazards/hazard-template.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/high-environmental-cost.doctree b/.doctrees/contents/hazards/high-environmental-cost.doctree deleted file mode 100644 index 029f64e..0000000 Binary files a/.doctrees/contents/hazards/high-environmental-cost.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/lacks-community-involvement.doctree b/.doctrees/contents/hazards/lacks-community-involvement.doctree deleted file mode 100644 index a6342eb..0000000 Binary files a/.doctrees/contents/hazards/lacks-community-involvement.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/lacks-informed-consent.doctree b/.doctrees/contents/hazards/lacks-informed-consent.doctree deleted file mode 100644 index 1e6d678..0000000 Binary files a/.doctrees/contents/hazards/lacks-informed-consent.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/ranks-classifies.doctree b/.doctrees/contents/hazards/ranks-classifies.doctree deleted file mode 100644 index e0159aa..0000000 Binary files a/.doctrees/contents/hazards/ranks-classifies.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/reinforces-biases.doctree b/.doctrees/contents/hazards/reinforces-biases.doctree deleted file mode 100644 index 571ef18..0000000 Binary files a/.doctrees/contents/hazards/reinforces-biases.doctree and /dev/null differ diff --git a/.doctrees/contents/hazards/risk-to-privacy.doctree b/.doctrees/contents/hazards/risk-to-privacy.doctree deleted file mode 100644 index d6638fb..0000000 Binary files a/.doctrees/contents/hazards/risk-to-privacy.doctree and /dev/null differ diff --git a/.doctrees/contents/materials.doctree b/.doctrees/contents/materials.doctree deleted file mode 100644 index d5cba8f..0000000 Binary files a/.doctrees/contents/materials.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/examples.doctree b/.doctrees/contents/materials/examples.doctree deleted file mode 100644 index e4328a4..0000000 Binary files a/.doctrees/contents/materials/examples.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/misc/geno_to_pheno_example.doctree b/.doctrees/contents/materials/misc/geno_to_pheno_example.doctree deleted file mode 100644 index f9fe0d9..0000000 Binary files a/.doctrees/contents/materials/misc/geno_to_pheno_example.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/misc/proposal.doctree b/.doctrees/contents/materials/misc/proposal.doctree deleted file mode 100644 index 69cdaed..0000000 Binary files a/.doctrees/contents/materials/misc/proposal.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/misc/workshop-21092021.doctree b/.doctrees/contents/materials/misc/workshop-21092021.doctree deleted file mode 100644 index 506aeda..0000000 Binary files a/.doctrees/contents/materials/misc/workshop-21092021.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/presenting.doctree b/.doctrees/contents/materials/presenting.doctree deleted file mode 100644 index 016fe2b..0000000 Binary files a/.doctrees/contents/materials/presenting.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/seedcorn.doctree b/.doctrees/contents/materials/seedcorn.doctree deleted file mode 100644 index fc9c412..0000000 Binary files a/.doctrees/contents/materials/seedcorn.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/self-assessment.doctree b/.doctrees/contents/materials/self-assessment.doctree deleted file mode 100644 index 4912a4c..0000000 Binary files a/.doctrees/contents/materials/self-assessment.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/teaching.doctree b/.doctrees/contents/materials/teaching.doctree deleted file mode 100644 index 12130ea..0000000 Binary files a/.doctrees/contents/materials/teaching.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/teaching/students.doctree b/.doctrees/contents/materials/teaching/students.doctree deleted file mode 100644 index 9864f37..0000000 Binary files a/.doctrees/contents/materials/teaching/students.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/workshop.doctree b/.doctrees/contents/materials/workshop.doctree deleted file mode 100644 index b18dd4e..0000000 Binary files a/.doctrees/contents/materials/workshop.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/workshop/audience.doctree b/.doctrees/contents/materials/workshop/audience.doctree deleted file mode 100644 index 6af3493..0000000 Binary files a/.doctrees/contents/materials/workshop/audience.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/workshop/facilitating.doctree b/.doctrees/contents/materials/workshop/facilitating.doctree deleted file mode 100644 index 2d661db..0000000 Binary files a/.doctrees/contents/materials/workshop/facilitating.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/workshop/feedback.doctree b/.doctrees/contents/materials/workshop/feedback.doctree deleted file mode 100644 index 700b662..0000000 Binary files a/.doctrees/contents/materials/workshop/feedback.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/workshop/project-owners.doctree b/.doctrees/contents/materials/workshop/project-owners.doctree deleted file mode 100644 index 04c7bb8..0000000 Binary files a/.doctrees/contents/materials/workshop/project-owners.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/workshop/setup.doctree b/.doctrees/contents/materials/workshop/setup.doctree deleted file mode 100644 index 7ce4484..0000000 Binary files a/.doctrees/contents/materials/workshop/setup.doctree and /dev/null differ diff --git a/.doctrees/contents/materials/workshop/structure.doctree b/.doctrees/contents/materials/workshop/structure.doctree deleted file mode 100644 index 0d2f7d5..0000000 Binary files a/.doctrees/contents/materials/workshop/structure.doctree and /dev/null differ diff --git a/.doctrees/contents/mitigation-resources.doctree b/.doctrees/contents/mitigation-resources.doctree deleted file mode 100644 index 6ac77be..0000000 Binary files a/.doctrees/contents/mitigation-resources.doctree and /dev/null differ diff --git a/.doctrees/contents/presenting/github-badge.doctree b/.doctrees/contents/presenting/github-badge.doctree deleted file mode 100644 index 4e67612..0000000 Binary files a/.doctrees/contents/presenting/github-badge.doctree and /dev/null differ diff --git a/.doctrees/contents/presenting/image-app.doctree b/.doctrees/contents/presenting/image-app.doctree deleted file mode 100644 index f2bb557..0000000 Binary files a/.doctrees/contents/presenting/image-app.doctree and /dev/null differ diff --git a/.doctrees/contribute.doctree b/.doctrees/contribute.doctree new file mode 100644 index 0000000..5446cb4 Binary files /dev/null and b/.doctrees/contribute.doctree differ diff --git a/.doctrees/contribute/contributors.doctree b/.doctrees/contribute/contributors.doctree new file mode 100644 index 0000000..a70e467 Binary files /dev/null and b/.doctrees/contribute/contributors.doctree differ diff --git a/.doctrees/contribute/credit-for-contributions.doctree b/.doctrees/contribute/credit-for-contributions.doctree new file mode 100644 index 0000000..382bec0 Binary files /dev/null and b/.doctrees/contribute/credit-for-contributions.doctree differ diff --git a/.doctrees/contribute/how-to-contribute.doctree b/.doctrees/contribute/how-to-contribute.doctree new file mode 100644 index 0000000..898a774 Binary files /dev/null and b/.doctrees/contribute/how-to-contribute.doctree differ diff --git a/.doctrees/contribute/style-guide.doctree b/.doctrees/contribute/style-guide.doctree new file mode 100644 index 0000000..c612442 Binary files /dev/null and b/.doctrees/contribute/style-guide.doctree differ diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle index f8a0e26..dedeb25 100644 Binary files a/.doctrees/environment.pickle and b/.doctrees/environment.pickle differ diff --git a/.doctrees/events.doctree b/.doctrees/events.doctree new file mode 100644 index 0000000..1a5d9ef Binary files /dev/null and b/.doctrees/events.doctree differ diff --git a/.doctrees/events/2021-09-21_workshop.doctree b/.doctrees/events/2021-09-21_workshop.doctree new file mode 100644 index 0000000..d548576 Binary files /dev/null and b/.doctrees/events/2021-09-21_workshop.doctree differ diff --git a/.doctrees/events/bristol-tech-fest.doctree b/.doctrees/events/bristol-tech-fest.doctree new file mode 100644 index 0000000..c16d2a4 Binary files /dev/null and b/.doctrees/events/bristol-tech-fest.doctree differ diff --git a/.doctrees/events/coworking.doctree b/.doctrees/events/coworking.doctree new file mode 100644 index 0000000..4038068 Binary files /dev/null and b/.doctrees/events/coworking.doctree differ diff --git a/.doctrees/events/jgi-showcase-events.doctree b/.doctrees/events/jgi-showcase-events.doctree new file mode 100644 index 0000000..1c116a4 Binary files /dev/null and b/.doctrees/events/jgi-showcase-events.doctree differ diff --git a/.doctrees/events/mozfest2022.doctree b/.doctrees/events/mozfest2022.doctree new file mode 100644 index 0000000..596a140 Binary files /dev/null and b/.doctrees/events/mozfest2022.doctree differ diff --git a/.doctrees/hazards/automates-decision-making.doctree b/.doctrees/hazards/automates-decision-making.doctree new file mode 100644 index 0000000..29ddb23 Binary files /dev/null and b/.doctrees/hazards/automates-decision-making.doctree differ diff --git a/.doctrees/hazards/danger-of-misuse.doctree b/.doctrees/hazards/danger-of-misuse.doctree new file mode 100644 index 0000000..0472712 Binary files /dev/null and b/.doctrees/hazards/danger-of-misuse.doctree differ diff --git a/.doctrees/hazards/difficult-to-understand.doctree b/.doctrees/hazards/difficult-to-understand.doctree new file mode 100644 index 0000000..12e69a8 Binary files /dev/null and b/.doctrees/hazards/difficult-to-understand.doctree differ diff --git a/.doctrees/hazards/direct-harm.doctree b/.doctrees/hazards/direct-harm.doctree new file mode 100644 index 0000000..79349bb Binary files /dev/null and b/.doctrees/hazards/direct-harm.doctree differ diff --git a/.doctrees/hazards/general-hazard.doctree b/.doctrees/hazards/general-hazard.doctree new file mode 100644 index 0000000..69f3cd3 Binary files /dev/null and b/.doctrees/hazards/general-hazard.doctree differ diff --git a/.doctrees/hazards/hazard-template.doctree b/.doctrees/hazards/hazard-template.doctree new file mode 100644 index 0000000..e2cba6e Binary files /dev/null and b/.doctrees/hazards/hazard-template.doctree differ diff --git a/.doctrees/hazards/high-environmental-cost.doctree b/.doctrees/hazards/high-environmental-cost.doctree new file mode 100644 index 0000000..7662ed1 Binary files /dev/null and b/.doctrees/hazards/high-environmental-cost.doctree differ diff --git a/.doctrees/hazards/lacks-community-involvement.doctree b/.doctrees/hazards/lacks-community-involvement.doctree new file mode 100644 index 0000000..e11b8e7 Binary files /dev/null and b/.doctrees/hazards/lacks-community-involvement.doctree differ diff --git a/.doctrees/hazards/lacks-informed-consent.doctree b/.doctrees/hazards/lacks-informed-consent.doctree new file mode 100644 index 0000000..5fceff2 Binary files /dev/null and b/.doctrees/hazards/lacks-informed-consent.doctree differ diff --git a/.doctrees/hazards/ranks-classifies.doctree b/.doctrees/hazards/ranks-classifies.doctree new file mode 100644 index 0000000..e202935 Binary files /dev/null and b/.doctrees/hazards/ranks-classifies.doctree differ diff --git a/.doctrees/hazards/reinforces-biases.doctree b/.doctrees/hazards/reinforces-biases.doctree new file mode 100644 index 0000000..b9e840e Binary files /dev/null and b/.doctrees/hazards/reinforces-biases.doctree differ diff --git a/.doctrees/hazards/risk-to-privacy.doctree b/.doctrees/hazards/risk-to-privacy.doctree new file mode 100644 index 0000000..940b921 Binary files /dev/null and b/.doctrees/hazards/risk-to-privacy.doctree differ diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree index 15a9d05..a4daf17 100644 Binary files a/.doctrees/index.doctree and b/.doctrees/index.doctree differ diff --git a/.doctrees/labels.doctree b/.doctrees/labels.doctree index 1221485..b245e42 100644 Binary files a/.doctrees/labels.doctree and b/.doctrees/labels.doctree differ diff --git a/.doctrees/materials.doctree b/.doctrees/materials.doctree new file mode 100644 index 0000000..50c8c78 Binary files /dev/null and b/.doctrees/materials.doctree differ diff --git a/.doctrees/materials/examples.doctree b/.doctrees/materials/examples.doctree new file mode 100644 index 0000000..7dc6d76 Binary files /dev/null and b/.doctrees/materials/examples.doctree differ diff --git a/.doctrees/materials/misc/geno_to_pheno_example.doctree b/.doctrees/materials/misc/geno_to_pheno_example.doctree new file mode 100644 index 0000000..f2af979 Binary files /dev/null and b/.doctrees/materials/misc/geno_to_pheno_example.doctree differ diff --git a/.doctrees/materials/misc/proposal.doctree b/.doctrees/materials/misc/proposal.doctree new file mode 100644 index 0000000..34ea1df Binary files /dev/null and b/.doctrees/materials/misc/proposal.doctree differ diff --git a/.doctrees/materials/misc/workshop-21092021.doctree b/.doctrees/materials/misc/workshop-21092021.doctree new file mode 100644 index 0000000..6d52b9b Binary files /dev/null and b/.doctrees/materials/misc/workshop-21092021.doctree differ diff --git a/.doctrees/materials/mitigation-resources.doctree b/.doctrees/materials/mitigation-resources.doctree new file mode 100644 index 0000000..a548cc7 Binary files /dev/null and b/.doctrees/materials/mitigation-resources.doctree differ diff --git a/.doctrees/materials/presenting.doctree b/.doctrees/materials/presenting.doctree new file mode 100644 index 0000000..542e229 Binary files /dev/null and b/.doctrees/materials/presenting.doctree differ diff --git a/.doctrees/materials/seedcorn.doctree b/.doctrees/materials/seedcorn.doctree new file mode 100644 index 0000000..b42835e Binary files /dev/null and b/.doctrees/materials/seedcorn.doctree differ diff --git a/.doctrees/materials/self-assessment.doctree b/.doctrees/materials/self-assessment.doctree new file mode 100644 index 0000000..83ac062 Binary files /dev/null and b/.doctrees/materials/self-assessment.doctree differ diff --git a/.doctrees/materials/teaching.doctree b/.doctrees/materials/teaching.doctree new file mode 100644 index 0000000..41102f9 Binary files /dev/null and b/.doctrees/materials/teaching.doctree differ diff --git a/.doctrees/materials/workshop.doctree b/.doctrees/materials/workshop.doctree new file mode 100644 index 0000000..2e7396a Binary files /dev/null and b/.doctrees/materials/workshop.doctree differ diff --git a/.doctrees/materials/workshop/audience.doctree b/.doctrees/materials/workshop/audience.doctree new file mode 100644 index 0000000..fc0f3a9 Binary files /dev/null and b/.doctrees/materials/workshop/audience.doctree differ diff --git a/.doctrees/materials/workshop/facilitating.doctree b/.doctrees/materials/workshop/facilitating.doctree new file mode 100644 index 0000000..184ff1d Binary files /dev/null and b/.doctrees/materials/workshop/facilitating.doctree differ diff --git a/.doctrees/materials/workshop/feedback.doctree b/.doctrees/materials/workshop/feedback.doctree new file mode 100644 index 0000000..ddf13c2 Binary files /dev/null and b/.doctrees/materials/workshop/feedback.doctree differ diff --git a/.doctrees/materials/workshop/project-owners.doctree b/.doctrees/materials/workshop/project-owners.doctree new file mode 100644 index 0000000..e461360 Binary files /dev/null and b/.doctrees/materials/workshop/project-owners.doctree differ diff --git a/.doctrees/materials/workshop/setup.doctree b/.doctrees/materials/workshop/setup.doctree new file mode 100644 index 0000000..3f2f610 Binary files /dev/null and b/.doctrees/materials/workshop/setup.doctree differ diff --git a/.doctrees/materials/workshop/structure.doctree b/.doctrees/materials/workshop/structure.doctree new file mode 100644 index 0000000..bd5b02d Binary files /dev/null and b/.doctrees/materials/workshop/structure.doctree differ diff --git a/_images/hazardanatomy.png b/_images/hazardanatomy.png new file mode 100644 index 0000000..473f4c6 Binary files /dev/null and b/_images/hazardanatomy.png differ diff --git a/_panels_static/panels-bootstrap.5fd3999ee7762ccc51105388f4a9d115.css b/_panels_static/panels-bootstrap.5fd3999ee7762ccc51105388f4a9d115.css deleted file mode 100644 index 1b057df..0000000 --- a/_panels_static/panels-bootstrap.5fd3999ee7762ccc51105388f4a9d115.css +++ /dev/null @@ -1 +0,0 @@ -.badge{border-radius:.25rem;display:inline-block;font-size:75%;font-weight:700;line-height:1;padding:.25em .4em;text-align:center;vertical-align:baseline;white-space:nowrap}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{border-radius:10rem;padding-left:.6em;padding-right:.6em}.badge-primary{background-color:#007bff;color:#fff}.badge-primary[href]:focus,.badge-primary[href]:hover{background-color:#0062cc;color:#fff;text-decoration:none}.badge-secondary{background-color:#6c757d;color:#fff}.badge-secondary[href]:focus,.badge-secondary[href]:hover{background-color:#545b62;color:#fff;text-decoration:none}.badge-success{background-color:#28a745;color:#fff}.badge-success[href]:focus,.badge-success[href]:hover{background-color:#1e7e34;color:#fff;text-decoration:none}.badge-info{background-color:#17a2b8;color:#fff}.badge-info[href]:focus,.badge-info[href]:hover{background-color:#117a8b;color:#fff;text-decoration:none}.badge-warning{background-color:#ffc107;color:#212529}.badge-warning[href]:focus,.badge-warning[href]:hover{background-color:#d39e00;color:#212529;text-decoration:none}.badge-danger{background-color:#dc3545;color:#fff}.badge-danger[href]:focus,.badge-danger[href]:hover{background-color:#bd2130;color:#fff;text-decoration:none}.badge-light{background-color:#f8f9fa;color:#212529}.badge-light[href]:focus,.badge-light[href]:hover{background-color:#dae0e5;color:#212529;text-decoration:none}.badge-dark{background-color:#343a40;color:#fff}.badge-dark[href]:focus,.badge-dark[href]:hover{background-color:#1d2124;color:#fff;text-decoration:none}.border-0{border:0 !important}.border-top-0{border-top:0 !important}.border-right-0{border-right:0 !important}.border-bottom-0{border-bottom:0 !important}.border-left-0{border-left:0 !important}.p-0{padding:0 !important}.pt-0,.py-0{padding-top:0 !important}.pr-0,.px-0{padding-right:0 !important}.pb-0,.py-0{padding-bottom:0 !important}.pl-0,.px-0{padding-left:0 !important}.p-1{padding:.25rem !important}.pt-1,.py-1{padding-top:.25rem !important}.pr-1,.px-1{padding-right:.25rem !important}.pb-1,.py-1{padding-bottom:.25rem !important}.pl-1,.px-1{padding-left:.25rem !important}.p-2{padding:.5rem !important}.pt-2,.py-2{padding-top:.5rem !important}.pr-2,.px-2{padding-right:.5rem !important}.pb-2,.py-2{padding-bottom:.5rem !important}.pl-2,.px-2{padding-left:.5rem !important}.p-3{padding:1rem !important}.pt-3,.py-3{padding-top:1rem !important}.pr-3,.px-3{padding-right:1rem !important}.pb-3,.py-3{padding-bottom:1rem !important}.pl-3,.px-3{padding-left:1rem !important}.p-4{padding:1.5rem !important}.pt-4,.py-4{padding-top:1.5rem !important}.pr-4,.px-4{padding-right:1.5rem !important}.pb-4,.py-4{padding-bottom:1.5rem !important}.pl-4,.px-4{padding-left:1.5rem !important}.p-5{padding:3rem !important}.pt-5,.py-5{padding-top:3rem !important}.pr-5,.px-5{padding-right:3rem !important}.pb-5,.py-5{padding-bottom:3rem !important}.pl-5,.px-5{padding-left:3rem !important}.m-0{margin:0 !important}.mt-0,.my-0{margin-top:0 !important}.mr-0,.mx-0{margin-right:0 !important}.mb-0,.my-0{margin-bottom:0 !important}.ml-0,.mx-0{margin-left:0 !important}.m-1{margin:.25rem !important}.mt-1,.my-1{margin-top:.25rem !important}.mr-1,.mx-1{margin-right:.25rem !important}.mb-1,.my-1{margin-bottom:.25rem !important}.ml-1,.mx-1{margin-left:.25rem !important}.m-2{margin:.5rem !important}.mt-2,.my-2{margin-top:.5rem !important}.mr-2,.mx-2{margin-right:.5rem !important}.mb-2,.my-2{margin-bottom:.5rem !important}.ml-2,.mx-2{margin-left:.5rem !important}.m-3{margin:1rem !important}.mt-3,.my-3{margin-top:1rem !important}.mr-3,.mx-3{margin-right:1rem !important}.mb-3,.my-3{margin-bottom:1rem !important}.ml-3,.mx-3{margin-left:1rem !important}.m-4{margin:1.5rem !important}.mt-4,.my-4{margin-top:1.5rem !important}.mr-4,.mx-4{margin-right:1.5rem !important}.mb-4,.my-4{margin-bottom:1.5rem !important}.ml-4,.mx-4{margin-left:1.5rem !important}.m-5{margin:3rem !important}.mt-5,.my-5{margin-top:3rem !important}.mr-5,.mx-5{margin-right:3rem !important}.mb-5,.my-5{margin-bottom:3rem !important}.ml-5,.mx-5{margin-left:3rem !important}.btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;color:#212529;cursor:pointer;display:inline-block;font-size:1rem;font-weight:400;line-height:1.5;padding:.375rem .75rem;text-align:center;transition:color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;vertical-align:middle}.btn:hover{color:#212529;text-decoration:none}.btn:visited{color:#212529}.btn.focus,.btn:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.25);outline:0}.btn.disabled,.btn:disabled{opacity:.65}@media (prefers-reduced-motion: reduce){.btn{transition:none}}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{background-color:#007bff;border-color:#007bff;color:#fff}.btn-primary:visited{color:#fff}.btn-primary:hover{background-color:#0069d9;border-color:#0062cc;color:#fff}.btn-primary.focus,.btn-primary:focus{background-color:#0069d9;border-color:#0062cc;box-shadow:0 0 0 .2rem rgba(0,123,255,0.5);color:#fff}.btn-primary.disabled,.btn-primary:disabled{background-color:#007bff;border-color:#007bff;color:#fff}.btn-primary.active:not(:disabled):not(.disabled),.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{background-color:#0062cc;border-color:#005cbf;color:#fff}.btn-primary.active:not(:disabled):not(.disabled):focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-secondary{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-secondary:visited{color:#fff}.btn-secondary:hover{background-color:#5a6268;border-color:#545b62;color:#fff}.btn-secondary.focus,.btn-secondary:focus{background-color:#5a6268;border-color:#545b62;box-shadow:0 0 0 .2rem rgba(108,117,125,0.5);color:#fff}.btn-secondary.disabled,.btn-secondary:disabled{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-secondary.active:not(:disabled):not(.disabled),.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{background-color:#545b62;border-color:#4e555b;color:#fff}.btn-secondary.active:not(:disabled):not(.disabled):focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-success{background-color:#28a745;border-color:#28a745;color:#fff}.btn-success:visited{color:#fff}.btn-success:hover{background-color:#218838;border-color:#1e7e34;color:#fff}.btn-success.focus,.btn-success:focus{background-color:#218838;border-color:#1e7e34;box-shadow:0 0 0 .2rem rgba(40,167,69,0.5);color:#fff}.btn-success.disabled,.btn-success:disabled{background-color:#28a745;border-color:#28a745;color:#fff}.btn-success.active:not(:disabled):not(.disabled),.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{background-color:#1e7e34;border-color:#1c7430;color:#fff}.btn-success.active:not(:disabled):not(.disabled):focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-info{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-info:visited{color:#fff}.btn-info:hover{background-color:#138496;border-color:#117a8b;color:#fff}.btn-info.focus,.btn-info:focus{background-color:#138496;border-color:#117a8b;box-shadow:0 0 0 .2rem rgba(23,162,184,0.5);color:#fff}.btn-info.disabled,.btn-info:disabled{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-info.active:not(:disabled):not(.disabled),.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{background-color:#117a8b;border-color:#10707f;color:#fff}.btn-info.active:not(:disabled):not(.disabled):focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-warning{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-warning:visited{color:#212529}.btn-warning:hover{background-color:#e0a800;border-color:#d39e00;color:#212529}.btn-warning.focus,.btn-warning:focus{background-color:#e0a800;border-color:#d39e00;box-shadow:0 0 0 .2rem rgba(255,193,7,0.5);color:#212529}.btn-warning.disabled,.btn-warning:disabled{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-warning.active:not(:disabled):not(.disabled),.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{background-color:#d39e00;border-color:#c69500;color:#212529}.btn-warning.active:not(:disabled):not(.disabled):focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-danger{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-danger:visited{color:#fff}.btn-danger:hover{background-color:#c82333;border-color:#bd2130;color:#fff}.btn-danger.focus,.btn-danger:focus{background-color:#c82333;border-color:#bd2130;box-shadow:0 0 0 .2rem rgba(220,53,69,0.5);color:#fff}.btn-danger.disabled,.btn-danger:disabled{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-danger.active:not(:disabled):not(.disabled),.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{background-color:#bd2130;border-color:#b21f2d;color:#fff}.btn-danger.active:not(:disabled):not(.disabled):focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-light{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-light:visited{color:#212529}.btn-light:hover{background-color:#e2e6ea;border-color:#dae0e5;color:#212529}.btn-light.focus,.btn-light:focus{background-color:#e2e6ea;border-color:#dae0e5;box-shadow:0 0 0 .2rem rgba(248,249,250,0.5);color:#212529}.btn-light.disabled,.btn-light:disabled{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-light.active:not(:disabled):not(.disabled),.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{background-color:#dae0e5;border-color:#d3d9df;color:#212529}.btn-light.active:not(:disabled):not(.disabled):focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-dark{background-color:#343a40;border-color:#343a40;color:#fff}.btn-dark:visited{color:#fff}.btn-dark:hover{background-color:#23272b;border-color:#1d2124;color:#fff}.btn-dark.focus,.btn-dark:focus{background-color:#23272b;border-color:#1d2124;box-shadow:0 0 0 .2rem rgba(52,58,64,0.5);color:#fff}.btn-dark.disabled,.btn-dark:disabled{background-color:#343a40;border-color:#343a40;color:#fff}.btn-dark.active:not(:disabled):not(.disabled),.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{background-color:#1d2124;border-color:#171a1d;color:#fff}.btn-dark.active:not(:disabled):not(.disabled):focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-outline-primary{border-color:#007bff;color:#007bff}.btn-outline-primary:visited{color:#007bff}.btn-outline-primary:hover{background-color:#007bff;border-color:#007bff;color:#fff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{background-color:transparent;color:#007bff}.btn-outline-primary.active:not(:disabled):not(.disabled),.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{background-color:#007bff;border-color:#007bff;color:#fff}.btn-outline-primary.active:not(:disabled):not(.disabled):focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-outline-secondary{border-color:#6c757d;color:#6c757d}.btn-outline-secondary:visited{color:#6c757d}.btn-outline-secondary:hover{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{background-color:transparent;color:#6c757d}.btn-outline-secondary.active:not(:disabled):not(.disabled),.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-outline-secondary.active:not(:disabled):not(.disabled):focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-outline-success{border-color:#28a745;color:#28a745}.btn-outline-success:visited{color:#28a745}.btn-outline-success:hover{background-color:#28a745;border-color:#28a745;color:#fff}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{background-color:transparent;color:#28a745}.btn-outline-success.active:not(:disabled):not(.disabled),.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{background-color:#28a745;border-color:#28a745;color:#fff}.btn-outline-success.active:not(:disabled):not(.disabled):focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-outline-info{border-color:#17a2b8;color:#17a2b8}.btn-outline-info:visited{color:#17a2b8}.btn-outline-info:hover{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{background-color:transparent;color:#17a2b8}.btn-outline-info.active:not(:disabled):not(.disabled),.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-outline-info.active:not(:disabled):not(.disabled):focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-outline-warning{border-color:#ffc107;color:#ffc107}.btn-outline-warning:visited{color:#ffc107}.btn-outline-warning:hover{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{background-color:transparent;color:#ffc107}.btn-outline-warning.active:not(:disabled):not(.disabled),.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-outline-warning.active:not(:disabled):not(.disabled):focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-outline-danger{border-color:#dc3545;color:#dc3545}.btn-outline-danger:visited{color:#dc3545}.btn-outline-danger:hover{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{background-color:transparent;color:#dc3545}.btn-outline-danger.active:not(:disabled):not(.disabled),.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-outline-danger.active:not(:disabled):not(.disabled):focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-outline-light{border-color:#f8f9fa;color:#f8f9fa}.btn-outline-light:visited{color:#f8f9fa}.btn-outline-light:hover{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{background-color:transparent;color:#f8f9fa}.btn-outline-light.active:not(:disabled):not(.disabled),.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-outline-light.active:not(:disabled):not(.disabled):focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-outline-dark{border-color:#343a40;color:#343a40}.btn-outline-dark:visited{color:#343a40}.btn-outline-dark:hover{background-color:#343a40;border-color:#343a40;color:#fff}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{background-color:transparent;color:#343a40}.btn-outline-dark.active:not(:disabled):not(.disabled),.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{background-color:#343a40;border-color:#343a40;color:#fff}.btn-outline-dark.active:not(:disabled):not(.disabled):focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-link{color:#007bff;font-weight:400;text-decoration:none}.btn-link:hover{color:#0056b3;text-decoration:underline}.btn-link.focus,.btn-link:focus{box-shadow:none;text-decoration:underline}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{border-radius:.3rem;font-size:1.25rem;line-height:1.5;padding:.5rem 1rem}.btn-group-sm>.btn,.btn-sm{border-radius:.2rem;font-size:.875rem;line-height:1.5;padding:.25rem .5rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input.btn-block[type=button],input.btn-block[type=reset],input.btn-block[type=submit]{width:100%}.stretched-link::after{background-color:rgba(0,0,0,0);bottom:0;content:'';left:0;pointer-events:auto;position:absolute;right:0;top:0;z-index:1}.text-wrap{white-space:normal !important}.card{background-clip:border-box;background-color:#fff;border:1px solid rgba(0,0,0,0.125);border-radius:.25rem;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.card>hr{margin-left:0;margin-right:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;min-height:1px;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-bottom:0;margin-top:-.375rem}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{background-color:rgba(0,0,0,0.03);border-bottom:1px solid rgba(0,0,0,0.125);margin-bottom:0;padding:.75rem 1.25rem}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{background-color:rgba(0,0,0,0.03);border-top:1px solid rgba(0,0,0,0.125);padding:.75rem 1.25rem}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{border-bottom:0;margin-bottom:-.75rem;margin-left:-.625rem;margin-right:-.625rem}.card-header-pills{margin-left:-.625rem;margin-right:-.625rem}.card-img-overlay{bottom:0;left:0;padding:1.25rem;position:absolute;right:0;top:0}.card-img,.card-img-bottom,.card-img-top{-ms-flex-negative:0;flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-left-radius:calc(.25rem - 1px);border-bottom-right-radius:calc(.25rem - 1px)}.w-100{width:100% !important}.shadow{box-shadow:0 0.5rem 1rem rgba(0,0,0,0.15) !important}.bg-primary{background-color:#007bff !important}button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc !important}a.bg-primary:focus,a.bg-primary:hover{background-color:#0062cc !important}a.text-primary:focus,a.text-primary:hover{color:#121416 !important}.bg-secondary{background-color:#6c757d !important}button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62 !important}a.bg-secondary:focus,a.bg-secondary:hover{background-color:#545b62 !important}a.text-secondary:focus,a.text-secondary:hover{color:#121416 !important}.bg-success{background-color:#28a745 !important}button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34 !important}a.bg-success:focus,a.bg-success:hover{background-color:#1e7e34 !important}a.text-success:focus,a.text-success:hover{color:#121416 !important}.bg-info{background-color:#17a2b8 !important}button.bg-info:focus,button.bg-info:hover{background-color:#117a8b !important}a.bg-info:focus,a.bg-info:hover{background-color:#117a8b !important}a.text-info:focus,a.text-info:hover{color:#121416 !important}.bg-warning{background-color:#ffc107 !important}button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00 !important}a.bg-warning:focus,a.bg-warning:hover{background-color:#d39e00 !important}a.text-warning:focus,a.text-warning:hover{color:#121416 !important}.bg-danger{background-color:#dc3545 !important}button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130 !important}a.bg-danger:focus,a.bg-danger:hover{background-color:#bd2130 !important}a.text-danger:focus,a.text-danger:hover{color:#121416 !important}.bg-light{background-color:#f8f9fa !important}button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5 !important}a.bg-light:focus,a.bg-light:hover{background-color:#dae0e5 !important}a.text-light:focus,a.text-light:hover{color:#121416 !important}.bg-dark{background-color:#343a40 !important}button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124 !important}a.bg-dark:focus,a.bg-dark:hover{background-color:#1d2124 !important}a.text-dark:focus,a.text-dark:hover{color:#121416 !important}.bg-white{background-color:#fff !important}button.bg-white:focus,button.bg-white:hover{background-color:#e6e6e6 !important}a.bg-white:focus,a.bg-white:hover{background-color:#e6e6e6 !important}a.text-white:focus,a.text-white:hover{color:#121416 !important}.text-primary{color:#007bff !important}.text-secondary{color:#6c757d !important}.text-success{color:#28a745 !important}.text-info{color:#17a2b8 !important}.text-warning{color:#ffc107 !important}.text-danger{color:#dc3545 !important}.text-light{color:#f8f9fa !important}.text-dark{color:#343a40 !important}.text-white{color:#fff !important}.text-body{color:#212529 !important}.text-muted{color:#6c757d !important}.text-black-50{color:rgba(0,0,0,0.5) !important}.text-white-50{color:rgba(255,255,255,0.5) !important}.bg-transparent{background-color:transparent !important}.text-justify{text-align:justify !important}.text-left{text-align:left !important}.text-right{text-align:right !important}.text-center{text-align:center !important}.font-weight-light{font-weight:300 !important}.font-weight-lighter{font-weight:lighter !important}.font-weight-normal{font-weight:400 !important}.font-weight-bold{font-weight:700 !important}.font-weight-bolder{font-weight:bolder !important}.font-italic{font-style:italic !important}.container{margin-left:auto;margin-right:auto;padding-left:15px;padding-right:15px;width:100%}@media (min-width: 576px){.container{max-width:540px}}@media (min-width: 768px){.container{max-width:720px}}@media (min-width: 992px){.container{max-width:960px}}@media (min-width: 1200px){.container{max-width:1140px}}.container-fluid,.container-lg,.container-md,.container-sm,.container-xl{margin-left:auto;margin-right:auto;padding-left:15px;padding-right:15px;width:100%}@media (min-width: 576px){.container,.container-sm{max-width:540px}}@media (min-width: 768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width: 992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width: 1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-left:-15px;margin-right:-15px}.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{padding-left:15px;padding-right:15px;position:relative;width:100%}@media (min-width: 576px){.col-sm{flex-basis:0;flex-grow:1;-ms-flex-positive:1;-ms-flex-preferred-size:0;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;max-width:100%;width:auto}.col-sm-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}}@media (min-width: 768px){.col-md{flex-basis:0;flex-grow:1;-ms-flex-positive:1;-ms-flex-preferred-size:0;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;max-width:100%;width:auto}.col-md-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}}@media (min-width: 992px){.col-lg{flex-basis:0;flex-grow:1;-ms-flex-positive:1;-ms-flex-preferred-size:0;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;max-width:100%;width:auto}.col-lg-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}}@media (min-width: 1200px){.col-xl{flex-basis:0;flex-grow:1;-ms-flex-positive:1;-ms-flex-preferred-size:0;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;max-width:100%;width:auto}.col-xl-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}}.d-flex{display:-ms-flexbox !important;display:flex !important}.sphinx-bs,.sphinx-bs *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sphinx-bs p{margin-top:0} diff --git a/_panels_static/panels-main.c949a650a448cc0ae9fd3441c0e17fb0.css b/_panels_static/panels-main.c949a650a448cc0ae9fd3441c0e17fb0.css deleted file mode 100644 index fc14abc..0000000 --- a/_panels_static/panels-main.c949a650a448cc0ae9fd3441c0e17fb0.css +++ /dev/null @@ -1 +0,0 @@ -details.dropdown .summary-title{padding-right:3em !important;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}details.dropdown:hover{cursor:pointer}details.dropdown .summary-content{cursor:default}details.dropdown summary{list-style:none;padding:1em}details.dropdown summary .octicon.no-title{vertical-align:middle}details.dropdown[open] summary .octicon.no-title{visibility:hidden}details.dropdown summary::-webkit-details-marker{display:none}details.dropdown summary:focus{outline:none}details.dropdown summary:hover .summary-up svg,details.dropdown summary:hover .summary-down svg{opacity:1}details.dropdown .summary-up svg,details.dropdown .summary-down svg{display:block;opacity:.6}details.dropdown .summary-up,details.dropdown .summary-down{pointer-events:none;position:absolute;right:1em;top:.75em}details.dropdown[open] .summary-down{visibility:hidden}details.dropdown:not([open]) .summary-up{visibility:hidden}details.dropdown.fade-in[open] summary~*{-moz-animation:panels-fade-in .5s ease-in-out;-webkit-animation:panels-fade-in .5s ease-in-out;animation:panels-fade-in .5s ease-in-out}details.dropdown.fade-in-slide-down[open] summary~*{-moz-animation:panels-fade-in .5s ease-in-out, panels-slide-down .5s ease-in-out;-webkit-animation:panels-fade-in .5s ease-in-out, panels-slide-down .5s ease-in-out;animation:panels-fade-in .5s ease-in-out, panels-slide-down .5s ease-in-out}@keyframes panels-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes panels-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.octicon{display:inline-block;fill:currentColor;vertical-align:text-top}.tabbed-content{box-shadow:0 -.0625rem var(--tabs-color-overline),0 .0625rem var(--tabs-color-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.tabbed-content>:first-child{margin-top:0 !important}.tabbed-content>:last-child{margin-bottom:0 !important}.tabbed-content>.tabbed-set{margin:0}.tabbed-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.tabbed-set>input{opacity:0;position:absolute}.tabbed-set>input:checked+label{border-color:var(--tabs-color-label-active);color:var(--tabs-color-label-active)}.tabbed-set>input:checked+label+.tabbed-content{display:block}.tabbed-set>input:focus+label{outline-style:auto}.tabbed-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.tabbed-set>label{border-bottom:.125rem solid transparent;color:var(--tabs-color-label-inactive);cursor:pointer;font-size:var(--tabs-size-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .tabbed-set>label:hover{color:var(--tabs-color-label-active)} diff --git a/_panels_static/panels-variables.06eb56fa6e07937060861dad626602ad.css b/_panels_static/panels-variables.06eb56fa6e07937060861dad626602ad.css deleted file mode 100644 index adc6166..0000000 --- a/_panels_static/panels-variables.06eb56fa6e07937060861dad626602ad.css +++ /dev/null @@ -1,7 +0,0 @@ -:root { ---tabs-color-label-active: hsla(231, 99%, 66%, 1); ---tabs-color-label-inactive: rgba(178, 206, 245, 0.62); ---tabs-color-overline: rgb(207, 236, 238); ---tabs-color-underline: rgb(207, 236, 238); ---tabs-size-label: 1rem; -} \ No newline at end of file diff --git a/_sources/about.md.txt b/_sources/about.md.txt new file mode 100644 index 0000000..c65782f --- /dev/null +++ b/_sources/about.md.txt @@ -0,0 +1,227 @@ +# About + +The image below describes the 'anatomy' of a Data Hazard label. + +```{image} images/hazardanatomy.png +:width: 70% +:alt: All Hazard labels have an descriptive icon, title, description, examples and suggesed safety precautions. +``` +
+ + + +## How the project started + +The Data Hazards project started in 2021. +We (Natalie Zelenka and Nina Di Cara) spoke together about wanting a way to communicate what might +go wrong in data science projects, because we were frustrated by the repetitive themes we were seeing +in harmful technologies that we talked about in [Data Ethics Club](https://dataethicsclub.com). +We were also concerned that many projects that have significant societal impact do not have those impacts +scrutinised by an ethics committee, because they do not technically have research participants. + +After this conversation we came up with the idea of Hazard labels for communicating these potential harms, +and called them Data Hazards. +We decided they should be visual, like COSHH chemical hazards are, and that they should be a way for +people at all stages of data science technology development to communicate about the same potential +outcomes (no matter how far away those outcomes might seem). + +You can see [the current Data Hazard labels here](labels). +You can [read our original proposal here](materials/misc/proposal). + +These days the project is bigger than just us, and we have many contributors who suggest new content, +changes to the labels, help us to teach others about ethical hazards or run their own events. +If you would like to get involved (we'd love you to!) then we've listed lots of ways +you could on our [Contributing page](contribute). + +Once we had thought of the original list of Hazards we wanted a way for researchers to think about them in +a format that encouraged them to reflect, invite different opinions and make them think more broadly about +the potential ethical concerns from their project. +This led to the development of our workshop format and [all the materials we have since made](materials) +for self-reflection and teaching. +All our resources are designed (and licensed) for re-use by others. + + +## Ethos + +The Data Hazards are currently intended to be used creatively and flexibly, in whatever way they are useful +to the user. +Sometimes this means they are flashcards for teaching students about ethics, sometimes they are displayed with +new research to communicate potential harms, and sometimes they are used in workshops as prompts. + +We believe it is important when using the Data Hazards to help investigate risks in a project, that people +beyond the original researcher are consulted on potential hazards. +This is because we believe that knowledge, including in the sciences, is not objective, and that our +perspectives are shaped by our lived socio-political experiences (this is based on [standpoint theory](https://en.wikipedia.org/wiki/Standpoint_theory)). +This means that ethical problems are not going to have a single correct answer, and that to get a well-rounded understanding of the ethical issues of any new technology we need people from lots of different standpoints to analyse it from their perspective. +This is the best way we can understand the harms it could possibly cause. +We also need to make sure that we are paying attention to how technology might be more likely to adversely affect people from minoritised backgrounds. + +We developed our [workshop format](materials/workshop) to help researchers to gather these different views. + +In summary, the Data Hazards exist to prompt discussion, reflection and thought. +They are not a checkbox exercise, and there is no requirement for a group to come to a consensus. +In an individual context you will likely come to a conclusion, but someone else may have a different view. +We hope that the Data Hazards discussion and reflective activities will help researchers be aware of a broader variety of potential ethical risks in tech projects, and that ethics is complex, situational and worth discussing. + + +## Contact + +The Data Hazards Project was founded by Dr Natalie Zelenka and Dr Nina Di Cara, and is now co-led by Natalie, Nina and Dr Huw Day. Our details are provided below. +We're always keen to hear from people interested in the project, or wanting to get involved. Feel free to send us both an email, or you can find us on Twitter! + +```{list-table} +:header-rows: 1 + +* - __Nina Di Cara__ + - __Natalie Zelenka__ + - __Huw Day__ +* - Senior Research Associate, School of Psychological Science, University of Bristol + - Senior Research Fellow in Health Data Science, Institute of Health Informatics, University College London + - Data Scientist, Jean Golding Institute, University of Bristol +* - GitHub: [@ninadicara](https://github.com/ninadicara) + - GitHub: [@NatalieZelenka](https://github.com/NatalieZelenka) + - GitHub: [@HuwWDay](https://github.com/HuwWDay) +* - Twitter/X: [@ninadicara](https://twitter.com/ninadicara) + - Twitter/X: [@NatZelenka](https://twitter.com/NatZelenka) + - Twitter/X: [@disco_huw](https://twitter.com/disco_huw) +* - Email: [nina.dicara@bristol.ac.uk](mailto:nina.dicara@bristol.ac.uk) + - Email: [n.zelenka@ucl.ac.uk](mailto:n.zelenka@ucl.ac.uk) + - Email: [huw.day@bristol.ac.uk](mailto:huw.day@bristol.ac.uk) +``` + diff --git a/_sources/contents/code-of-conduct.md.txt b/_sources/code-of-conduct.md.txt similarity index 99% rename from _sources/contents/code-of-conduct.md.txt rename to _sources/code-of-conduct.md.txt index 28fceab..c1feeba 100644 --- a/_sources/contents/code-of-conduct.md.txt +++ b/_sources/code-of-conduct.md.txt @@ -32,7 +32,7 @@ The below Do-s and Don’t-s are guidelines to remind us all of best standards o ## Reporting Procedure If you have been subject to or witnessed unacceptable behaviour, either during a meeting or on this repository, then you can get in touch with either Natalie or Nina. -Natalie: natalie.zelenka@bristol.ac.uk +Natalie: n.zelenka@ucl.ac.uk Nina: nina.dicara@bristol.ac.uk If you would prefer to contact someone who is not directly involved in organising the group, then you can direct your concerns to John Newby ([JGI Manager](http://www.bristol.ac.uk/golding/people/team/)), at [John.Newby@bristol.ac.uk](mailto:John.Newby@bristol.ac.uk) diff --git a/_sources/contents/about.md.txt b/_sources/contents/about.md.txt deleted file mode 100644 index d54c674..0000000 --- a/_sources/contents/about.md.txt +++ /dev/null @@ -1,246 +0,0 @@ -# About - -Read more about the origin of the project and its ethos, contributors and timeline here. - -
- -
- -## How the project started - -The Data Hazards project started in 2021. -We (Natalie Zelenka and Nina Di Cara) spoke together about wanting a way to communicate what might -go wrong in data science projects, because we were frustrated by the repetitive themes we were seeing -in harmful technologies that we talked about in [Data Ethics Club](https://dataethicsclub.com). -We were also concerned that many projects that have significant societal impact do not have those impacts -scrutinised by an ethics committee, because they do not technically have research participants. - -After this conversation we came up with the idea of Hazard labels for communicating these potential harms, -and called them Data Hazards. -We decided they should be visual, like COSHH chemical hazards are, and that they should be a way for -people at all stages of data science technology development to communicate about the same potential -outcomes (no matter how far away those outcomes might seem). - -You can see [the current Data Hazard labels here](data-hazards). -You can [read our original proposal here](materials/misc/proposal). - -These days the project is bigger than just us, and we have many contributors who suggest new content, -changes to the labels, help us to teach others about ethical hazards or run their own events. -If you would like to get involved (we'd love you to!) then we've listed lots of ways -you could on our [Contributing page](contribute). - - - -Once we had thought of the original list of Hazards we wanted a way for researchers to think about them in -a format that encouraged them to reflect, invite different opinions and make them think more broadly about -the potential ethical concerns from their project. -This led to the development of our workshop format and [all the materials we have since made](materials) -for self-reflection and teaching. -All our resources are designed (and licensed) for re-use by others. - - -## Ethos - -The Data Hazards are currently intended to be used creatively and flexibly, in whatever way they are useful -to the user. -Sometimes this means they are flashcards for teaching students about ethics, sometimes they are displayed with -new research to communicate potential harms, and sometimes they are used in workshops as prompts. - -We believe it is important when using the Data Hazards to help investigate risks in a project, that people -beyond the original researcher are consulted on potential hazards. -This is because we believe that knowledge, including in the sciences, is not objective, and that our -perspectives are shaped by our lived socio-political experiences (this is based on [standpoint theory](https://en.wikipedia.org/wiki/Standpoint_theory)). -This means that ethical problems are not going to have a single correct answer, and that to get a well-rounded understanding of the ethical issues of any new technology we need people from lots of different standpoints to analyse it from their perspective. -This is the best way we can understand the harms it could possibly cause. -We also need to make sure that we are paying attention to how technology might be more likely to adversely affect people from minoritised backgrounds. - -We developed our [workshop format](materials/workshop) to help researchers to gather these different views. - -In summary, the Data Hazards exist to prompt discussion, reflection and thought. -They are not a checkbox exercise, and there is no requirement for a group to come to a consensus. -In an individual context you will likely come to a conclusion, but someone else may have a different view. -We hope that the Data Hazards discussion and reflective activities will help researchers be aware of a broader variety of potential ethical risks in tech projects, and that ethics is complex, situational and worth discussing. - - -## Contributors - -Our brilliant contributors are listed here, and you can [read more detail about our contributing process here](contribute). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NatalieThurlby
NatalieThurlby

📆 🎨 🤔 📋 🚧 🚇 📖
Conor Houghton
Conor Houghton

🔍
Nina
Nina

📆 🤔 📋 🚧 ️️️️♿️ 📖 🎨 🐛
Valerio Maggio
Valerio Maggio

👀
Ismael-KG
Ismael-KG

📋
Kate Robson-Brown
Kate Robson-Brown

👀
Patricia Holley
Patricia Holley

👀
Lily Rice
Lily Rice

👀
ekuw
ekuw

👀
James Thomas
James Thomas

👀
Jakub Dakowski
Jakub Dakowski

💻
vairylein
vairylein

🎨 🤔
Holly Fraser
Holly Fraser

📓 💡
Gareth Jones
Gareth Jones

💻
Zoë Turner
Zoë Turner

🚧 🤔
Susana Roman Garcia
Susana Roman Garcia

💡 📢 🤔
- - - - - - - -(project-timeline)= -## Project timeline - -Here's a rough project timeline that tells the rough history of the project, and sometimes what we have coming up! - -````{panels} -:container: timeline -:column: col-6 p-0 -:card: - ---- -:column: +left ---- -:column: +entry right - -__March-April 2021__: Behind the scenes plans -^^^ - -{fa}`check,text-success mr-1` Thinking, reading and planning. - -{fa}`check,text-success mr-1` Writing [proposal](materials/misc/proposal). - -{fa}`check,text-success mr-1` Getting feedback on initial ideas. - ---- -:column: +entry left - -__May-Aug 2021__: Prepare for first Data Hazards workshop -^^^ - -{fa}`check,text-success mr-1` Launched the website. - -{fa}`check,text-success mr-1` Submitted ethics application. - -{fa}`check,text-success mr-1` Prepare materials and begin advertising. - -{fa}`check,text-success mr-1` Set up [Open Science Framework project](https://osf.io/3fv7t/) and [preregister](https://osf.io/pcv7j) analysis. - ---- -:column: +right ---- -:column: +left - ---- -:column: +entry right - -__Sept 2021__ Run first Data Hazards workshops (academic-focused) -^^^ - -{fa}`check,text-success mr-1` Ran the [first Data Hazards workshop](events/2021-09-21_workshop) on __21st Sept 2021__. - ---- -:column: +entry left - -__Oct 2021__ Use workshop feedback to improve data hazards and present early results - -^^^ - -{fa}`check,text-success mr-1` Presented early results from workshop at [AI Ethics Best Practices and the Future of Innovation](https://www.eventbrite.co.uk/e/ai-ethics-best-practices-and-the-future-of-innovation-tickets-173883098027) as part of [Bristol Tech Festival](https://bristoltechfest.org/) on __13th Oct 2021__ ([slides](events/bristol-tech-fest)). - -{fa}`check,text-success mr-1` Used workshop feedback to make improvements to the Hazard labels and workshop materials. - ---- -:column: +right - ---- -:column: +left - ---- -:column: +entry right - -__Jan 2021__ Awarded £20,000 Enhancing Research Culture funding -^^^ -{fa}`check,text-success mr-1` Set up our new project to deliver a 'train-the-trainer' for Data Hazards. - ---- -:column: +entry left - -__Feb-May 2022__ Developed new labels and facilitator training materials -^^^ -{fa}`check,text-success mr-1` Hired animator to create animated explainers for Data Hazards and new Hazard labels. - -{fa}`check,text-success mr-1` Developmed and released run-your-own workshop materials. - -{fa}`check,text-success mr-1` We went to MozFest 2022 to run a Data Hazards workshop! ---- -:column: +right - ---- -:column: +left - ---- -:column: +entry right - -__June 2022__: Run our facilitator workshops -^^^ -{fa}`check,text-success mr-1` Ran a Data Hazards workshop as part of the Jean Golding Institute Showcase. - -{fa}`check,text-success mr-1` Ran our first Data Hazards facilitator workshop in-person as part of Bristol Data Week. - -{fa}`check,text-success mr-1` Ran our second (online) Data Hazards facilitator workshop. - ---- -:column: +entry left - -__July-Dec 2022__: Prepare for first version release -^^^ - -{fa}`check,text-success mr-1` Analyse all the results and feedback from five total workshops. - -{fa}`check,text-success mr-1` Applied (successfully) for launch event funding from [UKRN](https://www.ukrn.org/about/). - -{fa}`check,text-success mr-1` Collect all previous suggestions for the project and think about future versions. - ---- -:column: +right - ---- -:column: +left - ---- -:column: +entry right - -__March 2023__: Version 1.0 Release! -^^^ - -{fa}`check,text-success mr-1` Attend AI UK 2023 as exhibitors! - -- 29th March we will run the Data Hazards V1.0 Launch event! - -- We will release a pre-print of our first paper about the project! - -```` - diff --git a/_sources/contents/contact.md.txt b/_sources/contents/contact.md.txt deleted file mode 100644 index b39339d..0000000 --- a/_sources/contents/contact.md.txt +++ /dev/null @@ -1,24 +0,0 @@ -# Contact - -The Data Hazards Project was founded by Dr Natalie Zelenka and Dr Nina Di Cara, and is now co-led by Natalie, Nina and Huw Day. Our details are provided below. -We're always keen to hear from people interested in the project, or wanting to get involved. Feel free to send us both an email, or you can find us on Twitter! - - -```{list-table} -:header-rows: 1 - -* - __Nina Di Cara__ - - __Natalie Zelenka__ - - __Huw Day__ -* - Senior Research Associate, School of Psychological Science, University of Bristol - - Senior Research Fellow in Health Data Science, Institute of Health Informatics, University College London - - Data Scientist, Jean Golding Institute, University of Bristol -* - GitHub: [@ninadicara](https://github.com/ninadicara) - - GitHub: [@NatalieZelenka](https://github.com/NatalieZelenka) - - GitHub: [@HuwWDay](https://github.com/HuwWDay) -* - Twitter/X: [@ninadicara](https://twitter.com/ninadicara) - - Twitter/X: [@NatZelenka](https://twitter.com/NatZelenka) - - Twitter/X: [@disco_huw](https://twitter.com/disco_huw) -* - Email: [nina.dicara@bristol.ac.uk](mailto:nina.dicara@bristol.ac.uk) - - Email: [n.zelenka@ucl.ac.uk](mailto:n.zelenka@ucl.ac.uk) - - Email: [huw.day@bristol.ac.uk](mailto:huw.day@bristol.ac.uk) diff --git a/_sources/contents/contribute/changelog.md.txt b/_sources/contents/contribute/changelog.md.txt deleted file mode 100644 index 63e2299..0000000 --- a/_sources/contents/contribute/changelog.md.txt +++ /dev/null @@ -1,25 +0,0 @@ -# Change log - -The change log records when changes that have been made to the project and gives a brief description of what the changes were. -The change log started in March 2022. -The most recent changes should be at the top of the list. - - - -## 06.12.2022: Update new Hazard labels -[@ninadicara](https://github.com/ninadicara) -Updated all the images of the Hazards with our new labels designed by the amazing [Yasmin Dwiputri](http://yasmindwiputri.com/)! - - -## 07.03.2022: Move Data Hazards to individual pages -[@ninadicara](https://github.com/ninadicara) -Moved all of the Hazards to their own individual pages, and linked them from the original sphinx panels. -Also capitalised all of the names so that they are consistently named. -This should make it easier for people to contribute to a single Hazard and record their contribution against it :) - - - diff --git a/_sources/contents/contribute/contributors.md.txt b/_sources/contents/contribute/contributors.md.txt deleted file mode 100644 index 8a0240c..0000000 --- a/_sources/contents/contribute/contributors.md.txt +++ /dev/null @@ -1,96 +0,0 @@ -# Record of contributions - -The Data Hazards project exists because of the support and contributions of the many different people below. -Please also note that people have also anonymously contributed ideas and resources to the project that Nina and Natalie have added on their behalf. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NatalieThurlby
NatalieThurlby

📆 🎨 🤔 📋 🚧 🚇 📖
Conor Houghton
Conor Houghton

🔍
Nina
Nina

📆 🤔 📋 🚧 ️️️️♿️ 📖 🎨 🐛
Valerio Maggio
Valerio Maggio

👀
Ismael-KG
Ismael-KG

📋
Kate Robson-Brown
Kate Robson-Brown

👀
Patricia Holley
Patricia Holley

👀
Lily Rice
Lily Rice

👀
ekuw
ekuw

👀
James Thomas
James Thomas

👀
Jakub Dakowski
Jakub Dakowski

💻
vairylein
vairylein

🎨 🤔
Holly Fraser
Holly Fraser

📓 💡
Gareth Jones
Gareth Jones

💻
Zoë Turner
Zoë Turner

🚧 🤔
Susana Roman Garcia
Susana Roman Garcia

💡 📢 🤔
Melanie I Stefan
Melanie I Stefan

🤔 📢
- - - - - -This page is a place where anyone who has contributed to the project can be recognised for the time, effort and expertise they have given to Data Hazards. - -This page is based on a similar model used by [The Turing Way](https://github.com/alan-turing-institute/the-turing-way/blob/main/contributors.md) for recognising contributors to open source projects. - -We welcome anyone asking to be added to this page if they have made a contribution. -You can read about different ways to contribute to the project in our [contributors guide](how-to-contribute). -To be added, please [submit an issue](https://github.com/very-good-science/data-hazards/issues), make a pull request, or [send us an email](mailto:grp-ethicaldatascience@groups.bristol.ac.uk) which includes the following details: -* Your Name -* Your Role and Affiliation -* (Optional) ORCID ID or other persistent identifier -* (Optional) Personal contact details or website -* Overview of your contribution to the Data Hazards Project - please don't be modest! - - -## Contributors - - - -### Nina Di Cara -* Role: Co-PI -* ORCID [0000-0002-6179-1067](https://orcid.org/0000-0002-6179-1067) -* GitHub: [ninadicara](https://github.com/ninadicara) -> Along with Natalie I worked on the original idea for the Data Hazards, created resources around them (like teaching materials, slides, reflective prompts, illustrations), planned and delivered our workshops, and the website content. Jointly Natalie and I provide leadership for the project in terms of its next steps and uses. I care a lot about reducing the harm that technology can do to people who may not have power to fight back against, and hope this projects goes some way to making us all think more carefully about what we can all do as individuals to prevent harm. I am also thrilled to have been able to work with (and continue to work with) all the fantastic people who have got involved with this project! - - -### Natalie Zelenka -* Role: Co-PI -* ORCID: [0000-0002-1007-0286](https://orcid.org/0000-0002-1007-0286) -* GitHub: [NatalieZelenka](https://github.com/NatalieZelenka) -> As a co-lead of the Data Hazards project, I developed the idea for Data Hazards with Nina, wrote lesson materials and proposals and drafted papers, designed images, found funding, and did lots of planning. Me and Nina shared these leadership and organisational tasks 50-50, but we are so grateful for everyone's contributions and support so far. I hope that - like some of the work that I'm [most](https://the-turing-way.netlify.app/) [inspired](https://reproducibilitea.org/) [by](https://carpentries.org/) - these materials *reduce barriers* for researchers. In this case, I hope Data Hazards makes it easier for data scientists to consider the ethical implications of their work and to make those decisions together with the communities who are affected by the work they are doing. - -### Ismael Kherrouvi Garcia - -* Role: Workshop facilitator (and huge fan!) -* ORCID: [0000-0002-6850-8375](https://doi.org/0000-0002-6850-8375) -* Find me on :octocat: [Ismael-KG](https://github.com/Ismael-KG), and Twitter ([@hermeneuticist](https://twitter.com/hermeneuticist)) -> In September 2021, I was delighted to facilitate a workshop alongside [@NatalieZelenka](https://github.com/NatalieZelenka) and [@ninadicara](https://github.com/ninadicara) to [test the Data Hazard labels](https://www.bristol.ac.uk/golding/events/2021/data-hazards-workshop---21-september-2021.html) with researchers from diverse backgrounds. This meant working with Natalie and Nina to familiarise myself with [the prompts they had prepared](https://github.com/very-good-science/data-hazards/blob/ae2ecfad7f85fe48670ed6221a6563353d31e77b/images/worst-case-prompt.png), and then keeping the conversation flowing during breakout rooms with workshop participants. I had previously gathered feedback from The Alan Turing Institute's [Ethics Advisory Group](https://www.turing.ac.uk/research/data-ethics/ethics-advisory-group) (EAG) for the Data Hazard labels. My time with the Turing's EAG allowed me to appreciate the value of the Data Hazard labels, both in the context of training data scientists on questions of ethics, and for preparing documentation for the review of research ethics committees. - - -### Melanie I Stefan - -* Role: Early adopter -* ORCID: [0000-0002-6086-7357](https://orcid.org/my-orcid?orcid=0000-0002-6086-7357) -* GitHub: [MelanieIStefan](https://github.com/MelanieIStefan) -> I was introduced to Data Hazards by the wonderful [@Susana465](https://susana465.github.io/), and it has informed my thinking and practice ever since. I helped facilitate a workhop on Data Hazards at [COMBINE 2022 in Berlin](https://co.mbine.org/author/combine-2022/), and also talked about how I use the Data Hazards framework to flag up potential issues with my own lecture materials at the [Data Hazards, Ethics and Reproducibility One-Day Symposium](https://www.eventbrite.com/e/online-data-hazards-ethics-and-reproducibility-one-day-symposium-tickets-517490858087) at the Turing Institute in 2023. I am also involved in the discussion on the Data Hazards labels themselves. - -### Susana Roman Garcia - -* Role: Workshop facilitator, content developer of the Data Hazards application to different settings, especially Neuroscience, PhD case study application of Data Hazards -* ORCID ID: [0009-0004-6967-7754](https://orcid.org/0009-0004-6967-7754) -* [Personal website](https://susana465.github.io/website/) -> I came across the Data Hazards project as I looked for a way to embed thinking about ethics into my PhD, around 2021/22. Since then, I have attended a facilitator training workshop given by Nina and Natalie; and applied the Data Hazards framework to my PhD as I go along. To showcase this, I made a [poster presentation](https://github.com/Susana465/Bias-and-Reproducibility-Poster/blob/main/README.md) for the [COMBINE](https://combine-org.github.io/events/) and [ICSB](https://www.icsb2022.berlin/home) 2022 conferences. ->I have also facilitated a couple of Data Hazards workshops, information for how I prepared can be found here [Data_Hazards_workshops](https://github.com/Susana465/Data_Hazards_workshops). I have also co-organised and co-hosted a [one-day symposium around Data Hazards, Ethics and Reproducibility in 2023](https://github.com/Susana465/der_symposium_20230310). -> Likewise, I also worked with the Data Hazards team to create a [poster](https://github.com/Susana465/DH_Project_CaseStudy) for AI UK 2023, in which I showcased my PhD work for people at the conference to discuss what Data Hazard labels they thought applied. -> I have also worked on adding a chapter to the [Turing Way Booklet](https://the-turing-way.netlify.app/index.html) about Data Hazards, which is currently still in the process of being reviewed and published as of January 2024 (see info [here](https://github.com/the-turing-way/the-turing-way/pull/3435)). - diff --git a/_sources/contents/data-hazards.md.txt b/_sources/contents/data-hazards.md.txt index ea14565..f1a68a8 100644 --- a/_sources/contents/data-hazards.md.txt +++ b/_sources/contents/data-hazards.md.txt @@ -1,162 +1 @@ -# Data Hazard labels - -This page contains the Data Hazard labels themselves. -These labels, descriptions, examples, and safety precautions will evolve as we develop the hazard labels with the communities who will use them. -We welcome you to suggest changes, so please check our [contribution guidelines](contribute) if you would like to. - -You can [download a printable set of Data Hazards cards here](../_static/DataHazards_PrintableCards.pdf). - -Each hazard has: -- __Hazard__ image, title, and description which represents and describes the risk. -- __Examples__ to clarify what the hazard covers. -- __Safety Precautions__ - things that we would want to see done **before** the research is deployed. - -They are designed to help us think about the different types of hazards. - -We also collect a series of mitigation resources and tools (scroll down) to help apply the safety precautions to your project. - -````{panels} -:container: container-fluid -:column: col-6 p-3 -:img-top-cls: p-3 bg-warning -:header: bg-warning -:body: bg-warning -:footer: bg-warning - -:img-top: /images/hazards/general-hazard.png - -```{link-button} hazards/general-hazard.html -:text: -:classes: stretched-link -``` -__Data Hazard__ - -Data Science is being used in this output, and any negative outcome of using this work are not the fault of "the algorithm" or "the software". - -This hazard applies to __all__ Data Science research outputs. - ---- -:img-top: /images/hazards/reinforce-bias.png - -```{link-button} hazards/reinforces-biases.html -:text: -:classes: stretched-link -``` -__Reinforces Existing Biases__ - -Reinforces unfair treatment of individuals and groups. This may be due to for example input data, algorithm or software design choices, or society at large. - -__Note:__ this is a hazard in it's own right, even if it isn't then used to harm people directly, due to e.g. reinforcing stereotypes. - ---- -:img-top: /images/hazards/classifies-people.png - -```{link-button} hazards/ranks-classifies.html -:text: -:classes: stretched-link -``` -__Ranks Or Classifies People__ - -Ranking and classifications of people are hazards in their own right and should be handled with care. - -To see why, we can think about what happens when the ranking/classification is inaccurate, when people disagree with how they are ranked/classified, as well as who the ranking/classification is and is not working for, how it can be gamed, and what it is used to justify or explain. - ---- -:img-top: /images/hazards/environment.png - -```{link-button} hazards/high-environmental-cost.html -:text: -:classes: stretched-link -``` -__High Environmental Cost__ - -This hazard is appropriate where methodologies are energy-hungry, data-hungry (requiring more and more computation), or require special hardware that require rare materials. - ---- -:img-top: /images/hazards/lacks-community.png - -```{link-button} hazards/lacks-community-involvement.html -:text: -:classes: stretched-link -``` -__Lacks Community Involvement__ - -This applies when technology is being produced without input from the community it is supposed to serve. - ---- -:img-top: /images/hazards/misuse.png - -```{link-button} hazards/danger-of-misuse.html -:text: -:classes: stretched-link -``` -__Danger Of Misuse__ - -There is a danger of misusing the algorithm, technology, or data collected as part of this work. - ---- -:img-top: /images/hazards/difficult-to-understand.png - -```{link-button} hazards/difficult-to-understand.html -:text: -:classes: stretched-link -``` -__Difficult To Understand__ - -There is a danger that the technology is difficult to understand. -This could be because of the technology itself is hard to interpret (e.g. neural nets), or problems with it's implementation (i.e. code is not provided, or not documented). - -Depending on the circumstances of its use, this could mean that incorrect results are hard to identify, or that the technology is inaccessible to people (difficult to implement or use). - ---- -:img-top: /images/hazards/direct-harm.png - -```{link-button} hazards/direct-harm.html -:text: -:classes: stretched-link -``` -__May Cause Direct Harm__ - -The application area of this technology means that it is capable of causing direct physical or psychological harm to someone even if used correctly e.g. healthcare and driverless vehicles may be expected to directly harm someone unless they have 100% accuracy. - ---- -:img-top: /images/hazards/privacy.png - -```{link-button} hazards/risk-to-privacy.html -:text: -:classes: stretched-link -``` -__Risk To Privacy__ - -This technology may risk the privacy of individuals whose data is processed by it. - ---- -:img-top: /images/hazards/automates-decision-making.png - -```{link-button} hazards/automates-decision-making.html -:text: -:classes: stretched-link -``` -__Automates Decision Making__ - -Automated decision making can be hazardous for a number of reasons, and these will be highly dependent on the field in which it is being applied. -We should ask ourselves whose decisions are being automated, what automation can bring to the process, and who is benefitted/harmed from this automation. - ---- -:img-top: /images/hazards/lacks-informed-consent.png - -```{link-button} hazards/lacks-informed-consent.html -:text: -:classes: stretched-link -``` -__Lacks Informed Consent__ - -This hazard applies to datasets or algorithms that use data which has not been provided with the explicit consent of the data owner/creator. This data often lacks -other contextual information which can also make it difficult to understand how the dataset may be biased. - -```` - -## Related resources - -You can find our [list of useful tools and resources to help you implement the Data Hazard safety resources here](mitigation-resources.md). -You can also [download a printable set of Data Hazards cards here](../_static/DataHazards_PrintableCards.pdf). + diff --git a/_sources/contents/materials/teaching/students.md.txt b/_sources/contents/materials/teaching/students.md.txt deleted file mode 100644 index db8fe6b..0000000 --- a/_sources/contents/materials/teaching/students.md.txt +++ /dev/null @@ -1,33 +0,0 @@ -# Data Hazards Student Overview - -This page contains some handy links about the Data Hazards project that might be useful to you throughout the session. - -## Slido link - -[Link to the Slido](https://app.sli.do/event/wes4zth7) - -Alternatively you can access it by going to https://slido.com and entering the code `#192908`. - -## Data Hazard label names - -Here is a short list of all the names of the Hazards to use as a reference. -You can get the full detail of all the Data Hazards with their additional info and safety precautions [from this link](../../data-hazards), or by clicking on the link in the menu bar. - -* Data hazard -* Reinforces exising biases -* Ranks or classifies people -* High environmental cost -* Lacks community involvement -* Danger of misuse -* Difficult to understand -* May cause direct harm -* Privacy -* Automates decision making -* Lacks informed consent - - -## Slides - -You can find [the slides we were presenting here](https://docs.google.com/presentation/d/1KzTdvnL8wk9oZ-h7C_yNWHtA4ki5i6moij8y-gP-z0s/edit?usp=sharing) (and below) in case you would like access to them later. - - diff --git a/_sources/contents/presenting/github-badge.md.txt b/_sources/contents/presenting/github-badge.md.txt deleted file mode 100644 index 4a181ce..0000000 --- a/_sources/contents/presenting/github-badge.md.txt +++ /dev/null @@ -1 +0,0 @@ -# GitHub badges for Data Hazards \ No newline at end of file diff --git a/_sources/contents/presenting/image-app.md.txt b/_sources/contents/presenting/image-app.md.txt deleted file mode 100644 index 195ce82..0000000 --- a/_sources/contents/presenting/image-app.md.txt +++ /dev/null @@ -1 +0,0 @@ -# Generate a Data Hazards summary image \ No newline at end of file diff --git a/_sources/contents/contribute.md.txt b/_sources/contribute.md.txt similarity index 79% rename from _sources/contents/contribute.md.txt rename to _sources/contribute.md.txt index ee98c54..36bdb79 100644 --- a/_sources/contents/contribute.md.txt +++ b/_sources/contribute.md.txt @@ -1,4 +1,4 @@ -# Contributing +# Contribute ```{toctree} :maxdepth: 1 @@ -7,7 +7,6 @@ contribute/style-guide contribute/how-to-contribute contribute/credit-for-contributions contribute/contributors -contribute/changelog ``` The Data Hazards project is always welcoming new contributors! @@ -15,8 +14,7 @@ This page gives you an overview of how you can get involved. You can see all of our wonderful existing contributors in our [Record of contributions](contribute/contributors). We strongly welcome first-time GitHub users and are very happy to provide support if you would like to learn how to edit the repository. -Please just [get in touch by email][dec-email] if that is the case. -You could also come to our [community co-working calls](events/coworking)! +Please just [get in touch by email][email] if that is the case. All our content is created and shared under a [CC-BY 4.0 license](https://creativecommons.org/licenses/by/4.0/), and so if you do contribute to the repository your work will also be shared under this license. @@ -26,15 +24,14 @@ All our content is created and shared under a [CC-BY 4.0 license](https://creati We would absolutely love your input on the following: -1. General feedback on our [Data Hazard Labels](data-hazards), which you can send to us through email or on [GitHub Discussions](https://github.com/very-good-science/data-hazards/discussions/new?category=feedback). +1. General feedback on our [Data Hazard Labels](labels), which you can send to us through [email][email] or as a [GitHub Issue][issues]. 2. Suggestions for new Data Hazard labels, or changes to them. For example you might suggest: - Ways of rewording Data Hazard label descriptions or titles. - New examples of Data Hazards. - New/updated "Safety Precautions" (ways of combatting Data Hazards). - Ideas for new Data Hazards. -3. Join one of [upcoming events](events) or (in development) asynchonous mailing lists to provide Data Hazards reviews on different projects. -4. Contribute to [any of our materials](materials) or share ideas for new materials to help others use the Hazards. +3. Contribute to [any of our materials](materials) or share ideas for new materials to help others use the Hazards. This could include: - Fixing a typo or a broken link. - Sharing a link to materials you have made. @@ -59,4 +56,5 @@ Check out our [Credit for contributions](contribue/../contribute/credit-for-cont --- [issues]: https://github.com/very-good-science/data-hazards/issues -[dec-email]: mailto:grp-ethicaldatascience@groups.bristol.ac.uk +[email]: mailto:data-hazards-project@bristol.ac.uk + diff --git a/_sources/contribute/contributors.md.txt b/_sources/contribute/contributors.md.txt new file mode 100644 index 0000000..41157d9 --- /dev/null +++ b/_sources/contribute/contributors.md.txt @@ -0,0 +1,125 @@ +# Record of contributions + +The Data Hazards project exists because of the support and contributions of the many different people below. +Please also note that people have also anonymously contributed ideas and resources to the project that Nina and Natalie have added on their behalf. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NatalieZelenka
NatalieZelenka

📆 🎨 🤔 📋 🚧 🚇 📖 🔬 💻
Nina
Nina

📆 🤔 📋 🚧 ️️️️♿️ 📖 🎨 🐛 🔬 💻
Conor Houghton
Conor Houghton

🔍
Valerio Maggio
Valerio Maggio

👀
Ismael-KG
Ismael-KG

📋 🤔 📢 📣 ️️️️♿️ 🔬
Kate Robson-Brown
Kate Robson-Brown

👀 📣
Patricia Holley
Patricia Holley

👀 📣
Lily Rice
Lily Rice

👀
ekuw
ekuw

👀
James Thomas
James Thomas

👀 📢 📣
Jakub Dakowski
Jakub Dakowski

💻
vairylein
vairylein

🎨 🤔 📣 🔬 📢
Holly Fraser
Holly Fraser

📓 💡
Gareth Jones
Gareth Jones

💻
Zoë Turner
Zoë Turner

🚧 🤔
Claire Haworth
Claire Haworth

📢 🔍 📣
Susana Roman Garcia
Susana Roman Garcia

💡 📢 🤔 📣 📋 🔬
Yasmin Dwiputri
Yasmin Dwiputri

🎨 🤔 📹
Huw Day
Huw Day

📋 💡 🤔 📣 🔬
Melanie I Stefan
Melanie I Stefan

🤔 📢 🔬
Euan Bennet
Euan Bennet

🔬 📢 📖
Emma Kuwertz
Emma Kuwertz

🔬 📢
Phil Clatworthy
Phil Clatworthy

🔬
SamCallaghan
SamCallaghan

📖
kateliddell
kateliddell

📖
Dylan246456
Dylan246456

📖
stefgrs
stefgrs

📖
Harriet Sands
Harriet Sands

📖
Joanne Parkes
Joanne Parkes

📖
loki maelorin
loki maelorin

📖
Mukilan Suresh
Mukilan Suresh

🤔
mcnanton
mcnanton

🐛
Emma Kuwertz
Emma Kuwertz

🔬 📢
CeilidhWelsh
CeilidhWelsh

📢 🔬 🤔
Oliver Davis
Oliver Davis

📢 📣
David C Sterratt
David C Sterratt

🔬 🤔
Nicola Romanò
Nicola Romanò

🔬 🤔
Léo Gorman
Léo Gorman

📢
Ben Cooper
Ben Cooper

📣 💻
JennyBunn
JennyBunn

📖
+ + + + + +This page is a place where anyone who has contributed to the project can be recognised for the time, effort and expertise they have given to Data Hazards. + +This page is based on a similar model used by [The Turing Way](https://github.com/alan-turing-institute/the-turing-way/blob/main/contributors.md) for recognising contributors to open source projects. + +We welcome anyone asking to be added to this page if they have made a contribution. +You can read about different ways to contribute to the project in our [contributors guide](how-to-contribute). +To be added, please [submit an issue](https://github.com/very-good-science/data-hazards/issues), make a pull request, or [send us an email](mailto:grp-ethicaldatascience@groups.bristol.ac.uk) which includes the following details: +* Your Name +* Your Role and Affiliation +* (Optional) ORCID ID or other persistent identifier +* (Optional) Personal contact details or website +* Overview of your contribution to the Data Hazards Project - please don't be modest! + + +## Contributors + + + +### Nina Di Cara +* Role: Co-PI +* ORCID [0000-0002-6179-1067](https://orcid.org/0000-0002-6179-1067) +* GitHub: [ninadicara](https://github.com/ninadicara) +> Along with Natalie I worked on the original idea for the Data Hazards, created resources around them (like teaching materials, slides, reflective prompts, illustrations), planned and delivered our workshops, and the website content. Jointly Natalie and I provide leadership for the project in terms of its next steps and uses. I care a lot about reducing the harm that technology can do to people who may not have power to fight back against, and hope this projects goes some way to making us all think more carefully about what we can all do as individuals to prevent harm. I am also thrilled to have been able to work with (and continue to work with) all the fantastic people who have got involved with this project! + + +### Natalie Zelenka +* Role: Co-PI +* ORCID: [0000-0002-1007-0286](https://orcid.org/0000-0002-1007-0286) +* GitHub: [NatalieZelenka](https://github.com/NatalieZelenka) +> As a co-lead of the Data Hazards project, I developed the idea for Data Hazards with Nina, wrote lesson materials and proposals and drafted papers, designed images, found funding, and did lots of planning. Me and Nina shared these leadership and organisational tasks 50-50, but we are so grateful for everyone's contributions and support so far. I hope that - like some of the work that I'm [most](https://the-turing-way.netlify.app/) [inspired](https://reproducibilitea.org/) [by](https://carpentries.org/) - these materials *reduce barriers* for researchers. In this case, I hope Data Hazards makes it easier for data scientists to consider the ethical implications of their work and to make those decisions together with the communities who are affected by the work they are doing. + +### Ismael Kherrouvi Garcia + +* Role: Workshop facilitator (and huge fan!) +* ORCID: [0000-0002-6850-8375](https://doi.org/0000-0002-6850-8375) +* Find me on :octocat: [Ismael-KG](https://github.com/Ismael-KG), and Twitter ([@hermeneuticist](https://twitter.com/hermeneuticist)) +> In September 2021, I was delighted to facilitate a workshop alongside [@NatalieZelenka](https://github.com/NatalieZelenka) and [@ninadicara](https://github.com/ninadicara) to [test the Data Hazard labels](https://www.bristol.ac.uk/golding/events/2021/data-hazards-workshop---21-september-2021.html) with researchers from diverse backgrounds. This meant working with Natalie and Nina to familiarise myself with [the prompts they had prepared](https://github.com/very-good-science/data-hazards/blob/ae2ecfad7f85fe48670ed6221a6563353d31e77b/images/worst-case-prompt.png), and then keeping the conversation flowing during breakout rooms with workshop participants. I had previously gathered feedback from The Alan Turing Institute's [Ethics Advisory Group](https://www.turing.ac.uk/research/data-ethics/ethics-advisory-group) (EAG) for the Data Hazard labels. My time with the Turing's EAG allowed me to appreciate the value of the Data Hazard labels, both in the context of training data scientists on questions of ethics, and for preparing documentation for the review of research ethics committees. + + +### Melanie I Stefan + +* Role: Early adopter +* ORCID: [0000-0002-6086-7357](https://orcid.org/my-orcid?orcid=0000-0002-6086-7357) +* GitHub: [MelanieIStefan](https://github.com/MelanieIStefan) +> I was introduced to Data Hazards by the wonderful [@Susana465](https://susana465.github.io/), and it has informed my thinking and practice ever since. I helped facilitate a workhop on Data Hazards at [COMBINE 2022 in Berlin](https://co.mbine.org/author/combine-2022/), and also talked about how I use the Data Hazards framework to flag up potential issues with my own lecture materials at the [Data Hazards, Ethics and Reproducibility One-Day Symposium](https://www.eventbrite.com/e/online-data-hazards-ethics-and-reproducibility-one-day-symposium-tickets-517490858087) at the Turing Institute in 2023. I am also involved in the discussion on the Data Hazards labels themselves. + +### Susana Roman Garcia + +* Role: Workshop facilitator, content developer of the Data Hazards application to different settings, especially Neuroscience, PhD case study application of Data Hazards +* ORCID ID: [0009-0004-6967-7754](https://orcid.org/0009-0004-6967-7754) +* [Personal website](https://susana465.github.io/website/) +> I came across the Data Hazards project as I looked for a way to embed thinking about ethics into my PhD, around 2021/22. Since then, I have attended a facilitator training workshop given by Nina and Natalie; and applied the Data Hazards framework to my PhD as I go along. To showcase this, I made a [poster presentation](https://github.com/Susana465/Bias-and-Reproducibility-Poster/blob/main/README.md) for the [COMBINE](https://combine-org.github.io/events/) and [ICSB](https://www.icsb2022.berlin/home) 2022 conferences. +>I have also facilitated a couple of Data Hazards workshops, information for how I prepared can be found here [Data_Hazards_workshops](https://github.com/Susana465/Data_Hazards_workshops). I have also co-organised and co-hosted a [one-day symposium around Data Hazards, Ethics and Reproducibility in 2023](https://github.com/Susana465/der_symposium_20230310). +> Likewise, I also worked with the Data Hazards team to create a [poster](https://github.com/Susana465/DH_Project_CaseStudy) for AI UK 2023, in which I showcased my PhD work for people at the conference to discuss what Data Hazard labels they thought applied. +> I have also worked on adding a chapter to the [Turing Way Booklet](https://the-turing-way.netlify.app/index.html) about Data Hazards, which is currently still in the process of being reviewed and published as of January 2024 (see info [here](https://github.com/the-turing-way/the-turing-way/pull/3435)). + diff --git a/_sources/contents/contribute/credit-for-contributions.md.txt b/_sources/contribute/credit-for-contributions.md.txt similarity index 100% rename from _sources/contents/contribute/credit-for-contributions.md.txt rename to _sources/contribute/credit-for-contributions.md.txt diff --git a/_sources/contents/contribute/how-to-contribute.md.txt b/_sources/contribute/how-to-contribute.md.txt similarity index 90% rename from _sources/contents/contribute/how-to-contribute.md.txt rename to _sources/contribute/how-to-contribute.md.txt index 3bc2210..0ce237f 100644 --- a/_sources/contents/contribute/how-to-contribute.md.txt +++ b/_sources/contribute/how-to-contribute.md.txt @@ -8,9 +8,8 @@ You can also come to our [open community co-working calls](../events/coworking) ## Suggesting new or improved Data Hazards -In the first instance please [start a Discussion with your idea](https://github.com/very-good-science/data-hazards/discussions/new?category=ideas) in the 'Ideas' category. +In the first instance [please start a new Issue with your idea][issues], and label it with the `data-hazard-ideas` category. We can then chat openly on GitHub about the suggestion, and this gives other people the opportunity to weigh-in on any changes we are considering. -Once changes have been agreed then you can follow the process below for making changes to the website. If you would rather you can also [email us][dh-email] to discuss. @@ -36,7 +35,7 @@ These require some Python packages to run. You may want to set up a [virtual environment](https://docs.python.org/3/library/venv.html) first, so that you don't install these packages system-wide. Then you can install the packages using `pip install -r requirements.txt` -## Adding slides + --- [issues]: https://github.com/very-good-science/data-hazards/issues diff --git a/_sources/contents/contribute/style-guide.md.txt b/_sources/contribute/style-guide.md.txt similarity index 100% rename from _sources/contents/contribute/style-guide.md.txt rename to _sources/contribute/style-guide.md.txt diff --git a/_sources/contents/events.md.txt b/_sources/events.md.txt similarity index 100% rename from _sources/contents/events.md.txt rename to _sources/events.md.txt diff --git a/_sources/contents/events/2021-09-21_workshop.md.txt b/_sources/events/2021-09-21_workshop.md.txt similarity index 100% rename from _sources/contents/events/2021-09-21_workshop.md.txt rename to _sources/events/2021-09-21_workshop.md.txt diff --git a/_sources/contents/events/bristol-tech-fest.md.txt b/_sources/events/bristol-tech-fest.md.txt similarity index 100% rename from _sources/contents/events/bristol-tech-fest.md.txt rename to _sources/events/bristol-tech-fest.md.txt diff --git a/_sources/contents/events/coworking.md.txt b/_sources/events/coworking.md.txt similarity index 100% rename from _sources/contents/events/coworking.md.txt rename to _sources/events/coworking.md.txt diff --git a/_sources/contents/events/jgi-showcase-events.md.txt b/_sources/events/jgi-showcase-events.md.txt similarity index 100% rename from _sources/contents/events/jgi-showcase-events.md.txt rename to _sources/events/jgi-showcase-events.md.txt diff --git a/_sources/contents/events/mozfest2022.md.txt b/_sources/events/mozfest2022.md.txt similarity index 100% rename from _sources/contents/events/mozfest2022.md.txt rename to _sources/events/mozfest2022.md.txt diff --git a/_sources/contents/hazards/automates-decision-making.md.txt b/_sources/hazards/automates-decision-making.md.txt similarity index 90% rename from _sources/contents/hazards/automates-decision-making.md.txt rename to _sources/hazards/automates-decision-making.md.txt index f86a0f4..82e7ee3 100644 --- a/_sources/contents/hazards/automates-decision-making.md.txt +++ b/_sources/hazards/automates-decision-making.md.txt @@ -1,7 +1,7 @@ # Hazard: Automates Decision Making -```{image} ../../images/hazards/automates-decision-making.png -:alt: A red diamond shaped outline (like a warning sign) with two connected cogs that have two arrows coming out of the top of them. +```{image} ../images/hazards/automates-decision-making.png +:alt: A red diamond shaped outline (like a warning sign) with two connected cogs that have arrows coming out of the top of them. :width: 250px ``` diff --git a/_sources/contents/hazards/danger-of-misuse.md.txt b/_sources/hazards/danger-of-misuse.md.txt similarity index 91% rename from _sources/contents/hazards/danger-of-misuse.md.txt rename to _sources/hazards/danger-of-misuse.md.txt index 9cad6d1..c19d833 100644 --- a/_sources/contents/hazards/danger-of-misuse.md.txt +++ b/_sources/hazards/danger-of-misuse.md.txt @@ -1,7 +1,7 @@ # Hazard: Danger Of Misuse -```{image} ../../images/hazards/misuse.png -:alt: A red diamond shaped outline (like a warning sign) with a hammer raised above a screw in the middle. +```{image} ../images/hazards/misuse.png +:alt: A red diamond shaped outline (like a warning sign) with a hammer raised above a bent screw in the middle. :width: 250px ``` diff --git a/_sources/contents/hazards/difficult-to-understand.md.txt b/_sources/hazards/difficult-to-understand.md.txt similarity index 97% rename from _sources/contents/hazards/difficult-to-understand.md.txt rename to _sources/hazards/difficult-to-understand.md.txt index 0646e74..ef2d3aa 100644 --- a/_sources/contents/hazards/difficult-to-understand.md.txt +++ b/_sources/hazards/difficult-to-understand.md.txt @@ -1,6 +1,6 @@ # Hazard: Difficult To Understand -```{image} ../../images/hazards/difficult-to-understand.png +```{image} ../images/hazards/difficult-to-understand.png :alt: A red diamond shaped outline (like a warning sign) with an image of a closed box and a question mark next to it. :width: 250px ``` diff --git a/_sources/contents/hazards/direct-harm.md.txt b/_sources/hazards/direct-harm.md.txt similarity index 96% rename from _sources/contents/hazards/direct-harm.md.txt rename to _sources/hazards/direct-harm.md.txt index 8187803..524f407 100644 --- a/_sources/contents/hazards/direct-harm.md.txt +++ b/_sources/hazards/direct-harm.md.txt @@ -1,6 +1,6 @@ # Hazard: May Cause Direct Harm -```{image} ../../images/hazards/direct-harm.png +```{image} ../images/hazards/direct-harm.png :alt: A red diamond shaped outline (like a warning sign) with a skull in the middle. :width: 250px ``` diff --git a/_sources/contents/hazards/general-hazard.md.txt b/_sources/hazards/general-hazard.md.txt similarity index 94% rename from _sources/contents/hazards/general-hazard.md.txt rename to _sources/hazards/general-hazard.md.txt index 392432c..365daa1 100644 --- a/_sources/contents/hazards/general-hazard.md.txt +++ b/_sources/hazards/general-hazard.md.txt @@ -1,6 +1,6 @@ # Hazard: General Data Hazard -```{image} ../../images/hazards/general-hazard.png +```{image} ../images/hazards/general-hazard.png :alt: A red diamond shaped outline (like a warning sign) with an exclamation mark in the middle. :width: 250px ``` diff --git a/_sources/contents/hazards/hazard-template.md.txt b/_sources/hazards/hazard-template.md.txt similarity index 81% rename from _sources/contents/hazards/hazard-template.md.txt rename to _sources/hazards/hazard-template.md.txt index 462c51f..9ea891f 100644 --- a/_sources/contents/hazards/hazard-template.md.txt +++ b/_sources/hazards/hazard-template.md.txt @@ -1,6 +1,6 @@ # Hazard: -```{image} ../../images/hazards/XX +```{image} ../images/hazards/XX :alt: A red diamond shaped outline (like a warning sign) with ..... :width: 250px ``` diff --git a/_sources/contents/hazards/high-environmental-cost.md.txt b/_sources/hazards/high-environmental-cost.md.txt similarity index 89% rename from _sources/contents/hazards/high-environmental-cost.md.txt rename to _sources/hazards/high-environmental-cost.md.txt index 8f5a412..563f582 100644 --- a/_sources/contents/hazards/high-environmental-cost.md.txt +++ b/_sources/hazards/high-environmental-cost.md.txt @@ -1,7 +1,7 @@ # Hazard: High Environmental Cost -```{image} ../../images/hazards/environment.png -:alt: A red diamond shaped outline (like a warning sign) with an image of a globe in the middle. +```{image} ../images/hazards/environment.png +:alt: A red diamond shaped outline (like a warning sign) with an image of a globe on fire in the middle. :width: 250px ``` diff --git a/_sources/contents/hazards/lacks-community-involvement.md.txt b/_sources/hazards/lacks-community-involvement.md.txt similarity index 92% rename from _sources/contents/hazards/lacks-community-involvement.md.txt rename to _sources/hazards/lacks-community-involvement.md.txt index 38b64ad..540afd5 100644 --- a/_sources/contents/hazards/lacks-community-involvement.md.txt +++ b/_sources/hazards/lacks-community-involvement.md.txt @@ -1,7 +1,7 @@ # Hazard: Lacks Community Involvement -```{image} ../../images/hazards/lacks-community.png -:alt: A red diamond shaped outline (like a warning sign) with figures in the middle who have empty speech bubbles above their heads. +```{image} ../images/hazards/lacks-community.png +:alt: A red diamond shaped outline (like a warning sign) with figures in the middle who have a speech bubble above their heads with a big cross through it. :width: 250px ``` diff --git a/_sources/contents/hazards/lacks-informed-consent.md.txt b/_sources/hazards/lacks-informed-consent.md.txt similarity index 81% rename from _sources/contents/hazards/lacks-informed-consent.md.txt rename to _sources/hazards/lacks-informed-consent.md.txt index 506f455..4738b31 100644 --- a/_sources/contents/hazards/lacks-informed-consent.md.txt +++ b/_sources/hazards/lacks-informed-consent.md.txt @@ -1,7 +1,7 @@ # Hazard: Lacks Informed Consent -```{image} ../../images/hazards/lacks-informed-consent.png -:alt: A red diamond shaped outline (like a warning sign) with an icon of a form in the middle. +```{image} ../images/hazards/lacks-informed-consent.png +:alt: A red diamond shaped outline (like a warning sign) containing a magnifying glass hovering over a cross on a piece of paper. :width: 250px ``` diff --git a/_sources/contents/hazards/ranks-classifies.md.txt b/_sources/hazards/ranks-classifies.md.txt similarity index 89% rename from _sources/contents/hazards/ranks-classifies.md.txt rename to _sources/hazards/ranks-classifies.md.txt index 6527582..7fc319d 100644 --- a/_sources/contents/hazards/ranks-classifies.md.txt +++ b/_sources/hazards/ranks-classifies.md.txt @@ -1,7 +1,7 @@ # Hazard: Ranks Or Classifies People -```{image} ../../images/hazards/classifies-people.png -:alt: A red diamond shaped outline (like a warning sign) with a set of weighing scales in the middle, and a person sitting on each side of the scale. +```{image} ../images/hazards/classifies-people.png +:alt: A red diamond shaped outline (like a warning sign) with three people standing on a podium of first, second and third place. :width: 250px ``` diff --git a/_sources/contents/hazards/reinforces-biases.md.txt b/_sources/hazards/reinforces-biases.md.txt similarity index 76% rename from _sources/contents/hazards/reinforces-biases.md.txt rename to _sources/hazards/reinforces-biases.md.txt index 437c383..6159a74 100644 --- a/_sources/contents/hazards/reinforces-biases.md.txt +++ b/_sources/hazards/reinforces-biases.md.txt @@ -1,7 +1,7 @@ # Hazard: Reinforces Existing Biases -```{image} ../../images/hazards/reinforce-bias.png -:alt: A red diamond shaped outline (like a warning sign) around two arrows pointing to each other in a circle. +```{image} ../images/hazards/reinforce-bias.png +:alt: A red diamond shaped outline (like a warning sign) with a dark head and shoulders, who has a white triangle in their mind. They are looking out at a black circle, a black square and a larger white triangle just ahead of them. This indicates that the largest shape is the one that they think of. :width: 250px ``` @@ -9,7 +9,7 @@ Reinforces unfair treatment of individuals and groups. This may be due to for example input data, algorithm or software design choices, or society at large. -__Note:__ this is a hazard in it's own right, even if it isn't then used to harm people directly, due to e.g. reinforcing stereotypes. +__Note:__ this is a Hazard in it's own right, even if it isn't then used to harm people directly, due to e.g. reinforcing stereotypes. ## Examples diff --git a/_sources/contents/hazards/risk-to-privacy.md.txt b/_sources/hazards/risk-to-privacy.md.txt similarity index 94% rename from _sources/contents/hazards/risk-to-privacy.md.txt rename to _sources/hazards/risk-to-privacy.md.txt index ce09f0f..cff557f 100644 --- a/_sources/contents/hazards/risk-to-privacy.md.txt +++ b/_sources/hazards/risk-to-privacy.md.txt @@ -1,6 +1,6 @@ # Hazard: Risk To Privacy -```{image} ../../images/hazards/privacy.png +```{image} ../images/hazards/privacy.png :alt: A red diamond shaped outline (like a warning sign) with a picture of a surveillance camera in the middle. :width: 250px ``` diff --git a/_sources/index.md.txt b/_sources/index.md.txt index b640e1a..8d0ab6f 100644 --- a/_sources/index.md.txt +++ b/_sources/index.md.txt @@ -1,59 +1,98 @@ # The Data Hazards Project -[//]: # (TODO: Include all alt text) - -
- -Data Hazards is a project about worst-case scenarios of data science. +Data Hazards is a project to help us all identify the hazards of using data science. Data scientists are great at selling our work, for example communicating the gains in efficiency and accuracy, but we are less well-practiced in thinking about the ethical implications of our work. The ethical implications go beyond most ethics Institutional Review Boards, to questions about the wider societal impact of data science and algorithms work. -### Aims -We aim to __create resources__ to: -1. Create a shared vocabulary of Data Hazards in the form of [Data Hazard Labels](contents/data-hazards). -2. Make ethical and future-thinking more accessible to data scientists, computer scientists and applied mathematicians - to apply to their own work. -3. Enable bringing together and respecting diverse and interdisciplinary viewpoints to this work, through workshops or mailing lists. -4. Find out what circumstances, and for who, these resources work best. - -### How -To support our aims we will: -1. Get feedback on our [Data Hazard labels](contents/data-hazards), to develop them with the communities who will be using them. -2. Create resources that help data scientists reflect on their own work, by creating prompts, frameworks, and forms for them to consider. -3. Run workshops and mailing lists where data scientists can listen to diverse perspectives and grow their ideas of what is possible, and where interdisciplinary researchers and the public can both be heard, respected, and listened to by the people who are doing computational and mathematical work. -4. Listen to our community's feedback through surveys. - -```{admonition} Why are the Hazard Labels so scary-looking? -We know that the [Data Hazards labels](contents/data-hazards) are a bit frightening. Argh, there's a skull! -Please know that __we don't want these labels to scare anyone away from considering ethics or from doing data science__, and we will do everything that we can to make applying Data Hazards labels as welcoming and approachable as possible, but also have some good reasons for choosing these images. - -We chose this format because of the similarity to [COSHH hazard labels](https://www.hse.gov.uk/chemical-classification/labelling-packaging/hazard-symbols-hazard-pictograms.htm) - hazard labels for chemicals. -We made this choice because we want a similar response from people: -1. Attention-grabbing, asking people to stop and think, and take the safety precautions seriously, rather than as an optional extra. -2. We're asking people to "handle with care", not to stop doing the work. We still use chemicals, but we think about how it can be done safely and how to avoid emergencies. -3. They are familiar, especially to scientists, who (within universities) tend to have the least experience of applying ethics. - +```{admonition} Project Aims +1. Create a __community-driven open-source vocabulary__ of ethical hazards for data-intensive research and development, in the form of [Data Hazard labels](contents/data-hazards). +2. Make ethical and future-thinking __more accessible__ to data scientists, computer scientists and applied mathematicians to apply to their own work. +3. Enable bringing together and respecting __diverse and interdisciplinary viewpoints__ to this work, and produce resources to do this. +4. Find out in what circumstances, and for who, these resources work best. ``` +## Contributors + +Our brilliant contributors are listed here, and you can [read more detail about our contributing process here](contribute). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NatalieZelenka
NatalieZelenka

📆 🎨 🤔 📋 🚧 🚇 📖 🔬 💻
Nina
Nina

📆 🤔 📋 🚧 ️️️️♿️ 📖 🎨 🐛 🔬 💻
Conor Houghton
Conor Houghton

🔍
Valerio Maggio
Valerio Maggio

👀
Ismael-KG
Ismael-KG

📋 🤔 📢 📣 ️️️️♿️ 🔬
Kate Robson-Brown
Kate Robson-Brown

👀 📣
Patricia Holley
Patricia Holley

👀 📣
Lily Rice
Lily Rice

👀
ekuw
ekuw

👀
James Thomas
James Thomas

👀 📢 📣
Jakub Dakowski
Jakub Dakowski

💻
vairylein
vairylein

🎨 🤔 📣 🔬 📢
Holly Fraser
Holly Fraser

📓 💡
Gareth Jones
Gareth Jones

💻
Zoë Turner
Zoë Turner

🚧 🤔
Claire Haworth
Claire Haworth

📢 🔍 📣
Susana Roman Garcia
Susana Roman Garcia

💡 📢 🤔 📣 📋 🔬
Yasmin Dwiputri
Yasmin Dwiputri

🎨 🤔 📹
Huw Day
Huw Day

📋 💡 🤔 📣 🔬
Melanie I Stefan
Melanie I Stefan

🤔 📢 🔬
Euan Bennet
Euan Bennet

🔬 📢 📖
Emma Kuwertz
Emma Kuwertz

🔬 📢
Phil Clatworthy
Phil Clatworthy

🔬
SamCallaghan
SamCallaghan

📖
kateliddell
kateliddell

📖
Dylan246456
Dylan246456

📖
stefgrs
stefgrs

📖
Harriet Sands
Harriet Sands

📖
Joanne Parkes
Joanne Parkes

📖
loki maelorin
loki maelorin

📖
Mukilan Suresh
Mukilan Suresh

🤔
mcnanton
mcnanton

🐛
Emma Kuwertz
Emma Kuwertz

🔬 📢
CeilidhWelsh
CeilidhWelsh

📢 🔬 🤔
Oliver Davis
Oliver Davis

📢 📣
David C Sterratt
David C Sterratt

🔬 🤔
Nicola Romanò
Nicola Romanò

🔬 🤔
Léo Gorman
Léo Gorman

📢
Ben Cooper
Ben Cooper

📣 💻
JennyBunn
JennyBunn

📖
+ + + + ```{toctree} :maxdepth: 2 :hidden: -contents/data-hazards -contents/about -contents/materials -contents/contribute -contents/contact +labels +about +materials +contribute ``` + +:::::{grid} 1 2 3 3 +:margin: 4 4 0 0 +:gutter: 2 + +::::{grid-item-card} General Data Hazard +:img-top: images/hazards/general-hazard.png +:img-alt: A red diamond shaped outline (like a warning sign) with an exclamation mark in the middle. +:link: /hazards/general-hazard +:link-type: doc + +Data Science is being used in this output, and any negative outcome of using this work are not the fault of "the algorithm" or "the software". +:::: + +::::{grid-item-card} Automates Decision Making +:img-top: /images/hazards/automates-decision-making.png +:img-alt: A red diamond shaped outline (like a warning sign) with two connected cogs that have arrows coming out of the top of them. +:link: hazards/automates-decision-making +:link-type: doc + +Automated decision making can be hazardous for a number of reasons, and these will be highly dependent on the field in which it is being applied. +:::: + +::::{grid-item-card} Danger Of Misuse +:img-top: /images/hazards/misuse.png +:img-alt: A red diamond shaped outline (like a warning sign) with a hammer raised above a bent screw in the middle. +:link: hazards/danger-of-misuse +:link-type: doc + +There is a danger of misusing the algorithm, technology, or data collected as part of this work. +:::: + +::::{grid-item-card} Difficult to Understand +:img-top: /images/hazards/difficult-to-understand.png +:img-alt: A red diamond shaped outline (like a warning sign) with an image of a closed box and a question mark next to it. +:link: hazards/difficult-to-understand +:link-type: doc + +This may apply if the technology itself is hard to interpret (e.g. neural nets), or documentation is poor/unavailable. +:::: + +::::{grid-item-card} High Environmental Cost +:img-top: images/hazards/environment.png +:img-alt: A red diamond shaped outline (like a warning sign) with an image of a globe on fire in the middle. +:link: hazards/high-environmental-cost +:link-type: doc + +Indicates methodologies that are energy-hungry, data-hungry, or require special hardware with rare materials. +:::: + +::::{grid-item-card} Lacks Community Involvement +:img-top: /images/hazards/lacks-community.png +:img-alt: A red diamond shaped outline (like a warning sign) with figures in the middle who have a speech bubble above their heads with a big cross through it. +:link: hazards/lacks-community-involvement +:link-type: doc + +This applies when technology is being produced without input from the community it is supposed to serve. +:::: + +::::{grid-item-card} Lacks Informed Consent +:img-top: /images/hazards/lacks-informed-consent.png +:img-alt: A red diamond shaped outline (like a warning sign) containing a magnifying glass hovering over a cross on a piece of paper. +:link: hazards/lacks-informed-consent +:link-type: doc + +This hazard applies to datasets or algorithms that use data which has not been provided with the explicit consent of the data owner/creator. +:::: + +::::{grid-item-card} May Cause Direct Harm +:img-top: /images/hazards/direct-harm.png +:img-alt: A red diamond shaped outline (like a warning sign) with a skull in the middle. +:link: hazards/direct-harm +:link-type: doc + +The application area of this technology means that it is capable of causing direct physical or psychological harm to someone even if used correctly. +:::: + +::::{grid-item-card} Ranks Or Classifies People +:img-top: images/hazards/classifies-people.png +:img-alt: A red diamond shaped outline (like a warning sign) with three people standing on a podium of first, second and third place. +:link: hazards/ranks-classifies +:link-type: doc + +Ranking and classifications of people are hazards in their own right and should be handled with care. +:::: + +::::{grid-item-card} Reinforces Existing Biases +:img-top: images/hazards/reinforce-bias.png +:img-alt: A red diamond shaped outline (like a warning sign) with a dark head and shoulders, who has a white triangle in their mind. They are looking out at a black circle, a black square and a larger white triangle just ahead of them. This indicates that the largest shape is the one that they think of. +:link: hazards/reinforces-biases +:link-type: doc + +Reinforces unfair treatment of individuals and groups. This may be due to for example input data, algorithm or software design choices, or society at large. +:::: + +::::{grid-item-card} Risk to Privacy +:img-top: /images/hazards/privacy.png +:img-alt: A red diamond shaped outline (like a warning sign) with a picture of a surveillance camera in the middle. +:link: hazards/risk-to-privacy +:link-type: doc + +This technology may risk the privacy of individuals whose data is processed by it. +:::: + +::::: + + +## Future development + +Suggestions for future versions of the Data Hazard labels are curated as GitHub Issues. [Click here to see the current suggestions.](https://github.com/very-good-science/data-hazards/labels/hazard-label-idea) + + +## Change log + +The change log records when changes that have been made to the project and gives a brief description of what the changes were. +The change log started in March 2022. +The most recent changes should be at the top of the list. + + + +__29.05.2024: Put labels in alphabetical order__ +[@ninadicara](https://github.com/ninadicara) + + +__06.12.2022: Update new Hazard labels__ +[@ninadicara](https://github.com/ninadicara) +Updated all the images of the Hazards with our new labels designed by the amazing [Yasmin Dwiputri](http://yasmindwiputri.com/)! + + +__07.03.2022: Move Data Hazards to individual pages__ +[@ninadicara](https://github.com/ninadicara) +Moved all of the Hazards to their own individual pages, and linked them from the original sphinx panels. +Also capitalised all of the names so that they are consistently named. +This should make it easier for people to contribute to a single Hazard and record their contribution against it :) + + + diff --git a/_sources/contents/materials.md.txt b/_sources/materials.md.txt similarity index 86% rename from _sources/contents/materials.md.txt rename to _sources/materials.md.txt index 1b94d95..0f4d773 100644 --- a/_sources/contents/materials.md.txt +++ b/_sources/materials.md.txt @@ -12,15 +12,16 @@ materials/teaching materials/self-assessment materials/presenting materials/examples +materials/mitigation-resources ``` -On this page you will find materials we have made to help people to use or apply the [Data Hazard labels](data-hazards). +On this page you will find materials we have made to help people to use or apply the [Data Hazard labels](labels). This includes a workshop format, a teaching/lecture based format, and an asychronous format which can be adapted to just be an individual exercise. You are welcome to use any of the materials we share here, which (like all of our content) are available to use with a [CC-BY 4.0 license](https://creativecommons.org/licenses/by/4.0/). This means, roughly, they can be re-used and adapted as long as you credit this repository. -We are currently developing all these materials so please do get in touch with us through the [Contact](contact) tab above if you have any thoughts or examples of how you have used the materials! +We are currently developing all these materials so please do [get in touch with us](about) if you have any thoughts or examples of how you have used the materials! Alternatively if you have changes in mind that you would like to make then check out [How to contribute](contribute) - we always welcome new contributors! diff --git a/_sources/contents/materials/examples.md.txt b/_sources/materials/examples.md.txt similarity index 100% rename from _sources/contents/materials/examples.md.txt rename to _sources/materials/examples.md.txt diff --git a/_sources/contents/materials/misc/geno_to_pheno_example.md.txt b/_sources/materials/misc/geno_to_pheno_example.md.txt similarity index 100% rename from _sources/contents/materials/misc/geno_to_pheno_example.md.txt rename to _sources/materials/misc/geno_to_pheno_example.md.txt diff --git a/_sources/contents/materials/misc/proposal.md.txt b/_sources/materials/misc/proposal.md.txt similarity index 100% rename from _sources/contents/materials/misc/proposal.md.txt rename to _sources/materials/misc/proposal.md.txt diff --git a/_sources/contents/materials/misc/workshop-21092021.md.txt b/_sources/materials/misc/workshop-21092021.md.txt similarity index 100% rename from _sources/contents/materials/misc/workshop-21092021.md.txt rename to _sources/materials/misc/workshop-21092021.md.txt diff --git a/_sources/contents/mitigation-resources.md.txt b/_sources/materials/mitigation-resources.md.txt similarity index 100% rename from _sources/contents/mitigation-resources.md.txt rename to _sources/materials/mitigation-resources.md.txt diff --git a/_sources/contents/materials/presenting.md.txt b/_sources/materials/presenting.md.txt similarity index 100% rename from _sources/contents/materials/presenting.md.txt rename to _sources/materials/presenting.md.txt diff --git a/_sources/contents/materials/seedcorn.md.txt b/_sources/materials/seedcorn.md.txt similarity index 100% rename from _sources/contents/materials/seedcorn.md.txt rename to _sources/materials/seedcorn.md.txt diff --git a/_sources/contents/materials/self-assessment.md.txt b/_sources/materials/self-assessment.md.txt similarity index 100% rename from _sources/contents/materials/self-assessment.md.txt rename to _sources/materials/self-assessment.md.txt diff --git a/_sources/contents/materials/teaching.md.txt b/_sources/materials/teaching.md.txt similarity index 97% rename from _sources/contents/materials/teaching.md.txt rename to _sources/materials/teaching.md.txt index e957651..7df58ce 100644 --- a/_sources/contents/materials/teaching.md.txt +++ b/_sources/materials/teaching.md.txt @@ -18,12 +18,6 @@ We suggest starting with a 10-15 minute presentation to introduce the Data Hazar The lecturer should then present a case study that the students can discuss in small groups. Prior to the discussion, students should have the opportunity to ask clarifying questions about the project. -We provided a summary page for students too, to use during the seminar. -```{toctree} -:maxdepth: 1 -teaching/students -``` - ## Timings 17:00 - 17:05 - Settling in diff --git a/_sources/contents/materials/workshop.md.txt b/_sources/materials/workshop.md.txt similarity index 94% rename from _sources/contents/materials/workshop.md.txt rename to _sources/materials/workshop.md.txt index 6f2dbb0..b0bfcac 100644 --- a/_sources/contents/materials/workshop.md.txt +++ b/_sources/materials/workshop.md.txt @@ -4,7 +4,7 @@ The Data Hazards were originally designed around a workshop format. This was to allow a series of _Project Owners_ to present a research project to _Audience Members_, who would give them feedback on the ethics of their project. This could be in any context, like a team meeting, a seminar or a scoping exercise. -You can [download a printable set of Data Hazards cards here](../../_static/DataHazards_PrintableCards.pdf). +You can [download a printable set of Data Hazards cards here](../_static/DataHazards_PrintableCards.pdf). 'click')\n event = event.replace(stripNameRegex, '');\n return customEvents[event] || event;\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false);\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true);\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return;\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);\n const inNamespace = typeEvent !== originalTypeEvent;\n const events = getElementEvents(element);\n const storeElementEvent = events[typeEvent] || {};\n const isNamespace = originalTypeEvent.startsWith('.');\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return;\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null);\n return;\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1));\n }\n }\n\n for (const keyHandlers of Object.keys(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '');\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n const event = storeElementEvent[keyHandlers];\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null;\n }\n\n const $ = getjQuery();\n const typeEvent = getTypeEvent(event);\n const inNamespace = event !== typeEvent;\n let jQueryEvent = null;\n let bubbles = true;\n let nativeDispatch = true;\n let defaultPrevented = false;\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args);\n $(element).trigger(jQueryEvent);\n bubbles = !jQueryEvent.isPropagationStopped();\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();\n defaultPrevented = jQueryEvent.isDefaultPrevented();\n }\n\n let evt = new Event(event, {\n bubbles,\n cancelable: true\n });\n evt = hydrateObj(evt, args);\n\n if (defaultPrevented) {\n evt.preventDefault();\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt);\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault();\n }\n\n return evt;\n }\n\n};\n\nfunction hydrateObj(obj, meta) {\n for (const [key, value] of Object.entries(meta || {})) {\n try {\n obj[key] = value;\n } catch (_unused) {\n Object.defineProperty(obj, key, {\n configurable: true,\n\n get() {\n return value;\n }\n\n });\n }\n }\n\n return obj;\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\nconst elementMap = new Map();\nconst Data = {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map());\n }\n\n const instanceMap = elementMap.get(element); // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`);\n return;\n }\n\n instanceMap.set(key, instance);\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null;\n }\n\n return null;\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return;\n }\n\n const instanceMap = elementMap.get(element);\n instanceMap.delete(key); // free up element references if there are no instances left for an element\n\n if (instanceMap.size === 0) {\n elementMap.delete(element);\n }\n }\n\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\nfunction normalizeData(value) {\n if (value === 'true') {\n return true;\n }\n\n if (value === 'false') {\n return false;\n }\n\n if (value === Number(value).toString()) {\n return Number(value);\n }\n\n if (value === '' || value === 'null') {\n return null;\n }\n\n if (typeof value !== 'string') {\n return value;\n }\n\n try {\n return JSON.parse(decodeURIComponent(value));\n } catch (_unused) {\n return value;\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`);\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value);\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`);\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {};\n }\n\n const attributes = {};\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'));\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '');\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length);\n attributes[pureKey] = normalizeData(element.dataset[key]);\n }\n\n return attributes;\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`));\n }\n\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {};\n }\n\n static get DefaultType() {\n return {};\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!');\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config);\n config = this._configAfterMerge(config);\n\n this._typeCheckConfig(config);\n\n return config;\n }\n\n _configAfterMerge(config) {\n return config;\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse\n\n return { ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n };\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const property of Object.keys(configTypes)) {\n const expectedTypes = configTypes[property];\n const value = config[property];\n const valueType = isElement(value) ? 'element' : toType(value);\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`);\n }\n }\n }\n\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst VERSION = '5.2.3';\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super();\n element = getElement(element);\n\n if (!element) {\n return;\n }\n\n this._element = element;\n this._config = this._getConfig(config);\n Data.set(this._element, this.constructor.DATA_KEY, this);\n } // Public\n\n\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY);\n EventHandler.off(this._element, this.constructor.EVENT_KEY);\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null;\n }\n }\n\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated);\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element);\n config = this._configAfterMerge(config);\n\n this._typeCheckConfig(config);\n\n return config;\n } // Static\n\n\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY);\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null);\n }\n\n static get VERSION() {\n return VERSION;\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`;\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`;\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`;\n }\n\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`;\n const name = component.NAME;\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n\n if (isDisabled(this)) {\n return;\n }\n\n const target = getElementFromSelector(this) || this.closest(`.${name}`);\n const instance = component.getOrCreateInstance(target); // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n\n instance[method]();\n });\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$f = 'alert';\nconst DATA_KEY$a = 'bs.alert';\nconst EVENT_KEY$b = `.${DATA_KEY$a}`;\nconst EVENT_CLOSE = `close${EVENT_KEY$b}`;\nconst EVENT_CLOSED = `closed${EVENT_KEY$b}`;\nconst CLASS_NAME_FADE$5 = 'fade';\nconst CLASS_NAME_SHOW$8 = 'show';\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME$f;\n } // Public\n\n\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE);\n\n if (closeEvent.defaultPrevented) {\n return;\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW$8);\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE$5);\n\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated);\n } // Private\n\n\n _destroyElement() {\n this._element.remove();\n\n EventHandler.trigger(this._element, EVENT_CLOSED);\n this.dispose();\n } // Static\n\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this);\n\n if (typeof config !== 'string') {\n return;\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n\n data[config](this);\n });\n }\n\n}\n/**\n * Data API implementation\n */\n\n\nenableDismissTrigger(Alert, 'close');\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$e = 'button';\nconst DATA_KEY$9 = 'bs.button';\nconst EVENT_KEY$a = `.${DATA_KEY$9}`;\nconst DATA_API_KEY$6 = '.data-api';\nconst CLASS_NAME_ACTIVE$3 = 'active';\nconst SELECTOR_DATA_TOGGLE$5 = '[data-bs-toggle=\"button\"]';\nconst EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`;\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME$e;\n } // Public\n\n\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE$3));\n } // Static\n\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this);\n\n if (config === 'toggle') {\n data[config]();\n }\n });\n }\n\n}\n/**\n * Data API implementation\n */\n\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event => {\n event.preventDefault();\n const button = event.target.closest(SELECTOR_DATA_TOGGLE$5);\n const data = Button.getOrCreateInstance(button);\n data.toggle();\n});\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector));\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector);\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector));\n },\n\n parents(element, selector) {\n const parents = [];\n let ancestor = element.parentNode.closest(selector);\n\n while (ancestor) {\n parents.push(ancestor);\n ancestor = ancestor.parentNode.closest(selector);\n }\n\n return parents;\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling;\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous];\n }\n\n previous = previous.previousElementSibling;\n }\n\n return [];\n },\n\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling;\n\n while (next) {\n if (next.matches(selector)) {\n return [next];\n }\n\n next = next.nextElementSibling;\n }\n\n return [];\n },\n\n focusableChildren(element) {\n const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable=\"true\"]'].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',');\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el));\n }\n\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$d = 'swipe';\nconst EVENT_KEY$9 = '.bs.swipe';\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY$9}`;\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$9}`;\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY$9}`;\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$9}`;\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY$9}`;\nconst POINTER_TYPE_TOUCH = 'touch';\nconst POINTER_TYPE_PEN = 'pen';\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event';\nconst SWIPE_THRESHOLD = 40;\nconst Default$c = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n};\nconst DefaultType$c = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n};\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super();\n this._element = element;\n\n if (!element || !Swipe.isSupported()) {\n return;\n }\n\n this._config = this._getConfig(config);\n this._deltaX = 0;\n this._supportPointerEvents = Boolean(window.PointerEvent);\n\n this._initEvents();\n } // Getters\n\n\n static get Default() {\n return Default$c;\n }\n\n static get DefaultType() {\n return DefaultType$c;\n }\n\n static get NAME() {\n return NAME$d;\n } // Public\n\n\n dispose() {\n EventHandler.off(this._element, EVENT_KEY$9);\n } // Private\n\n\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX;\n return;\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX;\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX;\n }\n\n this._handleSwipe();\n\n execute(this._config.endCallback);\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this._deltaX;\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX);\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return;\n }\n\n const direction = absDeltaX / this._deltaX;\n this._deltaX = 0;\n\n if (!direction) {\n return;\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback);\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event));\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event));\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT);\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event));\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event));\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event));\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH);\n } // Static\n\n\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;\n }\n\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$c = 'carousel';\nconst DATA_KEY$8 = 'bs.carousel';\nconst EVENT_KEY$8 = `.${DATA_KEY$8}`;\nconst DATA_API_KEY$5 = '.data-api';\nconst ARROW_LEFT_KEY$1 = 'ArrowLeft';\nconst ARROW_RIGHT_KEY$1 = 'ArrowRight';\nconst TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next';\nconst ORDER_PREV = 'prev';\nconst DIRECTION_LEFT = 'left';\nconst DIRECTION_RIGHT = 'right';\nconst EVENT_SLIDE = `slide${EVENT_KEY$8}`;\nconst EVENT_SLID = `slid${EVENT_KEY$8}`;\nconst EVENT_KEYDOWN$1 = `keydown${EVENT_KEY$8}`;\nconst EVENT_MOUSEENTER$1 = `mouseenter${EVENT_KEY$8}`;\nconst EVENT_MOUSELEAVE$1 = `mouseleave${EVENT_KEY$8}`;\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY$8}`;\nconst EVENT_LOAD_DATA_API$3 = `load${EVENT_KEY$8}${DATA_API_KEY$5}`;\nconst EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$8}${DATA_API_KEY$5}`;\nconst CLASS_NAME_CAROUSEL = 'carousel';\nconst CLASS_NAME_ACTIVE$2 = 'active';\nconst CLASS_NAME_SLIDE = 'slide';\nconst CLASS_NAME_END = 'carousel-item-end';\nconst CLASS_NAME_START = 'carousel-item-start';\nconst CLASS_NAME_NEXT = 'carousel-item-next';\nconst CLASS_NAME_PREV = 'carousel-item-prev';\nconst SELECTOR_ACTIVE = '.active';\nconst SELECTOR_ITEM = '.carousel-item';\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM;\nconst SELECTOR_ITEM_IMG = '.carousel-item img';\nconst SELECTOR_INDICATORS = '.carousel-indicators';\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]';\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]';\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY$1]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY$1]: DIRECTION_LEFT\n};\nconst Default$b = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n};\nconst DefaultType$b = {\n interval: '(number|boolean)',\n // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n};\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._interval = null;\n this._activeElement = null;\n this._isSliding = false;\n this.touchTimeout = null;\n this._swipeHelper = null;\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element);\n\n this._addEventListeners();\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle();\n }\n } // Getters\n\n\n static get Default() {\n return Default$b;\n }\n\n static get DefaultType() {\n return DefaultType$b;\n }\n\n static get NAME() {\n return NAME$c;\n } // Public\n\n\n next() {\n this._slide(ORDER_NEXT);\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next();\n }\n }\n\n prev() {\n this._slide(ORDER_PREV);\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element);\n }\n\n this._clearInterval();\n }\n\n cycle() {\n this._clearInterval();\n\n this._updateInterval();\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval);\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return;\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle());\n return;\n }\n\n this.cycle();\n }\n\n to(index) {\n const items = this._getItems();\n\n if (index > items.length - 1 || index < 0) {\n return;\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index));\n return;\n }\n\n const activeIndex = this._getItemIndex(this._getActive());\n\n if (activeIndex === index) {\n return;\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV;\n\n this._slide(order, items[index]);\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose();\n }\n\n super.dispose();\n } // Private\n\n\n _configAfterMerge(config) {\n config.defaultInterval = config.interval;\n return config;\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN$1, event => this._keydown(event));\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER$1, () => this.pause());\n EventHandler.on(this._element, EVENT_MOUSELEAVE$1, () => this._maybeEnableCycle());\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners();\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault());\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return;\n } // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n\n this.pause();\n\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout);\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval);\n };\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n };\n this._swipeHelper = new Swipe(this._element, swipeConfig);\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return;\n }\n\n const direction = KEY_TO_DIRECTION[event.key];\n\n if (direction) {\n event.preventDefault();\n\n this._slide(this._directionToOrder(direction));\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element);\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return;\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement);\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE$2);\n activeIndicator.removeAttribute('aria-current');\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement);\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE$2);\n newActiveIndicator.setAttribute('aria-current', 'true');\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive();\n\n if (!element) {\n return;\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10);\n this._config.interval = elementInterval || this._config.defaultInterval;\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return;\n }\n\n const activeElement = this._getActive();\n\n const isNext = order === ORDER_NEXT;\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap);\n\n if (nextElement === activeElement) {\n return;\n }\n\n const nextElementIndex = this._getItemIndex(nextElement);\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n });\n };\n\n const slideEvent = triggerEvent(EVENT_SLIDE);\n\n if (slideEvent.defaultPrevented) {\n return;\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // todo: change tests that use empty divs to avoid this check\n return;\n }\n\n const isCycling = Boolean(this._interval);\n this.pause();\n this._isSliding = true;\n\n this._setActiveIndicatorElement(nextElementIndex);\n\n this._activeElement = nextElement;\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END;\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV;\n nextElement.classList.add(orderClassName);\n reflow(nextElement);\n activeElement.classList.add(directionalClassName);\n nextElement.classList.add(directionalClassName);\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName);\n nextElement.classList.add(CLASS_NAME_ACTIVE$2);\n activeElement.classList.remove(CLASS_NAME_ACTIVE$2, orderClassName, directionalClassName);\n this._isSliding = false;\n triggerEvent(EVENT_SLID);\n };\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated());\n\n if (isCycling) {\n this.cycle();\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE);\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element);\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element);\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval);\n this._interval = null;\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT;\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV;\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT;\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;\n } // Static\n\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config);\n\n if (typeof config === 'number') {\n data.to(config);\n return;\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n\n data[config]();\n }\n });\n }\n\n}\n/**\n * Data API implementation\n */\n\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_SLIDE, function (event) {\n const target = getElementFromSelector(this);\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return;\n }\n\n event.preventDefault();\n const carousel = Carousel.getOrCreateInstance(target);\n const slideIndex = this.getAttribute('data-bs-slide-to');\n\n if (slideIndex) {\n carousel.to(slideIndex);\n\n carousel._maybeEnableCycle();\n\n return;\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next();\n\n carousel._maybeEnableCycle();\n\n return;\n }\n\n carousel.prev();\n\n carousel._maybeEnableCycle();\n});\nEventHandler.on(window, EVENT_LOAD_DATA_API$3, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE);\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel);\n }\n});\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$b = 'collapse';\nconst DATA_KEY$7 = 'bs.collapse';\nconst EVENT_KEY$7 = `.${DATA_KEY$7}`;\nconst DATA_API_KEY$4 = '.data-api';\nconst EVENT_SHOW$6 = `show${EVENT_KEY$7}`;\nconst EVENT_SHOWN$6 = `shown${EVENT_KEY$7}`;\nconst EVENT_HIDE$6 = `hide${EVENT_KEY$7}`;\nconst EVENT_HIDDEN$6 = `hidden${EVENT_KEY$7}`;\nconst EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$7}${DATA_API_KEY$4}`;\nconst CLASS_NAME_SHOW$7 = 'show';\nconst CLASS_NAME_COLLAPSE = 'collapse';\nconst CLASS_NAME_COLLAPSING = 'collapsing';\nconst CLASS_NAME_COLLAPSED = 'collapsed';\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`;\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal';\nconst WIDTH = 'width';\nconst HEIGHT = 'height';\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing';\nconst SELECTOR_DATA_TOGGLE$4 = '[data-bs-toggle=\"collapse\"]';\nconst Default$a = {\n parent: null,\n toggle: true\n};\nconst DefaultType$a = {\n parent: '(null|element)',\n toggle: 'boolean'\n};\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._isTransitioning = false;\n this._triggerArray = [];\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$4);\n\n for (const elem of toggleList) {\n const selector = getSelectorFromElement(elem);\n const filterElement = SelectorEngine.find(selector).filter(foundElement => foundElement === this._element);\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem);\n }\n }\n\n this._initializeChildren();\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown());\n }\n\n if (this._config.toggle) {\n this.toggle();\n }\n } // Getters\n\n\n static get Default() {\n return Default$a;\n }\n\n static get DefaultType() {\n return DefaultType$a;\n }\n\n static get NAME() {\n return NAME$b;\n } // Public\n\n\n toggle() {\n if (this._isShown()) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return;\n }\n\n let activeChildren = []; // find active children\n\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES).filter(element => element !== this._element).map(element => Collapse.getOrCreateInstance(element, {\n toggle: false\n }));\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return;\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW$6);\n\n if (startEvent.defaultPrevented) {\n return;\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide();\n }\n\n const dimension = this._getDimension();\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE);\n\n this._element.classList.add(CLASS_NAME_COLLAPSING);\n\n this._element.style[dimension] = 0;\n\n this._addAriaAndCollapsedClass(this._triggerArray, true);\n\n this._isTransitioning = true;\n\n const complete = () => {\n this._isTransitioning = false;\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING);\n\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);\n\n this._element.style[dimension] = '';\n EventHandler.trigger(this._element, EVENT_SHOWN$6);\n };\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);\n const scrollSize = `scroll${capitalizedDimension}`;\n\n this._queueCallback(complete, this._element, true);\n\n this._element.style[dimension] = `${this._element[scrollSize]}px`;\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return;\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE$6);\n\n if (startEvent.defaultPrevented) {\n return;\n }\n\n const dimension = this._getDimension();\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`;\n reflow(this._element);\n\n this._element.classList.add(CLASS_NAME_COLLAPSING);\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);\n\n for (const trigger of this._triggerArray) {\n const element = getElementFromSelector(trigger);\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false);\n }\n }\n\n this._isTransitioning = true;\n\n const complete = () => {\n this._isTransitioning = false;\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING);\n\n this._element.classList.add(CLASS_NAME_COLLAPSE);\n\n EventHandler.trigger(this._element, EVENT_HIDDEN$6);\n };\n\n this._element.style[dimension] = '';\n\n this._queueCallback(complete, this._element, true);\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW$7);\n } // Private\n\n\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle); // Coerce string values\n\n config.parent = getElement(config.parent);\n return config;\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT;\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return;\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE$4);\n\n for (const element of children) {\n const selected = getElementFromSelector(element);\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected));\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent); // remove children if greater depth\n\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element));\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return;\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen);\n element.setAttribute('aria-expanded', isOpen);\n }\n } // Static\n\n\n static jQueryInterface(config) {\n const _config = {};\n\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false;\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config);\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n\n data[config]();\n }\n });\n }\n\n}\n/**\n * Data API implementation\n */\n\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, function (event) {\n // preventDefault only for elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') {\n event.preventDefault();\n }\n\n const selector = getSelectorFromElement(this);\n const selectorElements = SelectorEngine.find(selector);\n\n for (const element of selectorElements) {\n Collapse.getOrCreateInstance(element, {\n toggle: false\n }).toggle();\n }\n});\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$a = 'dropdown';\nconst DATA_KEY$6 = 'bs.dropdown';\nconst EVENT_KEY$6 = `.${DATA_KEY$6}`;\nconst DATA_API_KEY$3 = '.data-api';\nconst ESCAPE_KEY$2 = 'Escape';\nconst TAB_KEY$1 = 'Tab';\nconst ARROW_UP_KEY$1 = 'ArrowUp';\nconst ARROW_DOWN_KEY$1 = 'ArrowDown';\nconst RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE$5 = `hide${EVENT_KEY$6}`;\nconst EVENT_HIDDEN$5 = `hidden${EVENT_KEY$6}`;\nconst EVENT_SHOW$5 = `show${EVENT_KEY$6}`;\nconst EVENT_SHOWN$5 = `shown${EVENT_KEY$6}`;\nconst EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst CLASS_NAME_SHOW$6 = 'show';\nconst CLASS_NAME_DROPUP = 'dropup';\nconst CLASS_NAME_DROPEND = 'dropend';\nconst CLASS_NAME_DROPSTART = 'dropstart';\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center';\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center';\nconst SELECTOR_DATA_TOGGLE$3 = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)';\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE$3}.${CLASS_NAME_SHOW$6}`;\nconst SELECTOR_MENU = '.dropdown-menu';\nconst SELECTOR_NAVBAR = '.navbar';\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav';\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start';\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end';\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start';\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end';\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start';\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start';\nconst PLACEMENT_TOPCENTER = 'top';\nconst PLACEMENT_BOTTOMCENTER = 'bottom';\nconst Default$9 = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n};\nconst DefaultType$9 = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n};\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._popper = null;\n this._parent = this._element.parentNode; // dropdown wrapper\n // todo: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.2/forms/input-group/\n\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] || SelectorEngine.findOne(SELECTOR_MENU, this._parent);\n this._inNavbar = this._detectNavbar();\n } // Getters\n\n\n static get Default() {\n return Default$9;\n }\n\n static get DefaultType() {\n return DefaultType$9;\n }\n\n static get NAME() {\n return NAME$a;\n } // Public\n\n\n toggle() {\n return this._isShown() ? this.hide() : this.show();\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return;\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n };\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$5, relatedTarget);\n\n if (showEvent.defaultPrevented) {\n return;\n }\n\n this._createPopper(); // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop);\n }\n }\n\n this._element.focus();\n\n this._element.setAttribute('aria-expanded', true);\n\n this._menu.classList.add(CLASS_NAME_SHOW$6);\n\n this._element.classList.add(CLASS_NAME_SHOW$6);\n\n EventHandler.trigger(this._element, EVENT_SHOWN$5, relatedTarget);\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return;\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n };\n\n this._completeHide(relatedTarget);\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy();\n }\n\n super.dispose();\n }\n\n update() {\n this._inNavbar = this._detectNavbar();\n\n if (this._popper) {\n this._popper.update();\n }\n } // Private\n\n\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$5, relatedTarget);\n\n if (hideEvent.defaultPrevented) {\n return;\n } // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n\n\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop);\n }\n }\n\n if (this._popper) {\n this._popper.destroy();\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW$6);\n\n this._element.classList.remove(CLASS_NAME_SHOW$6);\n\n this._element.setAttribute('aria-expanded', 'false');\n\n Manipulator.removeDataAttribute(this._menu, 'popper');\n EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget);\n }\n\n _getConfig(config) {\n config = super._getConfig(config);\n\n if (typeof config.reference === 'object' && !isElement(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME$a.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`);\n }\n\n return config;\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)');\n }\n\n let referenceElement = this._element;\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent;\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference);\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference;\n }\n\n const popperConfig = this._getPopperConfig();\n\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig);\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW$6);\n }\n\n _getPlacement() {\n const parentDropdown = this._parent;\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT;\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT;\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER;\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER;\n } // We need to trim the value because custom properties can also include spaces\n\n\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end';\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP;\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM;\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null;\n }\n\n _getOffset() {\n const {\n offset\n } = this._config;\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10));\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element);\n }\n\n return offset;\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n }, {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }; // Disable Popper if we have a static display or Dropdown is in Navbar\n\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static'); // todo:v6 remove\n\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }];\n }\n\n return { ...defaultBsPopperConfig,\n ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)\n };\n }\n\n _selectMenuItem({\n key,\n target\n }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element));\n\n if (!items.length) {\n return;\n } // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n\n\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus();\n } // Static\n\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config);\n\n if (typeof config !== 'string') {\n return;\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n\n data[config]();\n });\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) {\n return;\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN);\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle);\n\n if (!context || context._config.autoClose === false) {\n continue;\n }\n\n const composedPath = event.composedPath();\n const isMenuTarget = composedPath.includes(context._menu);\n\n if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) {\n continue;\n } // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n\n\n if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue;\n }\n\n const relatedTarget = {\n relatedTarget: context._element\n };\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event;\n }\n\n context._completeHide(relatedTarget);\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n const isInput = /input|textarea/i.test(event.target.tagName);\n const isEscapeEvent = event.key === ESCAPE_KEY$2;\n const isUpOrDownEvent = [ARROW_UP_KEY$1, ARROW_DOWN_KEY$1].includes(event.key);\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return;\n }\n\n if (isInput && !isEscapeEvent) {\n return;\n }\n\n event.preventDefault(); // todo: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.2/forms/input-group/\n\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE$3) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE$3, event.delegateTarget.parentNode);\n const instance = Dropdown.getOrCreateInstance(getToggleButton);\n\n if (isUpOrDownEvent) {\n event.stopPropagation();\n instance.show();\n\n instance._selectMenuItem(event);\n\n return;\n }\n\n if (instance._isShown()) {\n // else is escape and we check if it is shown\n event.stopPropagation();\n instance.hide();\n getToggleButton.focus();\n }\n }\n\n}\n/**\n * Data API implementation\n */\n\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$3, Dropdown.dataApiKeydownHandler);\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler);\nEventHandler.on(document, EVENT_CLICK_DATA_API$3, Dropdown.clearMenus);\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus);\nEventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) {\n event.preventDefault();\n Dropdown.getOrCreateInstance(this).toggle();\n});\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';\nconst SELECTOR_STICKY_CONTENT = '.sticky-top';\nconst PROPERTY_PADDING = 'padding-right';\nconst PROPERTY_MARGIN = 'margin-right';\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body;\n } // Public\n\n\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth;\n return Math.abs(window.innerWidth - documentWidth);\n }\n\n hide() {\n const width = this.getWidth();\n\n this._disableOverFlow(); // give padding to element to balance the hidden scrollbar width\n\n\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n\n\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width);\n\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width);\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow');\n\n this._resetElementAttributes(this._element, PROPERTY_PADDING);\n\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING);\n\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN);\n }\n\n isOverflowing() {\n return this.getWidth() > 0;\n } // Private\n\n\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow');\n\n this._element.style.overflow = 'hidden';\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth();\n\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return;\n }\n\n this._saveInitialAttribute(element, styleProperty);\n\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty);\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`);\n };\n\n this._applyManipulationCallback(selector, manipulationCallBack);\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty);\n\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue);\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty); // We only want to remove the property if the value is `null`; the value can also be zero\n\n if (value === null) {\n element.style.removeProperty(styleProperty);\n return;\n }\n\n Manipulator.removeDataAttribute(element, styleProperty);\n element.style.setProperty(styleProperty, value);\n };\n\n this._applyManipulationCallback(selector, manipulationCallBack);\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector);\n return;\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel);\n }\n }\n\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$9 = 'backdrop';\nconst CLASS_NAME_FADE$4 = 'fade';\nconst CLASS_NAME_SHOW$5 = 'show';\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME$9}`;\nconst Default$8 = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true,\n // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n\n};\nconst DefaultType$8 = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n};\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n this._isAppended = false;\n this._element = null;\n } // Getters\n\n\n static get Default() {\n return Default$8;\n }\n\n static get DefaultType() {\n return DefaultType$8;\n }\n\n static get NAME() {\n return NAME$9;\n } // Public\n\n\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback);\n return;\n }\n\n this._append();\n\n const element = this._getElement();\n\n if (this._config.isAnimated) {\n reflow(element);\n }\n\n element.classList.add(CLASS_NAME_SHOW$5);\n\n this._emulateAnimation(() => {\n execute(callback);\n });\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback);\n return;\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW$5);\n\n this._emulateAnimation(() => {\n this.dispose();\n execute(callback);\n });\n }\n\n dispose() {\n if (!this._isAppended) {\n return;\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN);\n\n this._element.remove();\n\n this._isAppended = false;\n } // Private\n\n\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div');\n backdrop.className = this._config.className;\n\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE$4);\n }\n\n this._element = backdrop;\n }\n\n return this._element;\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement);\n return config;\n }\n\n _append() {\n if (this._isAppended) {\n return;\n }\n\n const element = this._getElement();\n\n this._config.rootElement.append(element);\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback);\n });\n this._isAppended = true;\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated);\n }\n\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$8 = 'focustrap';\nconst DATA_KEY$5 = 'bs.focustrap';\nconst EVENT_KEY$5 = `.${DATA_KEY$5}`;\nconst EVENT_FOCUSIN$2 = `focusin${EVENT_KEY$5}`;\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$5}`;\nconst TAB_KEY = 'Tab';\nconst TAB_NAV_FORWARD = 'forward';\nconst TAB_NAV_BACKWARD = 'backward';\nconst Default$7 = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n\n};\nconst DefaultType$7 = {\n autofocus: 'boolean',\n trapElement: 'element'\n};\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n this._isActive = false;\n this._lastTabNavDirection = null;\n } // Getters\n\n\n static get Default() {\n return Default$7;\n }\n\n static get DefaultType() {\n return DefaultType$7;\n }\n\n static get NAME() {\n return NAME$8;\n } // Public\n\n\n activate() {\n if (this._isActive) {\n return;\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus();\n }\n\n EventHandler.off(document, EVENT_KEY$5); // guard against infinite focus loop\n\n EventHandler.on(document, EVENT_FOCUSIN$2, event => this._handleFocusin(event));\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));\n this._isActive = true;\n }\n\n deactivate() {\n if (!this._isActive) {\n return;\n }\n\n this._isActive = false;\n EventHandler.off(document, EVENT_KEY$5);\n } // Private\n\n\n _handleFocusin(event) {\n const {\n trapElement\n } = this._config;\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return;\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement);\n\n if (elements.length === 0) {\n trapElement.focus();\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus();\n } else {\n elements[0].focus();\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return;\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;\n }\n\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$7 = 'modal';\nconst DATA_KEY$4 = 'bs.modal';\nconst EVENT_KEY$4 = `.${DATA_KEY$4}`;\nconst DATA_API_KEY$2 = '.data-api';\nconst ESCAPE_KEY$1 = 'Escape';\nconst EVENT_HIDE$4 = `hide${EVENT_KEY$4}`;\nconst EVENT_HIDE_PREVENTED$1 = `hidePrevented${EVENT_KEY$4}`;\nconst EVENT_HIDDEN$4 = `hidden${EVENT_KEY$4}`;\nconst EVENT_SHOW$4 = `show${EVENT_KEY$4}`;\nconst EVENT_SHOWN$4 = `shown${EVENT_KEY$4}`;\nconst EVENT_RESIZE$1 = `resize${EVENT_KEY$4}`;\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$4}`;\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$4}`;\nconst EVENT_KEYDOWN_DISMISS$1 = `keydown.dismiss${EVENT_KEY$4}`;\nconst EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$4}${DATA_API_KEY$2}`;\nconst CLASS_NAME_OPEN = 'modal-open';\nconst CLASS_NAME_FADE$3 = 'fade';\nconst CLASS_NAME_SHOW$4 = 'show';\nconst CLASS_NAME_STATIC = 'modal-static';\nconst OPEN_SELECTOR$1 = '.modal.show';\nconst SELECTOR_DIALOG = '.modal-dialog';\nconst SELECTOR_MODAL_BODY = '.modal-body';\nconst SELECTOR_DATA_TOGGLE$2 = '[data-bs-toggle=\"modal\"]';\nconst Default$6 = {\n backdrop: true,\n focus: true,\n keyboard: true\n};\nconst DefaultType$6 = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n};\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element);\n this._backdrop = this._initializeBackDrop();\n this._focustrap = this._initializeFocusTrap();\n this._isShown = false;\n this._isTransitioning = false;\n this._scrollBar = new ScrollBarHelper();\n\n this._addEventListeners();\n } // Getters\n\n\n static get Default() {\n return Default$6;\n }\n\n static get DefaultType() {\n return DefaultType$6;\n }\n\n static get NAME() {\n return NAME$7;\n } // Public\n\n\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget);\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return;\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$4, {\n relatedTarget\n });\n\n if (showEvent.defaultPrevented) {\n return;\n }\n\n this._isShown = true;\n this._isTransitioning = true;\n\n this._scrollBar.hide();\n\n document.body.classList.add(CLASS_NAME_OPEN);\n\n this._adjustDialog();\n\n this._backdrop.show(() => this._showElement(relatedTarget));\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return;\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$4);\n\n if (hideEvent.defaultPrevented) {\n return;\n }\n\n this._isShown = false;\n this._isTransitioning = true;\n\n this._focustrap.deactivate();\n\n this._element.classList.remove(CLASS_NAME_SHOW$4);\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated());\n }\n\n dispose() {\n for (const htmlElement of [window, this._dialog]) {\n EventHandler.off(htmlElement, EVENT_KEY$4);\n }\n\n this._backdrop.dispose();\n\n this._focustrap.deactivate();\n\n super.dispose();\n }\n\n handleUpdate() {\n this._adjustDialog();\n } // Private\n\n\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop),\n // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n });\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n });\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element);\n }\n\n this._element.style.display = 'block';\n\n this._element.removeAttribute('aria-hidden');\n\n this._element.setAttribute('aria-modal', true);\n\n this._element.setAttribute('role', 'dialog');\n\n this._element.scrollTop = 0;\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog);\n\n if (modalBody) {\n modalBody.scrollTop = 0;\n }\n\n reflow(this._element);\n\n this._element.classList.add(CLASS_NAME_SHOW$4);\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate();\n }\n\n this._isTransitioning = false;\n EventHandler.trigger(this._element, EVENT_SHOWN$4, {\n relatedTarget\n });\n };\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated());\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS$1, event => {\n if (event.key !== ESCAPE_KEY$1) {\n return;\n }\n\n if (this._config.keyboard) {\n event.preventDefault();\n this.hide();\n return;\n }\n\n this._triggerBackdropTransition();\n });\n EventHandler.on(window, EVENT_RESIZE$1, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog();\n }\n });\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return;\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition();\n\n return;\n }\n\n if (this._config.backdrop) {\n this.hide();\n }\n });\n });\n }\n\n _hideModal() {\n this._element.style.display = 'none';\n\n this._element.setAttribute('aria-hidden', true);\n\n this._element.removeAttribute('aria-modal');\n\n this._element.removeAttribute('role');\n\n this._isTransitioning = false;\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN);\n\n this._resetAdjustments();\n\n this._scrollBar.reset();\n\n EventHandler.trigger(this._element, EVENT_HIDDEN$4);\n });\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE$3);\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED$1);\n\n if (hideEvent.defaultPrevented) {\n return;\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n const initialOverflowY = this._element.style.overflowY; // return if the following background transition hasn't yet completed\n\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return;\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden';\n }\n\n this._element.classList.add(CLASS_NAME_STATIC);\n\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC);\n\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY;\n }, this._dialog);\n }, this._dialog);\n\n this._element.focus();\n }\n /**\n * The following methods are used to handle overflowing modals\n */\n\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n\n const scrollbarWidth = this._scrollBar.getWidth();\n\n const isBodyOverflowing = scrollbarWidth > 0;\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight';\n this._element.style[property] = `${scrollbarWidth}px`;\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft';\n this._element.style[property] = `${scrollbarWidth}px`;\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = '';\n this._element.style.paddingRight = '';\n } // Static\n\n\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config);\n\n if (typeof config !== 'string') {\n return;\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n\n data[config](relatedTarget);\n });\n }\n\n}\n/**\n * Data API implementation\n */\n\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) {\n const target = getElementFromSelector(this);\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n\n EventHandler.one(target, EVENT_SHOW$4, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return;\n }\n\n EventHandler.one(target, EVENT_HIDDEN$4, () => {\n if (isVisible(this)) {\n this.focus();\n }\n });\n }); // avoid conflict when clicking modal toggler while another one is open\n\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR$1);\n\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide();\n }\n\n const data = Modal.getOrCreateInstance(target);\n data.toggle(this);\n});\nenableDismissTrigger(Modal);\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$6 = 'offcanvas';\nconst DATA_KEY$3 = 'bs.offcanvas';\nconst EVENT_KEY$3 = `.${DATA_KEY$3}`;\nconst DATA_API_KEY$1 = '.data-api';\nconst EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$3}${DATA_API_KEY$1}`;\nconst ESCAPE_KEY = 'Escape';\nconst CLASS_NAME_SHOW$3 = 'show';\nconst CLASS_NAME_SHOWING$1 = 'showing';\nconst CLASS_NAME_HIDING = 'hiding';\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop';\nconst OPEN_SELECTOR = '.offcanvas.show';\nconst EVENT_SHOW$3 = `show${EVENT_KEY$3}`;\nconst EVENT_SHOWN$3 = `shown${EVENT_KEY$3}`;\nconst EVENT_HIDE$3 = `hide${EVENT_KEY$3}`;\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$3}`;\nconst EVENT_HIDDEN$3 = `hidden${EVENT_KEY$3}`;\nconst EVENT_RESIZE = `resize${EVENT_KEY$3}`;\nconst EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$3}${DATA_API_KEY$1}`;\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$3}`;\nconst SELECTOR_DATA_TOGGLE$1 = '[data-bs-toggle=\"offcanvas\"]';\nconst Default$5 = {\n backdrop: true,\n keyboard: true,\n scroll: false\n};\nconst DefaultType$5 = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n};\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._isShown = false;\n this._backdrop = this._initializeBackDrop();\n this._focustrap = this._initializeFocusTrap();\n\n this._addEventListeners();\n } // Getters\n\n\n static get Default() {\n return Default$5;\n }\n\n static get DefaultType() {\n return DefaultType$5;\n }\n\n static get NAME() {\n return NAME$6;\n } // Public\n\n\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget);\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return;\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$3, {\n relatedTarget\n });\n\n if (showEvent.defaultPrevented) {\n return;\n }\n\n this._isShown = true;\n\n this._backdrop.show();\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide();\n }\n\n this._element.setAttribute('aria-modal', true);\n\n this._element.setAttribute('role', 'dialog');\n\n this._element.classList.add(CLASS_NAME_SHOWING$1);\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate();\n }\n\n this._element.classList.add(CLASS_NAME_SHOW$3);\n\n this._element.classList.remove(CLASS_NAME_SHOWING$1);\n\n EventHandler.trigger(this._element, EVENT_SHOWN$3, {\n relatedTarget\n });\n };\n\n this._queueCallback(completeCallBack, this._element, true);\n }\n\n hide() {\n if (!this._isShown) {\n return;\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$3);\n\n if (hideEvent.defaultPrevented) {\n return;\n }\n\n this._focustrap.deactivate();\n\n this._element.blur();\n\n this._isShown = false;\n\n this._element.classList.add(CLASS_NAME_HIDING);\n\n this._backdrop.hide();\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW$3, CLASS_NAME_HIDING);\n\n this._element.removeAttribute('aria-modal');\n\n this._element.removeAttribute('role');\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset();\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN$3);\n };\n\n this._queueCallback(completeCallback, this._element, true);\n }\n\n dispose() {\n this._backdrop.dispose();\n\n this._focustrap.deactivate();\n\n super.dispose();\n } // Private\n\n\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);\n return;\n }\n\n this.hide();\n }; // 'static' option will be translated to true, and booleans will keep their value\n\n\n const isVisible = Boolean(this._config.backdrop);\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n });\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n });\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return;\n }\n\n if (!this._config.keyboard) {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);\n return;\n }\n\n this.hide();\n });\n } // Static\n\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config);\n\n if (typeof config !== 'string') {\n return;\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n\n data[config](this);\n });\n }\n\n}\n/**\n * Data API implementation\n */\n\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) {\n const target = getElementFromSelector(this);\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n\n if (isDisabled(this)) {\n return;\n }\n\n EventHandler.one(target, EVENT_HIDDEN$3, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus();\n }\n }); // avoid conflict when clicking a toggler of an offcanvas, while another is open\n\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR);\n\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide();\n }\n\n const data = Offcanvas.getOrCreateInstance(target);\n data.toggle(this);\n});\nEventHandler.on(window, EVENT_LOAD_DATA_API$2, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show();\n }\n});\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide();\n }\n }\n});\nenableDismissTrigger(Offcanvas);\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\nconst uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i;\n/**\n * A pattern that recognizes a commonly useful subset of URLs that are safe.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\n */\n\nconst SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i;\n/**\n * A pattern that matches safe data URLs. Only matches image, video and audio types.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\n */\n\nconst DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[\\d+/a-z]+=*$/i;\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase();\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue));\n }\n\n return true;\n } // Check if a regular expression validates the attribute.\n\n\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));\n};\n\nconst DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n div: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n};\nfunction sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml;\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml);\n }\n\n const domParser = new window.DOMParser();\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'));\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase();\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove();\n continue;\n }\n\n const attributeList = [].concat(...element.attributes);\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName);\n }\n }\n }\n\n return createdDocument.body.innerHTML;\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$5 = 'TemplateFactory';\nconst Default$4 = {\n allowList: DefaultAllowlist,\n content: {},\n // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '
'\n};\nconst DefaultType$4 = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n};\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n};\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n } // Getters\n\n\n static get Default() {\n return Default$4;\n }\n\n static get DefaultType() {\n return DefaultType$4;\n }\n\n static get NAME() {\n return NAME$5;\n } // Public\n\n\n getContent() {\n return Object.values(this._config.content).map(config => this._resolvePossibleFunction(config)).filter(Boolean);\n }\n\n hasContent() {\n return this.getContent().length > 0;\n }\n\n changeContent(content) {\n this._checkContent(content);\n\n this._config.content = { ...this._config.content,\n ...content\n };\n return this;\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div');\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template);\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector);\n }\n\n const template = templateWrapper.children[0];\n\n const extraClass = this._resolvePossibleFunction(this._config.extraClass);\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '));\n }\n\n return template;\n } // Private\n\n\n _typeCheckConfig(config) {\n super._typeCheckConfig(config);\n\n this._checkContent(config.content);\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({\n selector,\n entry: content\n }, DefaultContentType);\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template);\n\n if (!templateElement) {\n return;\n }\n\n content = this._resolvePossibleFunction(content);\n\n if (!content) {\n templateElement.remove();\n return;\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement);\n\n return;\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content);\n return;\n }\n\n templateElement.textContent = content;\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg;\n }\n\n _resolvePossibleFunction(arg) {\n return typeof arg === 'function' ? arg(this) : arg;\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = '';\n templateElement.append(element);\n return;\n }\n\n templateElement.textContent = element.textContent;\n }\n\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$4 = 'tooltip';\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']);\nconst CLASS_NAME_FADE$2 = 'fade';\nconst CLASS_NAME_MODAL = 'modal';\nconst CLASS_NAME_SHOW$2 = 'show';\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner';\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`;\nconst EVENT_MODAL_HIDE = 'hide.bs.modal';\nconst TRIGGER_HOVER = 'hover';\nconst TRIGGER_FOCUS = 'focus';\nconst TRIGGER_CLICK = 'click';\nconst TRIGGER_MANUAL = 'manual';\nconst EVENT_HIDE$2 = 'hide';\nconst EVENT_HIDDEN$2 = 'hidden';\nconst EVENT_SHOW$2 = 'show';\nconst EVENT_SHOWN$2 = 'shown';\nconst EVENT_INSERTED = 'inserted';\nconst EVENT_CLICK$1 = 'click';\nconst EVENT_FOCUSIN$1 = 'focusin';\nconst EVENT_FOCUSOUT$1 = 'focusout';\nconst EVENT_MOUSEENTER = 'mouseenter';\nconst EVENT_MOUSELEAVE = 'mouseleave';\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n};\nconst Default$3 = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 0],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '
' + '
' + '
' + '
',\n title: '',\n trigger: 'hover focus'\n};\nconst DefaultType$3 = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n};\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)');\n }\n\n super(element, config); // Private\n\n this._isEnabled = true;\n this._timeout = 0;\n this._isHovered = null;\n this._activeTrigger = {};\n this._popper = null;\n this._templateFactory = null;\n this._newContent = null; // Protected\n\n this.tip = null;\n\n this._setListeners();\n\n if (!this._config.selector) {\n this._fixTitle();\n }\n } // Getters\n\n\n static get Default() {\n return Default$3;\n }\n\n static get DefaultType() {\n return DefaultType$3;\n }\n\n static get NAME() {\n return NAME$4;\n } // Public\n\n\n enable() {\n this._isEnabled = true;\n }\n\n disable() {\n this._isEnabled = false;\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled;\n }\n\n toggle() {\n if (!this._isEnabled) {\n return;\n }\n\n this._activeTrigger.click = !this._activeTrigger.click;\n\n if (this._isShown()) {\n this._leave();\n\n return;\n }\n\n this._enter();\n }\n\n dispose() {\n clearTimeout(this._timeout);\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'));\n }\n\n this._disposePopper();\n\n super.dispose();\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements');\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return;\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW$2));\n const shadowRoot = findShadowRoot(this._element);\n\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element);\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return;\n } // todo v6 remove this OR make it optional\n\n\n this._disposePopper();\n\n const tip = this._getTipElement();\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'));\n\n const {\n container\n } = this._config;\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip);\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED));\n }\n\n this._popper = this._createPopper(tip);\n tip.classList.add(CLASS_NAME_SHOW$2); // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop);\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN$2));\n\n if (this._isHovered === false) {\n this._leave();\n }\n\n this._isHovered = false;\n };\n\n this._queueCallback(complete, this.tip, this._isAnimated());\n }\n\n hide() {\n if (!this._isShown()) {\n return;\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE$2));\n\n if (hideEvent.defaultPrevented) {\n return;\n }\n\n const tip = this._getTipElement();\n\n tip.classList.remove(CLASS_NAME_SHOW$2); // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop);\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false;\n this._activeTrigger[TRIGGER_FOCUS] = false;\n this._activeTrigger[TRIGGER_HOVER] = false;\n this._isHovered = null; // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return;\n }\n\n if (!this._isHovered) {\n this._disposePopper();\n }\n\n this._element.removeAttribute('aria-describedby');\n\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN$2));\n };\n\n this._queueCallback(complete, this.tip, this._isAnimated());\n }\n\n update() {\n if (this._popper) {\n this._popper.update();\n }\n } // Protected\n\n\n _isWithContent() {\n return Boolean(this._getTitle());\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate());\n }\n\n return this.tip;\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml(); // todo: remove this check on v6\n\n\n if (!tip) {\n return null;\n }\n\n tip.classList.remove(CLASS_NAME_FADE$2, CLASS_NAME_SHOW$2); // todo: on v6 the following can be achieved with CSS only\n\n tip.classList.add(`bs-${this.constructor.NAME}-auto`);\n const tipId = getUID(this.constructor.NAME).toString();\n tip.setAttribute('id', tipId);\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE$2);\n }\n\n return tip;\n }\n\n setContent(content) {\n this._newContent = content;\n\n if (this._isShown()) {\n this._disposePopper();\n\n this.show();\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content);\n } else {\n this._templateFactory = new TemplateFactory({ ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n });\n }\n\n return this._templateFactory;\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n };\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title');\n } // Private\n\n\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig());\n }\n\n _isAnimated() {\n return this._config.animation || this.tip && this.tip.classList.contains(CLASS_NAME_FADE$2);\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW$2);\n }\n\n _createPopper(tip) {\n const placement = typeof this._config.placement === 'function' ? this._config.placement.call(this, tip, this._element) : this._config.placement;\n const attachment = AttachmentMap[placement.toUpperCase()];\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment));\n }\n\n _getOffset() {\n const {\n offset\n } = this._config;\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10));\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element);\n }\n\n return offset;\n }\n\n _resolvePossibleFunction(arg) {\n return typeof arg === 'function' ? arg.call(this._element) : arg;\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [{\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n }, {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }, {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n }, {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n }, {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement);\n }\n }]\n };\n return { ...defaultBsPopperConfig,\n ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)\n };\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ');\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$1), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n\n context.toggle();\n });\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSEENTER) : this.constructor.eventName(EVENT_FOCUSIN$1);\n const eventOut = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSELEAVE) : this.constructor.eventName(EVENT_FOCUSOUT$1);\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true;\n\n context._enter();\n });\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget);\n\n context._leave();\n });\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide();\n }\n };\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title');\n\n if (!title) {\n return;\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title);\n }\n\n this._element.setAttribute('data-bs-original-title', title); // DO NOT USE IT. Is only for backwards compatibility\n\n\n this._element.removeAttribute('title');\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true;\n return;\n }\n\n this._isHovered = true;\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show();\n }\n }, this._config.delay.show);\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return;\n }\n\n this._isHovered = false;\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide();\n }\n }, this._config.delay.hide);\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout);\n this._timeout = setTimeout(handler, timeout);\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true);\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element);\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute];\n }\n }\n\n config = { ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n };\n config = this._mergeConfigObj(config);\n config = this._configAfterMerge(config);\n\n this._typeCheckConfig(config);\n\n return config;\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container);\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n };\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString();\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString();\n }\n\n return config;\n }\n\n _getDelegateConfig() {\n const config = {};\n\n for (const key in this._config) {\n if (this.constructor.Default[key] !== this._config[key]) {\n config[key] = this._config[key];\n }\n }\n\n config.selector = false;\n config.trigger = 'manual'; // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n\n return config;\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy();\n\n this._popper = null;\n }\n\n if (this.tip) {\n this.tip.remove();\n this.tip = null;\n }\n } // Static\n\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config);\n\n if (typeof config !== 'string') {\n return;\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n\n data[config]();\n });\n }\n\n}\n/**\n * jQuery\n */\n\n\ndefineJQueryPlugin(Tooltip);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$3 = 'popover';\nconst SELECTOR_TITLE = '.popover-header';\nconst SELECTOR_CONTENT = '.popover-body';\nconst Default$2 = { ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '
' + '
' + '

' + '
' + '
',\n trigger: 'click'\n};\nconst DefaultType$2 = { ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n};\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default$2;\n }\n\n static get DefaultType() {\n return DefaultType$2;\n }\n\n static get NAME() {\n return NAME$3;\n } // Overrides\n\n\n _isWithContent() {\n return this._getTitle() || this._getContent();\n } // Private\n\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n };\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content);\n } // Static\n\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config);\n\n if (typeof config !== 'string') {\n return;\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n\n data[config]();\n });\n }\n\n}\n/**\n * jQuery\n */\n\n\ndefineJQueryPlugin(Popover);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.2.3): scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n/**\n * Constants\n */\n\nconst NAME$2 = 'scrollspy';\nconst DATA_KEY$2 = 'bs.scrollspy';\nconst EVENT_KEY$2 = `.${DATA_KEY$2}`;\nconst DATA_API_KEY = '.data-api';\nconst EVENT_ACTIVATE = `activate${EVENT_KEY$2}`;\nconst EVENT_CLICK = `click${EVENT_KEY$2}`;\nconst EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$2}${DATA_API_KEY}`;\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';\nconst CLASS_NAME_ACTIVE$1 = 'active';\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]';\nconst SELECTOR_TARGET_LINKS = '[href]';\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';\nconst SELECTOR_NAV_LINKS = '.nav-link';\nconst SELECTOR_NAV_ITEMS = '.nav-item';\nconst SELECTOR_LIST_ITEMS = '.list-group-item';\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`;\nconst SELECTOR_DROPDOWN = '.dropdown';\nconst SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle';\nconst Default$1 = {\n offset: null,\n // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n};\nconst DefaultType$1 = {\n offset: '(number|null)',\n // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n};\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config); // this._element is the observablesContainer and config.target the menu links wrapper\n\n this._targetLinks = new Map();\n this._observableSections = new Map();\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element;\n this._activeTarget = null;\n this._observer = null;\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n };\n this.refresh(); // initialize\n } // Getters\n\n\n static get Default() {\n return Default$1;\n }\n\n static get DefaultType() {\n return DefaultType$1;\n }\n\n static get NAME() {\n return NAME$2;\n } // Public\n\n\n refresh() {\n this._initializeTargetsAndObservables();\n\n this._maybeEnableSmoothScroll();\n\n if (this._observer) {\n this._observer.disconnect();\n } else {\n this._observer = this._getNewObserver();\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section);\n }\n }\n\n dispose() {\n this._observer.disconnect();\n\n super.dispose();\n } // Private\n\n\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body; // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin;\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value));\n }\n\n return config;\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return;\n } // unregister any previous listeners\n\n\n EventHandler.off(this._config.target, EVENT_CLICK);\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash);\n\n if (observableSection) {\n event.preventDefault();\n const root = this._rootElement || window;\n const height = observableSection.offsetTop - this._element.offsetTop;\n\n if (root.scrollTo) {\n root.scrollTo({\n top: height,\n behavior: 'smooth'\n });\n return;\n } // Chrome 60 doesn't support `scrollTo`\n\n\n root.scrollTop = height;\n }\n });\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n };\n return new IntersectionObserver(entries => this._observerCallback(entries), options);\n } // The logic of selection\n\n\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`);\n\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop;\n\n this._process(targetElement(entry));\n };\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop;\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop;\n this._previousScrollData.parentScrollTop = parentScrollTop;\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null;\n\n this._clearActiveClass(targetElement(entry));\n\n continue;\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop; // if we are scrolling down, pick the bigger offsetTop\n\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry); // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n\n if (!parentScrollTop) {\n return;\n }\n\n continue;\n } // if we are scrolling up, pick the smallest offsetTop\n\n\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry);\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map();\n this._observableSections = new Map();\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target);\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue;\n }\n\n const observableSection = SelectorEngine.findOne(anchor.hash, this._element); // ensure that the observableSection exists & is visible\n\n if (isVisible(observableSection)) {\n this._targetLinks.set(anchor.hash, anchor);\n\n this._observableSections.set(anchor.hash, observableSection);\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return;\n }\n\n this._clearActiveClass(this._config.target);\n\n this._activeTarget = target;\n target.classList.add(CLASS_NAME_ACTIVE$1);\n\n this._activateParents(target);\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, {\n relatedTarget: target\n });\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE$1, target.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE$1);\n return;\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both
@@ -231,28 +238,34 @@ -