diff --git a/Website/.DS_Store b/Website/.DS_Store
new file mode 100644
index 0000000..d400a14
Binary files /dev/null and b/Website/.DS_Store differ
diff --git a/Website/.vscode/settings.json b/Website/.vscode/settings.json
new file mode 100644
index 0000000..6f3a291
--- /dev/null
+++ b/Website/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "liveServer.settings.port": 5501
+}
\ No newline at end of file
diff --git a/Website/Readme.md b/Website/Readme.md
new file mode 100644
index 0000000..ea75740
--- /dev/null
+++ b/Website/Readme.md
@@ -0,0 +1,28 @@
+# Nova Free Bootstrap 5 Business Template
+
+#### Preview
+
+ - [Demo](https://themewagon.github.io/Nova-Bootstrap-5/)
+
+#### Download
+ - [Download from ThemeWagon](https://themewagon.com/themes/nova-bootstrap/)
+
+## Getting Started
+
+Clone from Github
+
+```
+git clone https://github.com/themewagon/Nova-Bootstrap-5.git
+```
+## Author
+
+Design and code is completely written by Freebiesbug's design and development team.
+
+
+## License
+
+ - Design and Code is Copyright © [Freebiesbug](https://freebiesbug.com/)
+ - Licensed cover under [MIT]
+ - Distributed by [ThemeWagon](https://themewagon.com)
+
+
diff --git a/Website/assets/.DS_Store b/Website/assets/.DS_Store
new file mode 100644
index 0000000..e8b2f76
Binary files /dev/null and b/Website/assets/.DS_Store differ
diff --git a/Website/assets/css/style.css b/Website/assets/css/style.css
new file mode 100644
index 0000000..a3b792c
--- /dev/null
+++ b/Website/assets/css/style.css
@@ -0,0 +1,1702 @@
+/*
+Template name: Nova
+Template author: FreeBootstrap.net
+Author website: https://freebootstrap.net/
+License: https://freebootstrap.net/license
+Buy Pro
+*/
+:root,
+[data-bs-theme=light] {
+ --bs-body-bg: #ffffff;
+ --bs-body-color: #494B5B;
+ --bs-primary: #215C5C;
+ --bs-primary-rgb: 33, 92, 92;
+ --bs-primary-hover: #144B4B;
+ --bs-primary-hover-rgb: 20, 75, 75;
+ --bs-secondary: #CCE8C9;
+ --bs-secondary-rgb: 204, 232, 201;
+ --bs-heading-color: #16181B;
+ --inverse-color: #494B5B;
+ --inverse-color-rgb: 73, 75, 91;
+ --bs-link-color: var(--bs-primary);
+ --nav-bg: #ffffff;
+ --nav-color: #fff;
+ --nav-hover-color: #1f6bff;
+ --dropdown-bg: #ffffff;
+ --dropdown-color: #1f6bff;
+ --dropdown-hover-bg: #f7f7f7;
+ --nav-inverse: #000000;
+ --nav-inverse-alt: #ffffff;
+}
+
+.main-content {
+ display: grid;
+ margin-top: 5%;
+ grid-template-columns: 1fr 2fr;
+ gap: 30px;
+ padding: 30px;
+ }
+
+ /* Coluna da Esquerda */
+ .left-column {
+ display: flex;
+ flex-direction: column;
+ gap: 25px;
+ }
+
+ .lgpd-consent {
+ background: #e8f4fc;
+ padding: 20px;
+ border-radius: 8px;
+ border-left: 4px solid #144B4B;
+ }
+
+ .report-history {
+ background: #f8f9fa;
+ padding: 20px;
+ border-radius: 8px;
+ }
+
+ .report-history h3 {
+ margin-bottom: 15px;
+ color: #2c3e50;
+ border-bottom: 2px solid #144B4B;
+ padding-bottom: 8px;
+ }
+
+ .report-history ul {
+ list-style: none;
+ }
+
+ .report-history li {
+ padding: 10px 0;
+ border-bottom: 1px solid #e1e4e8;
+ }
+
+ .report-history li:last-child {
+ border-bottom: none;
+ }
+
+ /* Coluna da Direita */
+ .right-column {
+ background: #fff;
+ padding: 25px;
+ border-radius: 8px;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.05);
+ }
+
+ .report-title {
+ text-align: center;
+ margin-bottom: 25px;
+ color: #2c3e50;
+ border-bottom: 2px solid #144B4B;
+ padding-bottom: 15px;
+ }
+
+ .action-buttons {
+ display: flex;
+ justify-content: flex-end;
+ gap: 15px;
+ margin-bottom: 25px;
+ }
+
+ .btn {
+ padding: 10px 20px;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+ font-weight: 500;
+ transition: all 0.3s;
+ }
+
+ .btn-draft {
+ background: #e8f4fc;
+ color: #144B4B;
+ border: 1px solid #144B4B;
+ }
+
+ .btn-draft:hover {
+ background: #144B4B;
+ color: white;
+ }
+
+ .btn-finish {
+ background: #144B4B;
+ color: white;
+ }
+
+ .btn-finish:hover {
+ background: #2c3e50;
+ }
+
+ .report-type-priority {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 20px;
+ margin-bottom: 25px;
+ }
+
+ .info-box {
+ background: #f8f9fa;
+ padding: 15px;
+ border-radius: 8px;
+ }
+
+ .info-box h4 {
+ margin-bottom: 10px;
+ color: #2c3e50;
+ }
+
+ .form-section {
+ margin-bottom: 25px;
+ }
+
+ .form-section h3 {
+ margin-bottom: 15px;
+ color: #2c3e50;
+ border-bottom: 1px solid #e1e4e8;
+ padding-bottom: 8px;
+ }
+
+ .form-section textarea {
+ width: 100%;
+ min-height: 120px;
+ padding: 15px;
+ border: 1px solid #dce1e6;
+ border-radius: 5px;
+ resize: vertical;
+ font-family: inherit;
+ }
+
+
+ /* Responsividade */
+ @media (max-width: 900px) {
+ .main-content {
+ grid-template-columns: 1fr;
+ }
+
+ .report-type-priority {
+ grid-template-columns: 1fr;
+ }
+
+ .nav-links {
+ margin-top: 15px;
+ }
+ }
+
+
+.footer{background-color: white;}
+.logo{font-weight:800;letter-spacing:.4px}
+.logo span{color:var(--bs-primary)}
+.toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 14px 20px
+}
+
+.toolbar {
+ background: var(--bg);
+ border-bottom: 10px solid #111827
+}
+
+.toolbar__actions {
+ display: flex;
+ gap: 10px;
+ align-items: center
+}
+
+main.workspace {
+ padding-top: 100px;
+ /* ajuste conforme a altura real do seu header */
+ padding-left: 40px;
+ padding-right: 40px;
+}
+
+.patient-card .patient-info {
+ padding-left: 16px
+}
+
+.patient-card .patient-info li {
+ margin: 6px 0
+}
+
+.container {
+ width: min(1100px, 92%);
+ margin: 0 auto
+}
+
+.hero__panel.card {
+ padding: 22px
+}
+
+.with-editor .editor {
+ display: grid;
+ grid-template-columns: 320px 1fr;
+ gap: 16px;
+ padding: 20px 0
+}
+
+.grid-3 {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 16px
+}
+
+.grid-2 {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 14px
+}
+
+.value-list {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 8px 16px;
+ margin-top: 16px;
+ padding: 0
+}
+
+.hero {
+ display: grid;
+ grid-template-columns: 1.2fr .8fr;
+ gap: 26px;
+ padding: 42px 0
+}
+
+.card {
+ background: var(--card);
+ border: 1px solid #111827;
+ border-radius: var(--radius);
+ box-shadow: var(--shadow);
+ padding: 18px
+}
+
+.card--soft {
+ background: var(--soft)
+}
+
+.hero__panel.card {
+ padding: 22px
+}
+
+.editor__panel .form textarea {
+ resize: vertical
+}
+
+
+@media (max-width: 980px) {
+ .patient-card {
+ order: 2
+ }
+
+ .editor__panel {
+ order: 1
+ }
+
+ .hero {
+ grid-template-columns: 1fr
+ }
+
+ .grid-3 {
+ grid-template-columns: 1fr
+ }
+
+ .with-editor .editor {
+ grid-template-columns: 1fr
+ }
+}
+
+
+
+body {
+ font: 1rem/1.7 "Inter", sans-serif;
+ background-color: var(--bs-body-bg);
+ color: var(--bs-body-color);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.site-wrap {
+ position: relative;
+}
+
+::-moz-selection {
+ background-color: var(--bs-black);
+ color: var(--bs-white);
+}
+
+::selection {
+ background-color: var(--bs-black);
+ color: var(--bs-white);
+}
+
+a {
+ -webkit-transition: 0.3s all ease-in-out;
+ transition: 0.3s all ease-in-out;
+ color: var(--bs-primary);
+ text-decoration: underline;
+}
+
+a:hover {
+ text-decoration: none;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ color: var(--bs-heading-color);
+}
+
+.container {
+ max-width: 1140px;
+}
+
+.section {
+ padding: 70px 0;
+ scroll-margin-top: 60px;
+}
+
+@media (max-width: 767.98px) {
+ .section {
+ padding: 40px 0;
+ }
+}
+
+.section.first-section {
+ padding-top: 100px;
+}
+
+@media (min-width: 992px) {
+ .section.first-section {
+ padding-top: 130px;
+ }
+}
+
+.text-heading-color {
+ color: var(--bs-heading-color);
+}
+
+.shadow-sm {
+ -webkit-box-shadow: 0 0.125rem 0.25rem 0 rgba(var(--bs-black-rgb), 0.05) !important;
+ box-shadow: 0 0.125rem 0.25rem 0 rgba(var(--bs-black-rgb), 0.05) !important;
+}
+
+.shadow {
+ -webkit-box-shadow: 0 0.5rem 1rem 0 rgba(var(--bs-black-rgb), 0.05) !important;
+ box-shadow: 0 0.5rem 1rem 0 rgba(var(--bs-black-rgb), 0.05) !important;
+}
+
+.shadow-lg {
+ -webkit-box-shadow: 0 1rem 3rem 0 rgba(var(--bs-black-rgb), 0.05) !important;
+ box-shadow: 0 1rem 3rem 0 rgba(var(--bs-black-rgb), 0.05) !important;
+}
+
+.list-checked {
+ padding: 0;
+ margin: 0;
+ color: var(--bs-body-color);
+}
+
+.list-checked li {
+ position: relative;
+ margin-bottom: 10px;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: start;
+ -ms-flex-align: start;
+ align-items: start;
+ gap: 10px;
+}
+
+.list-checked li i {
+ width: 30px;
+ height: 30px;
+ text-align: center;
+ line-height: 30px;
+ display: inline-block;
+ background-color: rgba(var(--bs-primary-rgb), 0.1);
+ border-radius: 50%;
+ color: var(--bs-primary);
+ font-size: 20px;
+}
+
+.list-checked li:before {
+ position: absolute;
+ display: inline-block;
+ left: 0;
+ content: "";
+ vertical-align: -0.125em;
+ background-repeat: no-repeat;
+ background-position: right center;
+ background-size: 1.5625rem 1.5625rem;
+ width: 1.5625rem;
+ height: 1.5625rem;
+}
+
+.btn {
+ padding: 12px 20px;
+ background-color: var(--bs-primary);
+ color: var(--bs-white);
+ border: 1px solid transparent;
+ border-radius: 7px;
+ font-weight: 600;
+ position: relative;
+}
+
+.btn:hover,
+.btn:active,
+.btn:focus {
+ color: var(--bs-white);
+ background-color: var(--bs-primary-hover) !important;
+ border: 1px solid var(--bs-primary-hover) !important;
+}
+
+.btn.btn-white.hover-outline {
+ background-color: var(--bs-white) !important;
+ color: var(--bs-black) !important;
+ border: 1px solid transparent !important;
+}
+
+.btn.btn-white.hover-outline:hover {
+ color: var(--bs-white) !important;
+ background-color: transparent !important;
+ border: 1px solid var(--bs-white) !important;
+}
+
+.btn.btn-white-outline {
+ border: 1px solid rgba(var(--inverse-color-rgb), 0.2) !important;
+ color: var(--inverse-color) !important;
+ background-color: transparent;
+}
+
+.btn.btn-white-outline:hover,
+.btn.btn-white-outline:focus,
+.btn.btn-white-outline:active {
+ background-color: transparent !important;
+ border: 1px solid rgba(var(--inverse-color-rgb), 0.5) !important;
+}
+
+.block-squares {
+ position: absolute;
+ bottom: -12px;
+ right: 0;
+ z-index: 1;
+ width: auto;
+}
+
+.form-control {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ border-width: 1px;
+ font-size: 16px;
+ background-color: transparent;
+ border-color: rgba(var(--inverse-color-rgb), 0.1);
+}
+
+.form-control:focus {
+ outline: none;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ border-color: var(--bs-primary);
+}
+
+.a-link i {
+ font-size: 26px;
+ margin-left: 10px;
+ -webkit-transition: 0.25s all ease-in-out;
+ transition: 0.25s all ease-in-out;
+}
+
+.a-link:hover i {
+ margin-left: 15px;
+}
+
+.page-title {
+ padding-top: 100px !important;
+ padding-bottom: 50px !important;
+ background-color: rgba(var(--inverse-color-rgb), 0.03);
+}
+
+.special-link .icons {
+ display: inline-block;
+ width: 38px;
+ height: 38px;
+ line-height: 38px;
+ border-radius: 50%;
+ text-align: center;
+ position: relative;
+ border: 1px solid rgba(var(--inverse-color-rgb), 0.2);
+}
+
+.special-link .icons i {
+ font-size: 25px;
+ position: relative;
+ display: inline-block;
+ position: absolute;
+ -webkit-transition: 0.3s all ease-in-out;
+ transition: 0.3s all ease-in-out;
+}
+
+.special-link .icons i.icon-1 {
+ opacity: 1;
+ visibility: visible;
+ top: 50%;
+ left: 50%;
+ -webkit-transform: translate(-50%, -50%) rotate(-45deg);
+ transform: translate(-50%, -50%) rotate(-45deg);
+}
+
+.special-link .icons i.icon-2 {
+ opacity: 0;
+ visibility: hidden;
+ top: 80%;
+ left: 20%;
+ -webkit-transform: translate(-50%, -50%) rotate(-45deg);
+ transform: translate(-50%, -50%) rotate(-45deg);
+}
+
+.special-link:hover .icons .icon-1 {
+ opacity: 0;
+ visibility: hidden;
+ top: 20%;
+ left: 80%;
+ -webkit-transform: translate(-50%, -50%) rotate(-45deg);
+ transform: translate(-50%, -50%) rotate(-45deg);
+}
+
+.special-link:hover .icons .icon-2 {
+ opacity: 1;
+ visibility: visible;
+ top: 50%;
+ left: 50%;
+ -webkit-transform: translate(-50%, -50%) rotate(-45deg);
+ transform: translate(-50%, -50%) rotate(-45deg);
+}
+
+.fbs__net-navbar {
+ position: absolute;
+ top: 0;
+ -webkit-transition: 0.3s all ease-in-out;
+ transition: 0.3s all ease-in-out;
+ z-index: 99999;
+ width: 100%;
+ background-color: transparent !important;
+ border: none;
+}
+
+@media (min-width: 992px) {
+ .fbs__net-navbar {
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+}
+
+.fbs__net-navbar>.container {
+ position: relative;
+}
+
+.fbs__net-navbar.relative {
+ position: absolute;
+}
+
+.fbs__net-navbar .navbar-brand {
+ color: var(--bs-white);
+ font-size: 30px;
+ font-weight: bold;
+}
+
+.fbs__net-navbar .navbar-brand .logo.dark {
+ display: none;
+}
+
+.fbs__net-navbar .navbar-brand .logo.light {
+ display: block;
+}
+
+.fbs__net-navbar .navbar-nav>li>.nav-link {
+ position: relative;
+ padding-top: 22px;
+ padding-bottom: 22px;
+ padding-left: 10px;
+ padding-right: 10px;
+ font-size: 0.9375rem;
+ color: rgba(var(--bs-white-rgb), 1);
+ -webkit-transition: 0.3s all ease;
+ transition: 0.3s all ease;
+ position: relative;
+}
+
+@media (max-width: 991.98px) {
+ .fbs__net-navbar .navbar-nav>li>.nav-link {
+ color: var(--inverse-color);
+ }
+}
+
+.fbs__net-navbar .navbar-nav>li>.nav-link:before {
+ content: "";
+ position: absolute;
+ width: calc(100% - 20px);
+ -webkit-transform: scaleX(0);
+ transform: scaleX(0);
+ border-radius: 5px;
+ height: 1.5px;
+ bottom: 0;
+ left: 10px;
+ background: currentcolor;
+ -webkit-transform-origin: bottom right;
+ transform-origin: bottom right;
+ -webkit-transition: -webkit-transform 0.35s ease-out;
+ transition: -webkit-transform 0.35s ease-out;
+ transition: transform 0.35s ease-out;
+ transition: transform 0.35s ease-out, -webkit-transform 0.35s ease-out;
+}
+
+.fbs__net-navbar .navbar-nav>li>.nav-link:hover::before {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ -webkit-transform-origin: bottom left;
+ transform-origin: bottom left;
+}
+
+.fbs__net-navbar .navbar-nav>li>.nav-link:hover,
+.fbs__net-navbar .navbar-nav>li>.nav-link:focus {
+ color: var(--bs-white);
+}
+
+@media (max-width: 991.98px) {
+
+ .fbs__net-navbar .navbar-nav>li>.nav-link:hover,
+ .fbs__net-navbar .navbar-nav>li>.nav-link:focus {
+ color: var(--inverse-color) !important;
+ }
+}
+
+@media (max-width: 767.98px) {
+ .fbs__net-navbar .navbar-nav>li>.nav-link {
+ padding-top: 5px;
+ padding-bottom: 5px;
+ }
+}
+
+.fbs__net-navbar .navbar-nav>li>.nav-link.active {
+ color: var(--bs-white);
+}
+
+@media (max-width: 991.98px) {
+ .fbs__net-navbar .navbar-nav>li>.nav-link.active {
+ color: var(--inverse-color);
+ }
+}
+
+.fbs__net-navbar .navbar-nav>li>.nav-link.active:before {
+ content: "";
+ -webkit-transform-origin: bottom left;
+ transform-origin: bottom left;
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+}
+
+.fbs__net-navbar .navbar-nav>li>.nav-link.dropdown-toggle {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+}
+
+.fbs__net-navbar .navbar-nav>li>.nav-link.dropdown-toggle::after {
+ display: none;
+ content: "";
+}
+
+@media (max-width: 991.98px) {
+ .fbs__net-navbar .navbar-nav>li>.nav-link {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ }
+}
+
+.fbs__net-navbar .navbar-nav .dropdown-menu {
+ background-color: var(--nav-bg);
+}
+
+.fbs__net-navbar .navbar-nav .dropdown-menu .nav-link:hover {
+ background-color: var(--dropdown-hover-bg) !important;
+ color: var(--inverse-color);
+}
+
+.fbs__net-navbar .navbar-nav .dropdown-toggle::after {
+ display: none;
+}
+
+.fbs__net-navbar .navbar-nav .dropdown-toggle .bi-chevron-down {
+ margin-left: 0.5rem;
+}
+
+.fbs__net-navbar .fbs__net-navbar-toggler {
+ width: 50px;
+ height: 50px;
+ border-radius: 50%;
+ position: relative;
+ background-color: var(--bs-black);
+ color: var(--bs-white);
+ border: none;
+ display: none;
+}
+
+@media (max-width: 991.98px) {
+ .fbs__net-navbar .fbs__net-navbar-toggler {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ }
+}
+
+.fbs__net-navbar .navbar-brand {
+ margin-right: 0 !important;
+}
+
+.fbs__net-navbar .navbar-nav .dropdown>.dropdown-menu,
+.fbs__net-navbar .navbar-nav .dropend>.dropdown-menu,
+.fbs__net-navbar .navbar-nav .dropstart>.dropdown-menu {
+ border: none !important;
+ padding-left: 10px;
+ padding-right: 10px;
+ -webkit-box-shadow: 0 0.1875rem 0.375rem rgba(var(--bs-black-rgb), 0.1);
+ box-shadow: 0 0.1875rem 0.375rem rgba(var(--bs-black-rgb), 0.1);
+}
+
+@media (min-width: 992px) {
+
+ .fbs__net-navbar .navbar-nav .dropdown>.dropdown-menu,
+ .fbs__net-navbar .navbar-nav .dropend>.dropdown-menu,
+ .fbs__net-navbar .navbar-nav .dropstart>.dropdown-menu {
+ padding-left: 10px;
+ padding-right: 10px;
+ width: 200px;
+ border: none;
+ }
+}
+
+.fbs__net-navbar .navbar-nav .dropdown>.dropdown-menu .dropdown-item,
+.fbs__net-navbar .navbar-nav .dropdown>.dropdown-menu .nav-link,
+.fbs__net-navbar .navbar-nav .dropend>.dropdown-menu .dropdown-item,
+.fbs__net-navbar .navbar-nav .dropend>.dropdown-menu .nav-link,
+.fbs__net-navbar .navbar-nav .dropstart>.dropdown-menu .dropdown-item,
+.fbs__net-navbar .navbar-nav .dropstart>.dropdown-menu .nav-link {
+ font-size: 0.875rem;
+ padding: 10px 10px;
+ -webkit-transition: 0.3s all ease;
+ transition: 0.3s all ease;
+ border-radius: 0.5rem;
+}
+
+@media (min-width: 992px) {
+
+ .fbs__net-navbar .navbar-nav .dropdown:hover>.dropdown-menu,
+ .fbs__net-navbar .navbar-nav .dropend:hover>.dropdown-menu,
+ .fbs__net-navbar .navbar-nav .dropstart:hover>.dropdown-menu {
+ display: block;
+ -webkit-animation: fadeInUp 0.3s ease;
+ animation: fadeInUp 0.3s ease;
+ }
+}
+
+@media (min-width: 992px) {
+ .fbs__net-navbar .navbar-nav .dropend:hover>.dropdown-menu {
+ position: absolute;
+ top: 0;
+ left: 100%;
+ -webkit-animation: fadeInRight 0.3s ease;
+ animation: fadeInRight 0.3s ease;
+ }
+}
+
+@media (min-width: 992px) {
+ .fbs__net-navbar .navbar-nav .dropstart:hover>.dropdown-menu {
+ position: absolute;
+ top: 0;
+ right: 100%;
+ -webkit-animation: fadeInLeft 0.3s ease;
+ animation: fadeInLeft 0.3s ease;
+ }
+}
+
+.fbs__net-navbar .navbar-nav .dropdown-toggle::before {
+ display: none;
+}
+
+.fbs__net-navbar .navbar-nav .dropdown-toggle::after {
+ display: none;
+}
+
+.fbs__net-navbar .navbar-nav li.dropend>a,
+.fbs__net-navbar .navbar-nav li.dropstart>a {
+ position: relative;
+}
+
+.fbs__net-navbar .navbar-nav li.dropend>a .bi,
+.fbs__net-navbar .navbar-nav li.dropstart>a .bi {
+ position: absolute;
+ right: 10px;
+ top: 50%;
+ -webkit-transform: translateY(-50%);
+ transform: translateY(-50%);
+}
+
+@media (max-width: 991.98px) {
+
+ .fbs__net-navbar .navbar-nav li.dropend>a .bi,
+ .fbs__net-navbar .navbar-nav li.dropstart>a .bi {
+ -webkit-transform: rotate(90deg);
+ transform: rotate(90deg);
+ margin-top: -10px;
+ }
+}
+
+.fbs__net-navbar .navbar-nav li.dropend>a::after,
+.fbs__net-navbar .navbar-nav li.dropstart>a::after {
+ display: none;
+}
+
+.fbs__net-navbar .navbar-nav li.dropend>a {
+ position: relative;
+}
+
+.fbs__net-navbar .navbar-nav li.dropend>a:hover {
+ background-color: var(--dropdown-hover-bg) !important;
+}
+
+.fbs__net-navbar .navbar-nav li.dropend>a .caret {
+ position: absolute;
+ right: 10px;
+}
+
+.fbs__net-navbar .navbar-nav li.dropstart>a {
+ position: relative;
+}
+
+.fbs__net-navbar .navbar-nav li.dropstart>a:hover {
+ background-color: var(--dropdown-hover-bg) !important;
+}
+
+.fbs__net-navbar .navbar-nav li.dropstart>a .caret {
+ position: absolute;
+ left: 10px;
+}
+
+.fbs__net-navbar .navbar-toggler:hover,
+.fbs__net-navbar .navbar-toggler:focus,
+.fbs__net-navbar .navbar-toggler:active {
+ outline: none;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.fbs__net-navbar .header-social a {
+ -webkit-transition: 0.3s all ease;
+ transition: 0.3s all ease;
+ color: var(--bs-white);
+ width: 30px;
+ height: 30px;
+ line-height: 30px;
+ text-align: center;
+ border-radius: 4px;
+ display: inline-block;
+ background-color: transparent;
+}
+
+.fbs__net-navbar .header-social a:hover {
+ background-color: rgba(var(--bs-white-rgb), 0.1);
+}
+
+@media (min-width: 992px) {
+ .fbs__net-navbar .header-social a {
+ color: var(--bs-white);
+ }
+}
+
+.fbs__net-navbar .header-social .btn {
+ width: auto !important;
+ height: auto !important;
+ background-color: var(--bs-primary) !important;
+ color: var(--bs-white) !important;
+}
+
+@media (max-width: 575.98px) {
+ .fbs__net-navbar .header-social .btn {
+ display: none;
+ }
+}
+
+.fbs__net-navbar.active {
+ position: fixed;
+ top: 0;
+ width: 100%;
+ background-color: var(--nav-bg) !important;
+ -webkit-box-shadow: 0 0.1875rem 0.375rem rgba(var(--bs-black-rgb), 0.05) !important;
+ box-shadow: 0 0.1875rem 0.375rem rgba(var(--bs-black-rgb), 0.05) !important;
+}
+
+.fbs__net-navbar.active .navbar-brand {
+ color: rgba(var(--inverse-color-rgb), 1) !important;
+}
+
+.fbs__net-navbar.active .navbar-brand .logo.dark {
+ display: block;
+}
+
+.fbs__net-navbar.active .navbar-brand .logo.light {
+ display: none;
+}
+
+.fbs__net-navbar.active .nav-link {
+ color: rgba(var(--inverse-color-rgb), 1) !important;
+}
+
+.fbs__net-navbar.active .nav-link:hover {
+ color: rgba(var(--inverse-color-rgb), 1) !important;
+}
+
+.fbs__net-navbar.active .header-social a {
+ -webkit-transition: 0.3s all ease;
+ transition: 0.3s all ease;
+ color: var(--inverse-color);
+}
+
+.fbs__net-navbar.active .header-social a:hover {
+ background-color: rgba(var(--inverse-color-rgb), 0.1);
+}
+
+@media (min-width: 992px) {
+ .fbs__net-navbar.active .header-social a {
+ color: rgba(var(--inverse-color-rgb), 1) !important;
+ }
+}
+
+.fbs__net-navbar.active .header-social .btn {
+ width: auto !important;
+ height: auto !important;
+ background-color: var(--bs-primary) !important;
+ color: var(--bs-white) !important;
+}
+
+.fbs__net-navbar.active .navbar-nav>li>.dropdown-toggle:hover {
+ color: var(--inverse-color) !important;
+}
+
+.fbs__net-navbar.active .navbar-nav>li>.nav-link.dropdown-toggle::after {
+ display: none;
+ content: "";
+}
+
+.fbs__net-navbar.active .navbar-nav li.dropdown a:hover,
+.fbs__net-navbar.active .navbar-nav li.dropend a:hover,
+.fbs__net-navbar.active .navbar-nav li.dropstart a:hover {
+ color: var(--inverse-color) !important;
+}
+
+.fbs__net-navbar .fbs__net-icon-menu {
+ display: block;
+}
+
+.fbs__net-navbar .fbs__net-icon-close {
+ display: none;
+}
+
+.offcanvas-active .fbs__net-navbar .fbs__net-icon-menu {
+ display: none;
+}
+
+.offcanvas-active .fbs__net-navbar .fbs__net-icon-close {
+ display: block;
+}
+
+.fbs__net-navbar.dark {
+ -webkit-box-shadow: 0 0px 2px rgba(var(--inverse-color-rgb), 0.15);
+ box-shadow: 0 0px 2px rgba(var(--inverse-color-rgb), 0.15);
+}
+
+.fbs__net-navbar.dark .navbar-brand .logo.dark {
+ display: block;
+}
+
+.fbs__net-navbar.dark .navbar-brand .logo.light {
+ display: none;
+}
+
+.fbs__net-navbar.dark a {
+ color: var(--inverse-color) !important;
+}
+
+.fbs__net-navbar.dark a:hover {
+ color: var(--inverse-color);
+}
+
+.fbs__net-navbar.dark .header-social a:hover {
+ background-color: rgba(var(--inverse-color-rgb), 0.05);
+}
+
+.fbs__net-navbar.dark ul li a {
+ color: rgba(var(--inverse-color-rgb), 1) !important;
+}
+
+.fbs__net-navbar.dark ul li a:hover {
+ color: var(--inverse-color) !important;
+}
+
+.fbs__net-navbar .offcanvas-header .offcanvas-header-logo .logo-link .logo.dark {
+ display: block;
+}
+
+.fbs__net-navbar .offcanvas-header .offcanvas-header-logo .logo-link .logo.light {
+ display: none;
+}
+
+
+@-webkit-keyframes fadeInUp {
+ from {
+ opacity: 0;
+ -webkit-transform: translateY(10px);
+ transform: translateY(10px);
+ }
+
+ to {
+ opacity: 1;
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+}
+
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ -webkit-transform: translateY(10px);
+ transform: translateY(10px);
+ }
+
+ to {
+ opacity: 1;
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+}
+
+@-webkit-keyframes fadeInRight {
+ from {
+ opacity: 0;
+ -webkit-transform: translateX(10px);
+ transform: translateX(10px);
+ }
+
+ to {
+ opacity: 1;
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+@keyframes fadeInRight {
+ from {
+ opacity: 0;
+ -webkit-transform: translateX(10px);
+ transform: translateX(10px);
+ }
+
+ to {
+ opacity: 1;
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+@-webkit-keyframes fadeInLeft {
+ from {
+ opacity: 0;
+ -webkit-transform: translateX(-10px);
+ transform: translateX(-10px);
+ }
+
+ to {
+ opacity: 1;
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+@keyframes fadeInLeft {
+ from {
+ opacity: 0;
+ -webkit-transform: translateX(-10px);
+ transform: translateX(-10px);
+ }
+
+ to {
+ opacity: 1;
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+.hero__v6 {
+ padding: 10rem 0 !important;
+}
+
+.hero__v6 .hero-subtitle {
+ background: color-mix(in srgb, var(--bs-secondary), transparent 70%);
+ color: var(--bs-primary);
+ display: inline-block;
+ padding: 5px 12px;
+ border-radius: 7px;
+ font-weight: 600;
+ font-size: 0.75rem;
+ margin-bottom: 10px;
+}
+
+.hero__v6 .hero-title {
+ font-size: 48px;
+}
+
+@media (max-width: 1199.98px) {
+ .hero__v6 .hero-title {
+ font-size: 40px;
+ }
+}
+
+@media (max-width: 991.98px) {
+ .hero__v6 .hero-title {
+ font-size: 30px;
+ }
+}
+
+.hero__v6 .logos .logos-title {
+ font-size: 12px;
+ letter-spacing: 1px;
+ color: color-mix(in srgb, var(--bs-primary), transparent 10%);
+}
+
+.hero__v6 .logos img {
+ width: 140px;
+}
+
+.hero__v6 .hero-img {
+ position: relative;
+}
+
+.hero__v6 .hero-img .img-main {
+ position: relative;
+ z-index: 9;
+}
+
+.hero__v6 .hero-img .img-card {
+ z-index: 10;
+ border-radius: 20px;
+ -webkit-box-shadow: 0 15px 40px 0 rgba(var(--bs-black-rgb), 0.1);
+ box-shadow: 0 15px 40px 0 rgba(var(--bs-black-rgb), 0.1);
+ position: absolute;
+ max-width: 280px;
+ bottom: -40px;
+ left: -60px;
+}
+
+@media (max-width: 991.98px) {
+ .hero__v6 .hero-img .img-card {
+ left: 10px;
+ max-width: 380px;
+ }
+}
+
+@media (max-width: 575.98px) {
+ .hero__v6 .hero-img .img-card {
+ left: 10px;
+ max-width: 280px;
+ }
+}
+
+.features__v2 .icon {
+ width: 60px;
+ height: 60px;
+ line-height: 60px;
+ border-radius: 50%;
+ background-color: var(--bs-secondary);
+ color: var(--bs-primary);
+}
+
+.features__v2 .content {
+ background-color: rgba(var(--bs-secondary-rgb), 0.2);
+}
+
+.features__v2 .btn-play i {
+ width: 30px;
+ height: 30px;
+ line-height: 30px;
+ border-radius: 50%;
+ background-color: var(--bs-white);
+ color: var(--bs-primary);
+}
+
+.about__v4 .subtitle {
+ background-color: rgba(var(--bs-secondary-rgb), 0.2);
+ color: var(--bs-primary);
+ display: inline-block;
+ padding: 5px 12px;
+ border-radius: 7px;
+ font-weight: 600;
+ font-size: 0.75rem;
+ margin-bottom: 10px;
+}
+
+.about__v4 .features li .icon {
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ line-height: 20px;
+ background-color: var(--bs-primary);
+ color: var(--bs-white);
+}
+
+.about__v4 .mission-statement {
+ background-color: var(--bs-primary);
+ position: relative;
+ bottom: -20px;
+ width: 100%;
+}
+
+.about__v4 .mission-statement h3 {
+ font-size: 10px;
+ color: var(--bs-secondary);
+}
+
+.about__v4 .mission-statement p {
+ color: var(--bs-white);
+}
+
+.about__v4 .mission-icon {
+ width: 50px;
+ height: 50px;
+ -webkit-box-flex: 0;
+ -ms-flex: 0 0 50px;
+ flex: 0 0 50px;
+ line-height: 50px;
+ display: inline-block;
+ background-color: rgba(var(--bs-secondary-rgb), 0.1);
+}
+
+.about__v4 .mission-icon i {
+ color: var(--bs-secondary);
+}
+
+.pricing__v2 .subtitle {
+ background-color: rgba(var(--bs-secondary-rgb), 0.2);
+ color: var(--bs-primary);
+ display: inline-block;
+ padding: 5px 12px;
+ border-radius: 7px;
+ font-weight: 600;
+ font-size: 0.75rem;
+ margin-bottom: 10px;
+}
+
+.pricing__v2 .price-table {
+ border: 1px solid rgba(var(--inverse-color-rgb), 0.2);
+}
+
+.pricing__v2 .price-table .price {
+ color: var(--bs-heading-color);
+}
+
+.pricing__v2 .price-table .price strong {
+ font-size: 40px;
+}
+
+.pricing__v2 .price-table .icon {
+ -webkit-box-flex: 0;
+ -ms-flex: 0 0 20px;
+ flex: 0 0 20px;
+ width: 20px;
+ height: 20px;
+ line-height: 20px;
+ text-align: center;
+ border: 1px solid rgba(var(--bs-white-rgb), 0.2);
+}
+
+.pricing__v2 .popular {
+ background-color: var(--bs-primary);
+ color: var(--bs-white);
+}
+
+.pricing__v2 .popular .price {
+ color: var(--bs-secondary);
+}
+
+.pricing__v2 .popular h3 {
+ color: var(--bs-white);
+}
+
+.pricing__v2 .popular p {
+ color: var(--bs-white);
+}
+
+.pricing__v2 .popular .pricing-features h4 {
+ font-size: 12px;
+ color: var(--bs-secondary);
+}
+
+.howitworks__v1 .subtitle {
+ background-color: rgba(var(--bs-secondary-rgb), 0.2);
+ color: var(--bs-primary);
+ display: inline-block;
+ padding: 5px 12px;
+ border-radius: 7px;
+ font-weight: 600;
+ font-size: 0.75rem;
+ margin-bottom: 10px;
+}
+
+.howitworks__v1 .step-card {
+ position: relative;
+}
+
+.howitworks__v1 .step-card .step-number {
+ width: 60px;
+ height: 60px;
+ line-height: 60px;
+ display: inline-block;
+ color: var(--bs-secondary);
+ background-color: var(--bs-primary);
+ font-size: 18px;
+}
+
+.howitworks__v1 .arch-line {
+ position: absolute;
+ top: 15px;
+ width: 150px;
+ right: 0;
+ left: calc(100% + 24px);
+ -webkit-transform: translateX(-50%);
+ transform: translateX(-50%);
+}
+
+@media (max-width: 991.98px) {
+ .howitworks__v1 .arch-line {
+ display: none;
+ }
+}
+
+.howitworks__v1 .arch-line.reverse {
+ top: 20px;
+}
+
+.services__v3 .subtitle {
+ background-color: rgba(var(--bs-secondary-rgb), 0.2);
+ color: var(--bs-primary);
+ display: inline-block;
+ padding: 5px 12px;
+ border-radius: 7px;
+ font-weight: 600;
+ font-size: 0.75rem;
+ margin-bottom: 10px;
+}
+
+.services__v3 .icon {
+ display: inline-block;
+ position: relative;
+ color: var(--bs-primary) !important;
+}
+
+.services__v3 .icon:before {
+ content: "";
+ position: absolute;
+ z-index: -1;
+ width: 40px;
+ height: 40px;
+ right: -10px;
+ bottom: 0px;
+ border-radius: 50%;
+ background-color: rgba(var(--bs-secondary-rgb), 1);
+}
+
+.services__v3 .icon svg {
+ width: 50px;
+}
+
+.services__v3 .service-card {
+ border: 1px solid rgba(var(--inverse-color-rgb), 0.2);
+}
+
+.faq__v2 {
+ background-color: rgba(var(--inverse-color-rgb), 0.02);
+}
+
+.faq__v2 .subtitle {
+ background-color: rgba(var(--bs-secondary-rgb), 0.2);
+ color: var(--bs-primary);
+ display: inline-block;
+ padding: 5px 12px;
+ border-radius: 7px;
+ font-weight: 600;
+ font-size: 0.75rem;
+ margin-bottom: 10px;
+}
+
+.faq__v2 .custom-accordion {
+ --bs-accordion-bg: var(--bs-body-bg);
+ --bs-accordion-btn-icon: url("");
+ --bs-accordion-btn-active-icon: url("");
+}
+
+.faq__v2 .custom-accordion .accordion-button {
+ position: relative;
+ padding-right: 50px;
+}
+
+.faq__v2 .custom-accordion .accordion-button::after {
+ content: "\f4fe";
+ font-family: "bootstrap-icons" !important;
+ font-style: normal;
+ font-weight: 400 !important;
+ font-variant: normal;
+ text-transform: none;
+ right: 20px;
+ top: 15px;
+ width: 18px;
+ height: 14px;
+ font-size: 30px;
+ color: var(--inverse-color);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ line-height: 1;
+ position: absolute;
+ -webkit-font-smoothing: antialiased;
+}
+
+.faq__v2 .custom-accordion .accordion-button:not(.collapsed)::after {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ content: "\f2ea";
+}
+
+.faq__v2 .custom-accordion .accordion-item {
+ border: none;
+ margin-bottom: 10px;
+ border-radius: 10px;
+ overflow: hidden;
+ -webkit-transition: 0.3s all ease-in-out;
+ transition: 0.3s all ease-in-out;
+}
+
+.faq__v2 .custom-accordion .accordion-item .accordion-header .accordion-button {
+ outline: none;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ font-size: 18px;
+ font-weight: 500;
+ color: var(--bs-heading-color);
+ padding-top: 20px;
+ padding-bottom: 20px;
+ border: none;
+}
+
+.faq__v2 .custom-accordion .accordion-item .accordion-header .accordion-button:not(.collapsed) {
+ background-color: transparent;
+ color: var(--inverse-color);
+ -webkit-box-shadow: 0 1px 1px rgba(var(--inverse-color-rgb), 0.05);
+ box-shadow: 0 1px 1px rgba(var(--inverse-color-rgb), 0.05);
+}
+
+.faq__v2 .custom-accordion .accordion-item .accordion-body {
+ border-top: none;
+}
+
+.stats__v3 .content {
+ padding-top: 70px;
+ padding-bottom: 70px;
+ background-color: var(--bs-primary);
+ color: var(--bs-white);
+ overflow: hidden;
+ position: relative;
+}
+
+.stats__v3 .content h3 {
+ color: var(--bs-secondary);
+}
+
+.stats__v3 .content .rounded-borders {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ width: 500px;
+ height: 500px;
+}
+
+.stats__v3 .content .rounded-borders .rounded-border-1,
+.stats__v3 .content .rounded-borders .rounded-border-2,
+.stats__v3 .content .rounded-borders .rounded-border-3 {
+ border: 1px solid var(--bs-secondary);
+ width: 500px;
+ height: 500px;
+ border-radius: 50%;
+ position: absolute;
+}
+
+.stats__v3 .content .rounded-borders .rounded-border-1 {
+ right: 20px;
+ top: 20px;
+}
+
+.stats__v3 .content .rounded-borders .rounded-border-2 {
+ right: 40px;
+ top: 40px;
+}
+
+.testimonials__v2 .subtitle {
+ background-color: rgba(var(--bs-secondary-rgb), 0.2);
+ color: var(--bs-primary);
+ display: inline-block;
+ padding: 5px 12px;
+ border-radius: 7px;
+ font-weight: 600;
+ font-size: 0.75rem;
+ margin-bottom: 10px;
+}
+
+.testimonials__v2 .testimonial {
+ border: 1px solid rgba(var(--inverse-color-rgb), 0.2);
+}
+
+.testimonials__v2 .testimonial-author .author-img {
+ -webkit-box-flex: 0;
+ -ms-flex: 0 0 50px;
+ flex: 0 0 50px;
+}
+
+.contact__v2 .subtitle {
+ background-color: rgba(var(--bs-secondary-rgb), 0.2);
+ color: var(--bs-primary);
+ display: inline-block;
+ padding: 5px 12px;
+ border-radius: 7px;
+ font-weight: 600;
+ font-size: 0.75rem;
+ margin-bottom: 10px;
+}
+
+.contact__v2 .icon {
+ width: 50px;
+ height: 50px;
+ line-height: 50px;
+ text-align: center;
+ border: 1px solid rgba(var(--inverse-color-rgb), 0.2);
+ border-radius: 50%;
+}
+
+.footer {
+ border-top: 1px solid #111827;
+ background: var(--bg);
+ margin-top: 40px
+}
+
+.footer .container {
+ display: flex;
+ align-items: center;
+ gap: 18px;
+ justify-content: space-between;
+ padding: 16px 0
+}
+
+.footer a {
+ color: var(--muted)
+}
+
+.footer {
+ bottom: 0;
+ width: 95%;
+ text-align: center;
+}
+
+.footer h2,
+.footer h3,
+.footer h4 {
+ font-size: 16px;
+}
+
+.footer ul li {
+ padding: 0;
+ margin: 0 0 10px 0;
+}
+
+.footer a {
+ color: rgba(var(--inverse-color-rgb), 0.6);
+ text-decoration: none;
+}
+
+.footer a:hover {
+ color: var(--inverse-color);
+}
+
+.footer a .badge {
+ -webkit-transition: 0.3s all ease;
+ transition: 0.3s all ease;
+ background-color: rgba(var(--bs-primary-rgb), 0.1);
+ color: var(--bs-primary);
+}
+
+.footer a:hover .badge {
+ background-color: rgba(var(--bs-primary-rgb), 1);
+ color: var(--bs-white);
+}
+
+.footer .quick-contact i {
+ color: var(--inverse-color);
+}
+
+.footer .credits {
+ font-size: 13.5px;
+}
+
+#back-to-top {
+ position: fixed;
+ bottom: 0px;
+ right: 20px;
+ visibility: hidden;
+ opacity: 0;
+ background-color: var(--bs-primary);
+ color: white;
+ border: none;
+ border-radius: 50%;
+ padding: 10px;
+ cursor: pointer;
+ -webkit-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+ -webkit-transition: all 0.3s ease-in-out;
+ transition: all 0.3s ease-in-out;
+ z-index: 1000;
+ width: 40px;
+ height: 40px;
+}
+
+#back-to-top i {
+ font-size: 24px;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+}
+
+#back-to-top.show {
+ bottom: 20px;
+ opacity: 1;
+ visibility: visible;
+}
\ No newline at end of file
diff --git a/Website/assets/images/.DS_Store b/Website/assets/images/.DS_Store
new file mode 100644
index 0000000..ff3a152
Binary files /dev/null and b/Website/assets/images/.DS_Store differ
diff --git a/Website/assets/images/3d-render-1-min.jpg b/Website/assets/images/3d-render-1-min.jpg
new file mode 100644
index 0000000..f5106a5
Binary files /dev/null and b/Website/assets/images/3d-render-1-min.jpg differ
diff --git a/Website/assets/images/Facebook_icon.svg b/Website/assets/images/Facebook_icon.svg
new file mode 100644
index 0000000..c63c1ef
--- /dev/null
+++ b/Website/assets/images/Facebook_icon.svg
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/Google_icon.svg b/Website/assets/images/Google_icon.svg
new file mode 100644
index 0000000..088288f
--- /dev/null
+++ b/Website/assets/images/Google_icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Website/assets/images/about_2-min.jpg b/Website/assets/images/about_2-min.jpg
new file mode 100644
index 0000000..83fc2bb
Binary files /dev/null and b/Website/assets/images/about_2-min.jpg differ
diff --git a/Website/assets/images/arch-line-reverse.svg b/Website/assets/images/arch-line-reverse.svg
new file mode 100644
index 0000000..b2a57a7
--- /dev/null
+++ b/Website/assets/images/arch-line-reverse.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/Website/assets/images/arch-line.svg b/Website/assets/images/arch-line.svg
new file mode 100644
index 0000000..33e59af
--- /dev/null
+++ b/Website/assets/images/arch-line.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/Website/assets/images/astronaut.svg b/Website/assets/images/astronaut.svg
new file mode 100644
index 0000000..f403598
--- /dev/null
+++ b/Website/assets/images/astronaut.svg
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/block_squares.svg b/Website/assets/images/block_squares.svg
new file mode 100644
index 0000000..16d4ec0
--- /dev/null
+++ b/Website/assets/images/block_squares.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/business/business-img-1-min.jpg b/Website/assets/images/business/business-img-1-min.jpg
new file mode 100644
index 0000000..46ffb64
Binary files /dev/null and b/Website/assets/images/business/business-img-1-min.jpg differ
diff --git a/Website/assets/images/business/business-img-10-min.jpg b/Website/assets/images/business/business-img-10-min.jpg
new file mode 100644
index 0000000..6ff6926
Binary files /dev/null and b/Website/assets/images/business/business-img-10-min.jpg differ
diff --git a/Website/assets/images/business/business-img-2-min.jpg b/Website/assets/images/business/business-img-2-min.jpg
new file mode 100644
index 0000000..d6a37c9
Binary files /dev/null and b/Website/assets/images/business/business-img-2-min.jpg differ
diff --git a/Website/assets/images/business/business-img-3-min.jpg b/Website/assets/images/business/business-img-3-min.jpg
new file mode 100644
index 0000000..96e13a0
Binary files /dev/null and b/Website/assets/images/business/business-img-3-min.jpg differ
diff --git a/Website/assets/images/business/business-img-4-min.jpg b/Website/assets/images/business/business-img-4-min.jpg
new file mode 100644
index 0000000..0cf4630
Binary files /dev/null and b/Website/assets/images/business/business-img-4-min.jpg differ
diff --git a/Website/assets/images/business/business-img-5-min.jpg b/Website/assets/images/business/business-img-5-min.jpg
new file mode 100644
index 0000000..613f930
Binary files /dev/null and b/Website/assets/images/business/business-img-5-min.jpg differ
diff --git a/Website/assets/images/business/business-img-6-min.jpg b/Website/assets/images/business/business-img-6-min.jpg
new file mode 100644
index 0000000..82e7b27
Binary files /dev/null and b/Website/assets/images/business/business-img-6-min.jpg differ
diff --git a/Website/assets/images/business/business-img-7-min.jpg b/Website/assets/images/business/business-img-7-min.jpg
new file mode 100644
index 0000000..5a4cb71
Binary files /dev/null and b/Website/assets/images/business/business-img-7-min.jpg differ
diff --git a/Website/assets/images/business/business-img-8-min.jpg b/Website/assets/images/business/business-img-8-min.jpg
new file mode 100644
index 0000000..6aad1cb
Binary files /dev/null and b/Website/assets/images/business/business-img-8-min.jpg differ
diff --git a/Website/assets/images/business/business-img-9-min.jpg b/Website/assets/images/business/business-img-9-min.jpg
new file mode 100644
index 0000000..d924c86
Binary files /dev/null and b/Website/assets/images/business/business-img-9-min.jpg differ
diff --git a/Website/assets/images/card-expenses.png b/Website/assets/images/card-expenses.png
new file mode 100644
index 0000000..7859088
Binary files /dev/null and b/Website/assets/images/card-expenses.png differ
diff --git a/Website/assets/images/foto-main1.png b/Website/assets/images/foto-main1.png
new file mode 100644
index 0000000..dd8da1c
Binary files /dev/null and b/Website/assets/images/foto-main1.png differ
diff --git a/Website/assets/images/hero-bg-1-min.jpg b/Website/assets/images/hero-bg-1-min.jpg
new file mode 100644
index 0000000..a7fd595
Binary files /dev/null and b/Website/assets/images/hero-bg-1-min.jpg differ
diff --git a/Website/assets/images/hero-bg-2-min.jpg b/Website/assets/images/hero-bg-2-min.jpg
new file mode 100644
index 0000000..545dacc
Binary files /dev/null and b/Website/assets/images/hero-bg-2-min.jpg differ
diff --git a/Website/assets/images/hero-img-1-min.jpg b/Website/assets/images/hero-img-1-min.jpg
new file mode 100644
index 0000000..3f01b04
Binary files /dev/null and b/Website/assets/images/hero-img-1-min.jpg differ
diff --git a/Website/assets/images/hero-img-2-min.jpg b/Website/assets/images/hero-img-2-min.jpg
new file mode 100644
index 0000000..2ff019f
Binary files /dev/null and b/Website/assets/images/hero-img-2-min.jpg differ
diff --git a/Website/assets/images/img-1-min.jpg b/Website/assets/images/img-1-min.jpg
new file mode 100644
index 0000000..c34a8ec
Binary files /dev/null and b/Website/assets/images/img-1-min.jpg differ
diff --git a/Website/assets/images/img-10-min.jpg b/Website/assets/images/img-10-min.jpg
new file mode 100644
index 0000000..025403e
Binary files /dev/null and b/Website/assets/images/img-10-min.jpg differ
diff --git a/Website/assets/images/img-11-min.jpg b/Website/assets/images/img-11-min.jpg
new file mode 100644
index 0000000..b4540aa
Binary files /dev/null and b/Website/assets/images/img-11-min.jpg differ
diff --git a/Website/assets/images/img-12-min.jpg b/Website/assets/images/img-12-min.jpg
new file mode 100644
index 0000000..a923ae4
Binary files /dev/null and b/Website/assets/images/img-12-min.jpg differ
diff --git a/Website/assets/images/img-13-min.jpg b/Website/assets/images/img-13-min.jpg
new file mode 100644
index 0000000..80fedf3
Binary files /dev/null and b/Website/assets/images/img-13-min.jpg differ
diff --git a/Website/assets/images/img-14-min.jpg b/Website/assets/images/img-14-min.jpg
new file mode 100644
index 0000000..77b22f8
Binary files /dev/null and b/Website/assets/images/img-14-min.jpg differ
diff --git a/Website/assets/images/img-15-min.jpg b/Website/assets/images/img-15-min.jpg
new file mode 100644
index 0000000..e5300c8
Binary files /dev/null and b/Website/assets/images/img-15-min.jpg differ
diff --git a/Website/assets/images/img-16-min.jpg b/Website/assets/images/img-16-min.jpg
new file mode 100644
index 0000000..71eeeb7
Binary files /dev/null and b/Website/assets/images/img-16-min.jpg differ
diff --git a/Website/assets/images/img-2-min.jpg b/Website/assets/images/img-2-min.jpg
new file mode 100644
index 0000000..e323b7a
Binary files /dev/null and b/Website/assets/images/img-2-min.jpg differ
diff --git a/Website/assets/images/img-3-min.jpg b/Website/assets/images/img-3-min.jpg
new file mode 100644
index 0000000..630031d
Binary files /dev/null and b/Website/assets/images/img-3-min.jpg differ
diff --git a/Website/assets/images/img-4-min.jpg b/Website/assets/images/img-4-min.jpg
new file mode 100644
index 0000000..f145f99
Binary files /dev/null and b/Website/assets/images/img-4-min.jpg differ
diff --git a/Website/assets/images/img-5-min.jpg b/Website/assets/images/img-5-min.jpg
new file mode 100644
index 0000000..829af23
Binary files /dev/null and b/Website/assets/images/img-5-min.jpg differ
diff --git a/Website/assets/images/img-6-min.jpg b/Website/assets/images/img-6-min.jpg
new file mode 100644
index 0000000..48916c5
Binary files /dev/null and b/Website/assets/images/img-6-min.jpg differ
diff --git a/Website/assets/images/img-7-min.jpg b/Website/assets/images/img-7-min.jpg
new file mode 100644
index 0000000..b48f429
Binary files /dev/null and b/Website/assets/images/img-7-min.jpg differ
diff --git a/Website/assets/images/img-8-min.jpg b/Website/assets/images/img-8-min.jpg
new file mode 100644
index 0000000..22a310d
Binary files /dev/null and b/Website/assets/images/img-8-min.jpg differ
diff --git a/Website/assets/images/img-9-min.jpg b/Website/assets/images/img-9-min.jpg
new file mode 100644
index 0000000..7f50488
Binary files /dev/null and b/Website/assets/images/img-9-min.jpg differ
diff --git a/Website/assets/images/img1-min.jpg b/Website/assets/images/img1-min.jpg
new file mode 100644
index 0000000..6d77275
Binary files /dev/null and b/Website/assets/images/img1-min.jpg differ
diff --git a/Website/assets/images/logo-dark.svg b/Website/assets/images/logo-dark.svg
new file mode 100644
index 0000000..c992d28
--- /dev/null
+++ b/Website/assets/images/logo-dark.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo-light.svg b/Website/assets/images/logo-light.svg
new file mode 100644
index 0000000..1be0782
--- /dev/null
+++ b/Website/assets/images/logo-light.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/.DS_Store b/Website/assets/images/logo/.DS_Store
new file mode 100644
index 0000000..f5895ce
Binary files /dev/null and b/Website/assets/images/logo/.DS_Store differ
diff --git a/Website/assets/images/logo/actual-size/.DS_Store b/Website/assets/images/logo/actual-size/.DS_Store
new file mode 100644
index 0000000..784b5ea
Binary files /dev/null and b/Website/assets/images/logo/actual-size/.DS_Store differ
diff --git a/Website/assets/images/logo/actual-size/logo-air-bnb__black.svg b/Website/assets/images/logo/actual-size/logo-air-bnb__black.svg
new file mode 100644
index 0000000..ee072da
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-air-bnb__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/actual-size/logo-american-apparel__black.svg b/Website/assets/images/logo/actual-size/logo-american-apparel__black.svg
new file mode 100644
index 0000000..5a6f44a
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-american-apparel__black.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/actual-size/logo-apple__black.svg b/Website/assets/images/logo/actual-size/logo-apple__black.svg
new file mode 100644
index 0000000..f09a53f
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-apple__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/actual-size/logo-ebay__black-1.svg b/Website/assets/images/logo/actual-size/logo-ebay__black-1.svg
new file mode 100644
index 0000000..3658a56
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-ebay__black-1.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/actual-size/logo-ebay__black.svg b/Website/assets/images/logo/actual-size/logo-ebay__black.svg
new file mode 100644
index 0000000..8e76e38
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-ebay__black.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/actual-size/logo-google__black.svg b/Website/assets/images/logo/actual-size/logo-google__black.svg
new file mode 100644
index 0000000..e0cee2b
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-google__black.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/actual-size/logo-ibm__black.svg b/Website/assets/images/logo/actual-size/logo-ibm__black.svg
new file mode 100644
index 0000000..86ba469
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-ibm__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/actual-size/logo-invision__black.svg b/Website/assets/images/logo/actual-size/logo-invision__black.svg
new file mode 100644
index 0000000..d8d8803
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-invision__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/actual-size/logo-microsoft_black.svg b/Website/assets/images/logo/actual-size/logo-microsoft_black.svg
new file mode 100644
index 0000000..23b01c9
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-microsoft_black.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/actual-size/logo-netflix__black.svg b/Website/assets/images/logo/actual-size/logo-netflix__black.svg
new file mode 100644
index 0000000..ff9c372
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-netflix__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/actual-size/logo-uber__black.svg b/Website/assets/images/logo/actual-size/logo-uber__black.svg
new file mode 100644
index 0000000..57dd2d1
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-uber__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/actual-size/logo-youtube__black.svg b/Website/assets/images/logo/actual-size/logo-youtube__black.svg
new file mode 100644
index 0000000..1ce365b
--- /dev/null
+++ b/Website/assets/images/logo/actual-size/logo-youtube__black.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-air-bnb.svg b/Website/assets/images/logo/logo-air-bnb.svg
new file mode 100644
index 0000000..0a9ee8d
--- /dev/null
+++ b/Website/assets/images/logo/logo-air-bnb.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-air-bnb__black.svg b/Website/assets/images/logo/logo-air-bnb__black.svg
new file mode 100644
index 0000000..adccc40
--- /dev/null
+++ b/Website/assets/images/logo/logo-air-bnb__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-american-apparel.svg b/Website/assets/images/logo/logo-american-apparel.svg
new file mode 100644
index 0000000..15a9532
--- /dev/null
+++ b/Website/assets/images/logo/logo-american-apparel.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-american-apparel__black.svg b/Website/assets/images/logo/logo-american-apparel__black.svg
new file mode 100644
index 0000000..9e13bc3
--- /dev/null
+++ b/Website/assets/images/logo/logo-american-apparel__black.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-apple.svg b/Website/assets/images/logo/logo-apple.svg
new file mode 100644
index 0000000..fdbf8d0
--- /dev/null
+++ b/Website/assets/images/logo/logo-apple.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-apple__black.svg b/Website/assets/images/logo/logo-apple__black.svg
new file mode 100644
index 0000000..e58fb43
--- /dev/null
+++ b/Website/assets/images/logo/logo-apple__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-ebay-1.svg b/Website/assets/images/logo/logo-ebay-1.svg
new file mode 100644
index 0000000..79389f8
--- /dev/null
+++ b/Website/assets/images/logo/logo-ebay-1.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-ebay.svg b/Website/assets/images/logo/logo-ebay.svg
new file mode 100644
index 0000000..cfc51e4
--- /dev/null
+++ b/Website/assets/images/logo/logo-ebay.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-ebay__black-1.svg b/Website/assets/images/logo/logo-ebay__black-1.svg
new file mode 100644
index 0000000..1c5012b
--- /dev/null
+++ b/Website/assets/images/logo/logo-ebay__black-1.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-ebay__black.svg b/Website/assets/images/logo/logo-ebay__black.svg
new file mode 100644
index 0000000..8098db2
--- /dev/null
+++ b/Website/assets/images/logo/logo-ebay__black.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-google.svg b/Website/assets/images/logo/logo-google.svg
new file mode 100644
index 0000000..8d979dc
--- /dev/null
+++ b/Website/assets/images/logo/logo-google.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-google__black.svg b/Website/assets/images/logo/logo-google__black.svg
new file mode 100644
index 0000000..317374e
--- /dev/null
+++ b/Website/assets/images/logo/logo-google__black.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-ibm.svg b/Website/assets/images/logo/logo-ibm.svg
new file mode 100644
index 0000000..d811ff2
--- /dev/null
+++ b/Website/assets/images/logo/logo-ibm.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-ibm__black.svg b/Website/assets/images/logo/logo-ibm__black.svg
new file mode 100644
index 0000000..d9cb4e9
--- /dev/null
+++ b/Website/assets/images/logo/logo-ibm__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-invision.svg b/Website/assets/images/logo/logo-invision.svg
new file mode 100644
index 0000000..84d31f1
--- /dev/null
+++ b/Website/assets/images/logo/logo-invision.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-invision__black.svg b/Website/assets/images/logo/logo-invision__black.svg
new file mode 100644
index 0000000..b29cebe
--- /dev/null
+++ b/Website/assets/images/logo/logo-invision__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-microsoft.svg b/Website/assets/images/logo/logo-microsoft.svg
new file mode 100644
index 0000000..64bd9cd
--- /dev/null
+++ b/Website/assets/images/logo/logo-microsoft.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-microsoft__black.svg b/Website/assets/images/logo/logo-microsoft__black.svg
new file mode 100644
index 0000000..3fd26cf
--- /dev/null
+++ b/Website/assets/images/logo/logo-microsoft__black.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-netflix.svg b/Website/assets/images/logo/logo-netflix.svg
new file mode 100644
index 0000000..5745fd4
--- /dev/null
+++ b/Website/assets/images/logo/logo-netflix.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-netflix__black.svg b/Website/assets/images/logo/logo-netflix__black.svg
new file mode 100644
index 0000000..6e0863e
--- /dev/null
+++ b/Website/assets/images/logo/logo-netflix__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-uber.svg b/Website/assets/images/logo/logo-uber.svg
new file mode 100644
index 0000000..008d5fc
--- /dev/null
+++ b/Website/assets/images/logo/logo-uber.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-uber__black.svg b/Website/assets/images/logo/logo-uber__black.svg
new file mode 100644
index 0000000..f81a3c7
--- /dev/null
+++ b/Website/assets/images/logo/logo-uber__black.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-youtube.svg b/Website/assets/images/logo/logo-youtube.svg
new file mode 100644
index 0000000..0fbf451
--- /dev/null
+++ b/Website/assets/images/logo/logo-youtube.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/logo/logo-youtube__black.svg b/Website/assets/images/logo/logo-youtube__black.svg
new file mode 100644
index 0000000..57aa918
--- /dev/null
+++ b/Website/assets/images/logo/logo-youtube__black.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Website/assets/images/person-sq-1-min.jpg b/Website/assets/images/person-sq-1-min.jpg
new file mode 100644
index 0000000..ebef70a
Binary files /dev/null and b/Website/assets/images/person-sq-1-min.jpg differ
diff --git a/Website/assets/images/person-sq-2-min.jpg b/Website/assets/images/person-sq-2-min.jpg
new file mode 100644
index 0000000..a3cd500
Binary files /dev/null and b/Website/assets/images/person-sq-2-min.jpg differ
diff --git a/Website/assets/images/person-sq-3-min.jpg b/Website/assets/images/person-sq-3-min.jpg
new file mode 100644
index 0000000..433280e
Binary files /dev/null and b/Website/assets/images/person-sq-3-min.jpg differ
diff --git a/Website/assets/images/person-sq-4-min.jpg b/Website/assets/images/person-sq-4-min.jpg
new file mode 100644
index 0000000..8fa7b38
Binary files /dev/null and b/Website/assets/images/person-sq-4-min.jpg differ
diff --git a/Website/assets/images/person-sq-5-min.jpg b/Website/assets/images/person-sq-5-min.jpg
new file mode 100644
index 0000000..cd3cc67
Binary files /dev/null and b/Website/assets/images/person-sq-5-min.jpg differ
diff --git a/Website/assets/images/person-sq-6-min.jpg b/Website/assets/images/person-sq-6-min.jpg
new file mode 100644
index 0000000..a70f2cf
Binary files /dev/null and b/Website/assets/images/person-sq-6-min.jpg differ
diff --git a/Website/assets/images/person-sq-7-min.jpg b/Website/assets/images/person-sq-7-min.jpg
new file mode 100644
index 0000000..c9ea67e
Binary files /dev/null and b/Website/assets/images/person-sq-7-min.jpg differ
diff --git a/Website/assets/images/person-sq-8-min.jpg b/Website/assets/images/person-sq-8-min.jpg
new file mode 100644
index 0000000..06f8e8b
Binary files /dev/null and b/Website/assets/images/person-sq-8-min.jpg differ
diff --git a/Website/assets/images/person-sq-9-min.jpg b/Website/assets/images/person-sq-9-min.jpg
new file mode 100644
index 0000000..5e77dce
Binary files /dev/null and b/Website/assets/images/person-sq-9-min.jpg differ
diff --git a/Website/assets/images/portfolio-details-img-1-min.jpg b/Website/assets/images/portfolio-details-img-1-min.jpg
new file mode 100644
index 0000000..e73cc22
Binary files /dev/null and b/Website/assets/images/portfolio-details-img-1-min.jpg differ
diff --git a/Website/assets/images/portfolio-details-img-2-min.jpg b/Website/assets/images/portfolio-details-img-2-min.jpg
new file mode 100644
index 0000000..72b1d81
Binary files /dev/null and b/Website/assets/images/portfolio-details-img-2-min.jpg differ
diff --git a/Website/assets/images/portfolio-details-img-3-min.jpg b/Website/assets/images/portfolio-details-img-3-min.jpg
new file mode 100644
index 0000000..0a992c1
Binary files /dev/null and b/Website/assets/images/portfolio-details-img-3-min.jpg differ
diff --git a/Website/assets/images/portfolio-details-img-4-min.jpg b/Website/assets/images/portfolio-details-img-4-min.jpg
new file mode 100644
index 0000000..88018c0
Binary files /dev/null and b/Website/assets/images/portfolio-details-img-4-min.jpg differ
diff --git a/Website/assets/images/portfolio-details-img-5-min.jpg b/Website/assets/images/portfolio-details-img-5-min.jpg
new file mode 100644
index 0000000..9996315
Binary files /dev/null and b/Website/assets/images/portfolio-details-img-5-min.jpg differ
diff --git a/Website/assets/images/portfolio-details-img-6-min.jpg b/Website/assets/images/portfolio-details-img-6-min.jpg
new file mode 100644
index 0000000..cb039b0
Binary files /dev/null and b/Website/assets/images/portfolio-details-img-6-min.jpg differ
diff --git a/Website/assets/images/quote.svg b/Website/assets/images/quote.svg
new file mode 100644
index 0000000..70bc94a
--- /dev/null
+++ b/Website/assets/images/quote.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/Website/assets/images/scribble-1.svg b/Website/assets/images/scribble-1.svg
new file mode 100644
index 0000000..880a4a1
--- /dev/null
+++ b/Website/assets/images/scribble-1.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/Website/assets/images/scribble-2.svg b/Website/assets/images/scribble-2.svg
new file mode 100644
index 0000000..92244c3
--- /dev/null
+++ b/Website/assets/images/scribble-2.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/Website/assets/js/.DS_Store b/Website/assets/js/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/Website/assets/js/.DS_Store differ
diff --git a/Website/assets/js/custom.js b/Website/assets/js/custom.js
new file mode 100644
index 0000000..a23e789
--- /dev/null
+++ b/Website/assets/js/custom.js
@@ -0,0 +1,570 @@
+document.addEventListener("DOMContentLoaded", function () {
+
+
+
+ const sections = document.querySelectorAll(".section");
+ const navLinks = document.querySelectorAll(".fbs__net-navbar .scroll-link");
+
+ function removeActiveClasses() {
+ if (navLinks) {
+ navLinks.forEach((link) => link.classList.remove("active"));
+ }
+ }
+
+ function addActiveClass(currentSectionId) {
+ const activeLink = document.querySelector(
+ `.fbs__net-navbar .scroll-link[href="#${currentSectionId}"]`
+ );
+ if (activeLink) {
+ activeLink.classList.add("active");
+ }
+ }
+
+ function openNewPatient(){
+ document.getElementById('modal-new').showModal();
+}
+
+function exportCSV(){
+ const rows = [['Paciente','CPF','Idade','Status']];
+ document.querySelectorAll('#patients tbody tr').forEach(tr=>{
+ const tds = [...tr.querySelectorAll('td')].map(td=>td.innerText.replace(/\n.*/,'').trim());
+ rows.push([tds[0],tds[1],tds[2],tds[3]]);
+ });
+ const csv = rows.map(r=>r.map(s=>`"${s.replaceAll('"','""')}"`).join(',')).join('\n');
+ const blob = new Blob([csv], {type:'text/csv;charset=utf-8;'});
+ const url = URL.createObjectURL(blob);
+ const a = Object.assign(document.createElement('a'), {href:url, download:'pacientes.csv'});
+ document.body.appendChild(a); a.click(); a.remove();
+ setTimeout(()=>URL.revokeObjectURL(url), 1000);
+}
+
+function filterTable(q){
+ q = (q||'').toLowerCase();
+ document.querySelectorAll('#patients tbody tr').forEach(tr => {
+ const text = tr.innerText.toLowerCase();
+ tr.style.display = text.includes(q) ? '' : 'none';
+ });
+}
+
+ function getCurrentSection() {
+ let currentSection = null;
+ let minDistance = Infinity;
+ if (sections) {
+ sections.forEach((section) => {
+ const rect = section.getBoundingClientRect();
+ const distance = Math.abs(rect.top - window.innerHeight / 4);
+
+ if (distance < minDistance && rect.top < window.innerHeight) {
+ minDistance = distance;
+ currentSection = section.getAttribute("id");
+ }
+ });
+ }
+
+ return currentSection;
+ }
+
+ function updateActiveLink() {
+ const currentSectionId = getCurrentSection();
+ if (currentSectionId) {
+ removeActiveClasses();
+ addActiveClass(currentSectionId);
+ }
+ }
+
+ window.addEventListener("scroll", updateActiveLink);
+
+ const portfolioGrid = document.querySelector('#portfolio-grid');
+ if (portfolioGrid) {
+ var iso = new Isotope("#portfolio-grid", {
+ itemSelector: ".portfolio-item",
+ layoutMode: "masonry",
+ });
+
+ if (iso) {
+ iso.on("layoutComplete", updateActiveLink);
+
+ imagesLoaded("#portfolio-grid", function () {
+ iso.layout();
+ updateActiveLink();
+ });
+ }
+
+ var filterButtons = document.querySelectorAll(".filter-button");
+ if (filterButtons) {
+ filterButtons.forEach(function (button) {
+ button.addEventListener("click", function (e) {
+ e.preventDefault();
+ var filterValue = button.getAttribute("data-filter");
+ iso.arrange({ filter: filterValue });
+
+ filterButtons.forEach(function (btn) {
+ btn.classList.remove("active");
+ });
+ button.classList.add("active");
+ updateActiveLink();
+ });
+ });
+ }
+
+ updateActiveLink();
+ }
+});
+
+const navbarScrollInit = () => {
+ var navbar = document.querySelector(".fbs__net-navbar");
+
+ var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
+ if (navbar) {
+ if (scrollTop > 0) {
+ navbar.classList.add("active");
+ } else {
+ navbar.classList.remove("active");
+ }
+ }
+};
+
+const navbarInit = () => {
+ document.querySelectorAll('.dropdown-toggle[href="#"]').forEach(function (el, index) {
+ el.addEventListener("click", function (event) {
+ event.stopPropagation();
+ });
+ });
+};
+
+// ======= Marquee =======
+const logoMarqueeInit = () => {
+ const wrapper = document.querySelector(".logo-wrapper");
+ const boxes = gsap.utils.toArray(".logo-item");
+
+ if (boxes.length > 0) {
+ const loop = horizontalLoop(boxes, {
+ paused: false,
+ repeat: -1,
+ speed: 0.25,
+ reversed: false,
+ });
+
+ function horizontalLoop(items, config) {
+ items = gsap.utils.toArray(items);
+ config = config || {};
+ let tl = gsap.timeline({
+ repeat: config.repeat,
+ paused: config.paused,
+ defaults: { ease: "none" },
+ onReverseComplete: () =>
+ tl.totalTime(tl.rawTime() + tl.duration() * 100),
+ }),
+ length = items.length,
+ startX = items[0].offsetLeft,
+ times = [],
+ widths = [],
+ xPercents = [],
+ curIndex = 0,
+ pixelsPerSecond = (config.speed || 1) * 100,
+ snap =
+ config.snap === false ? (v) => v : gsap.utils.snap(config.snap || 1), // some browsers shift by a pixel to accommodate flex layouts, so for example if width is 20% the first element's width might be 242px, and the next 243px, alternating back and forth. So we snap to 5 percentage points to make things look more natural
+ totalWidth,
+ curX,
+ distanceToStart,
+ distanceToLoop,
+ item,
+ i;
+ gsap.set(items, {
+ // convert "x" to "xPercent" to make things responsive, and populate the widths/xPercents Arrays to make lookups faster.
+ xPercent: (i, el) => {
+ let w = (widths[i] = parseFloat(gsap.getProperty(el, "width", "px")));
+ xPercents[i] = snap(
+ (parseFloat(gsap.getProperty(el, "x", "px")) / w) * 100 +
+ gsap.getProperty(el, "xPercent")
+ );
+ return xPercents[i];
+ },
+ });
+ gsap.set(items, { x: 0 });
+ totalWidth =
+ items[length - 1].offsetLeft +
+ (xPercents[length - 1] / 100) * widths[length - 1] -
+ startX +
+ items[length - 1].offsetWidth *
+ gsap.getProperty(items[length - 1], "scaleX") +
+ (parseFloat(config.paddingRight) || 0);
+ for (i = 0; i < length; i++) {
+ item = items[i];
+ curX = (xPercents[i] / 100) * widths[i];
+ distanceToStart = item.offsetLeft + curX - startX;
+ distanceToLoop =
+ distanceToStart + widths[i] * gsap.getProperty(item, "scaleX");
+ tl.to(
+ item,
+ {
+ xPercent: snap(((curX - distanceToLoop) / widths[i]) * 100),
+ duration: distanceToLoop / pixelsPerSecond,
+ },
+ 0
+ )
+ .fromTo(
+ item,
+ {
+ xPercent: snap(
+ ((curX - distanceToLoop + totalWidth) / widths[i]) * 100
+ ),
+ },
+ {
+ xPercent: xPercents[i],
+ duration:
+ (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond,
+ immediateRender: false,
+ },
+ distanceToLoop / pixelsPerSecond
+ )
+ .add("label" + i, distanceToStart / pixelsPerSecond);
+ times[i] = distanceToStart / pixelsPerSecond;
+ }
+ function toIndex(index, vars) {
+ vars = vars || {};
+ Math.abs(index - curIndex) > length / 2 &&
+ (index += index > curIndex ? -length : length); // always go in the shortest direction
+ let newIndex = gsap.utils.wrap(0, length, index),
+ time = times[newIndex];
+ if (time > tl.time() !== index > curIndex) {
+ // if we're wrapping the timeline's playhead, make the proper adjustments
+ vars.modifiers = { time: gsap.utils.wrap(0, tl.duration()) };
+ time += tl.duration() * (index > curIndex ? 1 : -1);
+ }
+ curIndex = newIndex;
+ vars.overwrite = true;
+ return tl.tweenTo(time, vars);
+ }
+ tl.next = (vars) => toIndex(curIndex + 1, vars);
+ tl.previous = (vars) => toIndex(curIndex - 1, vars);
+ tl.current = () => curIndex;
+ tl.toIndex = (index, vars) => toIndex(index, vars);
+ tl.times = times;
+ tl.progress(1, true).progress(0, true); // pre-render for performance
+ if (config.reversed) {
+ tl.vars.onReverseComplete();
+ tl.reverse();
+ }
+ return tl;
+ }
+ }
+};
+
+document.addEventListener("DOMContentLoaded", logoMarqueeInit);
+
+// ======= Navbar Scroll =======
+document.addEventListener("DOMContentLoaded", function () {
+ logoMarqueeInit();
+ navbarInit();
+ window.addEventListener("scroll", navbarScrollInit);
+});
+
+// ======= Swiper =======
+const swiperInit = () => {
+ var swiper = new Swiper(".testimonialSwiper", {
+ slidesPerView: 1,
+ speed: 700,
+ spaceBetween: 30,
+ loop: true,
+ pagination: {
+ el: ".swiper-pagination",
+ clickable: true,
+ },
+ breakpoints: {
+ 640: {
+ slidesPerView: 1.5,
+ spaceBetween: 20,
+ },
+ 768: {
+ slidesPerView: 2.5,
+ spaceBetween: 30,
+ },
+ 1024: {
+ slidesPerView: 2.5,
+ spaceBetween: 30,
+ },
+ },
+ navigation: {
+ nextEl: ".custom-button-next",
+ prevEl: ".custom-button-prev",
+ },
+ });
+
+ const progressCircle = document.querySelector(".autoplay-progress svg");
+ const progressContent = document.querySelector(".autoplay-progress span");
+ if (progressCircle && progressContent ) {
+ var swiper2 = new Swiper(".sliderSwiper", {
+ slidesPerView: 1,
+ speed: 700,
+ spaceBetween: 0,
+ loop: true,
+ centeredSlides: true,
+ autoplay: {
+ delay: 7000,
+ disableOnInteraction: false
+ },
+ pagination: {
+ el: ".swiper-pagination",
+ clickable: true,
+ },
+ navigation: {
+ nextEl: ".custom-button-next",
+ prevEl: ".custom-button-prev",
+ },
+
+ on: {
+ autoplayTimeLeft(s, time, progress) {
+ progressCircle.style.setProperty("--progress", 1 - progress);
+ progressContent.textContent = `${Math.ceil(time / 1000)}s`;
+ }
+ }
+ });
+ }
+
+};
+
+document.addEventListener("DOMContentLoaded", swiperInit);
+
+// ======= Glightbox =======
+const glightBoxInit = () => {
+ const lightbox = GLightbox({
+ touchNavigation: true,
+ loop: true,
+ autoplayVideos: true,
+ });
+};
+document.addEventListener("DOMContentLoaded", glightBoxInit);
+
+// ======= BS OffCanvass =======
+const bsOffCanvasInit = () => {
+ var offcanvasElement = document.getElementById("fbs__net-navbars");
+ if (offcanvasElement) {
+ offcanvasElement.addEventListener("show.bs.offcanvas", function () {
+ document.body.classList.add("offcanvas-active");
+ });
+
+ offcanvasElement.addEventListener("hidden.bs.offcanvas", function () {
+ document.body.classList.remove("offcanvas-active");
+ });
+ }
+};
+document.addEventListener("DOMContentLoaded", bsOffCanvasInit);
+
+// ======= Back To Top =======
+const backToTopInit = () => {
+ const backToTopButton = document.getElementById("back-to-top");
+ if (backToTopButton) {
+ window.addEventListener("scroll", () => {
+ if (window.scrollY > 170) {
+ backToTopButton.classList.add("show");
+ } else {
+ backToTopButton.classList.remove("show");
+ }
+ });
+ backToTopButton.addEventListener("click", () => {
+ window.scrollTo({
+ top: 0,
+ behavior: "smooth",
+ });
+ });
+ }
+};
+
+document.addEventListener("DOMContentLoaded", backToTopInit);
+
+
+// ======= Inline SVG =======
+const inlineSvgInit = () => {
+ const imgElements = document.querySelectorAll(".js-img-to-inline-svg");
+ if (imgElements) {
+ imgElements.forEach((imgElement) => {
+ const imgURL = imgElement.getAttribute("src");
+
+ fetch(imgURL)
+ .then((response) => response.text())
+ .then((svgText) => {
+ const parser = new DOMParser();
+ const svgDocument = parser.parseFromString(svgText, "image/svg+xml");
+ const svgElement = svgDocument.documentElement;
+
+ Array.from(imgElement.attributes).forEach((attr) => {
+ if (attr.name !== "class") {
+ svgElement.setAttribute(attr.name, attr.value);
+ } else {
+ const classes = attr.value
+ .split(" ")
+ .filter((className) => className !== "js-img-to-inline-svg");
+ if (classes.length > 0) {
+ svgElement.setAttribute("class", classes.join(" "));
+ }
+ }
+ });
+
+ imgElement.replaceWith(svgElement);
+ })
+ .catch((error) => console.error("Error fetching SVG:", error));
+ });
+ }
+};
+
+document.addEventListener("DOMContentLoaded", inlineSvgInit);
+
+// ======= AOS =======
+const aosInit = () => {
+ AOS.init({
+ duration: 800,
+ easing: 'slide',
+ once: true
+ });
+}
+document.addEventListener("DOMContentLoaded", aosInit);
+
+// ======= PureCounter =======
+const pureCounterInit = () => {
+ new PureCounter({
+ selector: ".purecounter",
+ });
+}
+document.addEventListener("DOMContentLoaded", pureCounterInit);
+
+// ======= Disable Click Navbar Dropdown =======
+const addHoverEvents = (dropdown) => {
+ const dropdownToggle = dropdown.querySelector('.dropdown-toggle');
+
+ const preventClick = (event) => event.preventDefault();
+ const showDropdown = () => {
+ dropdown.classList.add('show');
+ dropdownToggle.setAttribute('aria-expanded', 'true');
+ const dropdownMenu = dropdown.querySelector('.dropdown-menu');
+ dropdownMenu.classList.add('show');
+ };
+ const hideDropdown = () => {
+ dropdown.classList.remove('show');
+ dropdownToggle.setAttribute('aria-expanded', 'false');
+ const dropdownMenu = dropdown.querySelector('.dropdown-menu');
+ dropdownMenu.classList.remove('show');
+ };
+
+ // Disable the click event for toggling the dropdown
+ dropdownToggle.addEventListener('click', preventClick);
+
+ // Open dropdown on hover
+ dropdown.addEventListener('mouseover', showDropdown);
+
+ // Close dropdown when mouse leaves
+ dropdown.addEventListener('mouseleave', hideDropdown);
+
+ // Store references to the event listeners for later removal
+ dropdown.__events = { preventClick, showDropdown, hideDropdown };
+};
+
+const removeHoverEvents = (dropdown) => {
+ const dropdownToggle = dropdown.querySelector('.dropdown-toggle');
+ const { preventClick, showDropdown, hideDropdown } = dropdown.__events || {};
+
+ if (preventClick) {
+ // Remove the event listeners
+ dropdownToggle.removeEventListener('click', preventClick);
+ dropdown.removeEventListener('mouseover', showDropdown);
+ dropdown.removeEventListener('mouseleave', hideDropdown);
+
+ // Remove the reference to the stored events
+ delete dropdown.__events;
+ }
+};
+
+const handleNavbarEvents = () => {
+ const dropdowns = document.querySelectorAll('.navbar .dropdown');
+ const dropstarts = document.querySelectorAll('.navbar .dropstart');
+ const dropends = document.querySelectorAll('.navbar .dropend');
+
+ if (window.innerWidth >= 992) {
+
+ // Add hover events to dropdowns
+ dropdowns.forEach(addHoverEvents);
+ dropstarts.forEach(addHoverEvents);
+ dropends.forEach(addHoverEvents);
+ } else {
+
+ // Remove hover events from dropdowns
+ dropdowns.forEach(removeHoverEvents);
+ dropstarts.forEach(removeHoverEvents);
+ dropends.forEach(removeHoverEvents);
+ }
+};
+
+// Function to handle resizing
+const handleResize = () => {
+ const dropdowns = document.querySelectorAll('.navbar .dropdown');
+ const dropstarts = document.querySelectorAll('.navbar .dropstart');
+ const dropends = document.querySelectorAll('.navbar .dropend');
+
+ // Remove hover events before rechecking window size
+ dropdowns.forEach(removeHoverEvents);
+ dropstarts.forEach(removeHoverEvents);
+ dropends.forEach(removeHoverEvents);
+
+ // Re-apply hover events based on window size
+ handleNavbarEvents();
+};
+
+// Call the function on resize event and initially
+window.addEventListener('resize', handleResize);
+handleNavbarEvents();
+
+
+
+// ======= Coming Soon Countdown =======
+const countdownInit = () => {
+
+ // Get the current year
+ const currentYear = new Date().getFullYear();
+ const nextYear = currentYear + 1;
+ const launchDate = new Date(`December 31, ${nextYear} 23:59:59`).getTime();
+
+ // Change this "December 31, 2024 23:59:59" to your your website launch date
+ // const launchDate = new Date("December 31, 2024 23:59:59").getTime();
+
+
+ const x = setInterval(function () {
+
+ const now = new Date().getTime();
+
+ const distance = launchDate - now;
+
+ const days = Math.floor(distance / (1000 * 60 * 60 * 24));
+ const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
+ const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
+ const seconds = Math.floor((distance % (1000 * 60)) / 1000);
+
+ // Output the result in an element with id
+ const daysEl = document.getElementById("days");
+ const hoursEl = document.getElementById("hours");
+ const minutesEl = document.getElementById("minutes");
+ const secondsEl = document.getElementById("seconds");
+ if (daysEl) {
+ daysEl.innerText = days;
+ }
+ if (hoursEl) {
+ hoursEl.innerText = hours;
+ }
+ if (minutesEl) {
+ minutesEl.innerText = minutes;
+ }
+ if (secondsEl) {
+ secondsEl.innerText = seconds;
+ }
+
+ // If the count down is finished, write some text
+ if (distance < 0) {
+ clearInterval(x);
+ document.querySelector(".countdown").innerText = "Launched!";
+ }
+ }, 1000);
+};
+document.addEventListener('DOMContentLoaded', countdownInit);
+
+window.openNewPatient = openNewPatient;
+window.exportCSV = exportCSV;
+window.filterTable = filterTable;
\ No newline at end of file
diff --git a/Website/assets/vendors/.DS_Store b/Website/assets/vendors/.DS_Store
new file mode 100644
index 0000000..ed5d414
Binary files /dev/null and b/Website/assets/vendors/.DS_Store differ
diff --git a/Website/assets/vendors/PHPMailer/index.html b/Website/assets/vendors/PHPMailer/index.html
new file mode 100644
index 0000000..91535fa
--- /dev/null
+++ b/Website/assets/vendors/PHPMailer/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+ Silence is golden.
+
+
+
+
+
\ No newline at end of file
diff --git a/Website/assets/vendors/PHPMailer/src/DSNConfigurator.php b/Website/assets/vendors/PHPMailer/src/DSNConfigurator.php
new file mode 100644
index 0000000..7058c1f
--- /dev/null
+++ b/Website/assets/vendors/PHPMailer/src/DSNConfigurator.php
@@ -0,0 +1,245 @@
+
+ * @author Jim Jagielski (jimjag)
+ * @author Andy Prevost (codeworxtech)
+ * @author Brent R. Matzelle (original founder)
+ * @copyright 2012 - 2023 Marcus Bointon
+ * @copyright 2010 - 2012 Jim Jagielski
+ * @copyright 2004 - 2009 Andy Prevost
+ * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
+ * @note This program is distributed in the hope that it will be useful - WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+namespace PHPMailer\PHPMailer;
+
+/**
+ * Configure PHPMailer with DSN string.
+ *
+ * @see https://en.wikipedia.org/wiki/Data_source_name
+ *
+ * @author Oleg Voronkovich
+ */
+class DSNConfigurator
+{
+ /**
+ * Create new PHPMailer instance configured by DSN.
+ *
+ * @param string $dsn DSN
+ * @param bool $exceptions Should we throw external exceptions?
+ *
+ * @return PHPMailer
+ */
+ public static function mailer($dsn, $exceptions = null)
+ {
+ static $configurator = null;
+
+ if (null === $configurator) {
+ $configurator = new DSNConfigurator();
+ }
+
+ return $configurator->configure(new PHPMailer($exceptions), $dsn);
+ }
+
+ /**
+ * Configure PHPMailer instance with DSN string.
+ *
+ * @param PHPMailer $mailer PHPMailer instance
+ * @param string $dsn DSN
+ *
+ * @return PHPMailer
+ */
+ public function configure(PHPMailer $mailer, $dsn)
+ {
+ $config = $this->parseDSN($dsn);
+
+ $this->applyConfig($mailer, $config);
+
+ return $mailer;
+ }
+
+ /**
+ * Parse DSN string.
+ *
+ * @param string $dsn DSN
+ *
+ * @throws Exception If DSN is malformed
+ *
+ * @return array Configuration
+ */
+ private function parseDSN($dsn)
+ {
+ $config = $this->parseUrl($dsn);
+
+ if (false === $config || !isset($config['scheme']) || !isset($config['host'])) {
+ throw new Exception('Malformed DSN');
+ }
+
+ if (isset($config['query'])) {
+ parse_str($config['query'], $config['query']);
+ }
+
+ return $config;
+ }
+
+ /**
+ * Apply configuration to mailer.
+ *
+ * @param PHPMailer $mailer PHPMailer instance
+ * @param array $config Configuration
+ *
+ * @throws Exception If scheme is invalid
+ */
+ private function applyConfig(PHPMailer $mailer, $config)
+ {
+ switch ($config['scheme']) {
+ case 'mail':
+ $mailer->isMail();
+ break;
+ case 'sendmail':
+ $mailer->isSendmail();
+ break;
+ case 'qmail':
+ $mailer->isQmail();
+ break;
+ case 'smtp':
+ case 'smtps':
+ $mailer->isSMTP();
+ $this->configureSMTP($mailer, $config);
+ break;
+ default:
+ throw new Exception(
+ sprintf(
+ 'Invalid scheme: "%s". Allowed values: "mail", "sendmail", "qmail", "smtp", "smtps".',
+ $config['scheme']
+ )
+ );
+ }
+
+ if (isset($config['query'])) {
+ $this->configureOptions($mailer, $config['query']);
+ }
+ }
+
+ /**
+ * Configure SMTP.
+ *
+ * @param PHPMailer $mailer PHPMailer instance
+ * @param array $config Configuration
+ */
+ private function configureSMTP($mailer, $config)
+ {
+ $isSMTPS = 'smtps' === $config['scheme'];
+
+ if ($isSMTPS) {
+ $mailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
+ }
+
+ $mailer->Host = $config['host'];
+
+ if (isset($config['port'])) {
+ $mailer->Port = $config['port'];
+ } elseif ($isSMTPS) {
+ $mailer->Port = SMTP::DEFAULT_SECURE_PORT;
+ }
+
+ $mailer->SMTPAuth = isset($config['user']) || isset($config['pass']);
+
+ if (isset($config['user'])) {
+ $mailer->Username = $config['user'];
+ }
+
+ if (isset($config['pass'])) {
+ $mailer->Password = $config['pass'];
+ }
+ }
+
+ /**
+ * Configure options.
+ *
+ * @param PHPMailer $mailer PHPMailer instance
+ * @param array $options Options
+ *
+ * @throws Exception If option is unknown
+ */
+ private function configureOptions(PHPMailer $mailer, $options)
+ {
+ $allowedOptions = get_object_vars($mailer);
+
+ unset($allowedOptions['Mailer']);
+ unset($allowedOptions['SMTPAuth']);
+ unset($allowedOptions['Username']);
+ unset($allowedOptions['Password']);
+ unset($allowedOptions['Hostname']);
+ unset($allowedOptions['Port']);
+ unset($allowedOptions['ErrorInfo']);
+
+ $allowedOptions = \array_keys($allowedOptions);
+
+ foreach ($options as $key => $value) {
+ if (!in_array($key, $allowedOptions)) {
+ throw new Exception(
+ sprintf(
+ 'Unknown option: "%s". Allowed values: "%s"',
+ $key,
+ implode('", "', $allowedOptions)
+ )
+ );
+ }
+
+ switch ($key) {
+ case 'AllowEmpty':
+ case 'SMTPAutoTLS':
+ case 'SMTPKeepAlive':
+ case 'SingleTo':
+ case 'UseSendmailOptions':
+ case 'do_verp':
+ case 'DKIM_copyHeaderFields':
+ $mailer->$key = (bool) $value;
+ break;
+ case 'Priority':
+ case 'SMTPDebug':
+ case 'WordWrap':
+ $mailer->$key = (int) $value;
+ break;
+ default:
+ $mailer->$key = $value;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Parse a URL.
+ * Wrapper for the built-in parse_url function to work around a bug in PHP 5.5.
+ *
+ * @param string $url URL
+ *
+ * @return array|false
+ */
+ protected function parseUrl($url)
+ {
+ if (\PHP_VERSION_ID >= 50600 || false === strpos($url, '?')) {
+ return parse_url($url);
+ }
+
+ $chunks = explode('?', $url);
+ if (is_array($chunks)) {
+ $result = parse_url($chunks[0]);
+ if (is_array($result)) {
+ $result['query'] = $chunks[1];
+ }
+ return $result;
+ }
+
+ return false;
+ }
+}
diff --git a/Website/assets/vendors/PHPMailer/src/Exception.php b/Website/assets/vendors/PHPMailer/src/Exception.php
new file mode 100644
index 0000000..09c1a2c
--- /dev/null
+++ b/Website/assets/vendors/PHPMailer/src/Exception.php
@@ -0,0 +1,40 @@
+
+ * @author Jim Jagielski (jimjag)
+ * @author Andy Prevost (codeworxtech)
+ * @author Brent R. Matzelle (original founder)
+ * @copyright 2012 - 2020 Marcus Bointon
+ * @copyright 2010 - 2012 Jim Jagielski
+ * @copyright 2004 - 2009 Andy Prevost
+ * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
+ * @note This program is distributed in the hope that it will be useful - WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+namespace PHPMailer\PHPMailer;
+
+/**
+ * PHPMailer exception handler.
+ *
+ * @author Marcus Bointon
+ */
+class Exception extends \Exception
+{
+ /**
+ * Prettify error message output.
+ *
+ * @return string
+ */
+ public function errorMessage()
+ {
+ return '' . htmlspecialchars($this->getMessage(), ENT_COMPAT | ENT_HTML401) . " \n";
+ }
+}
diff --git a/Website/assets/vendors/PHPMailer/src/OAuth.php b/Website/assets/vendors/PHPMailer/src/OAuth.php
new file mode 100644
index 0000000..a7e9588
--- /dev/null
+++ b/Website/assets/vendors/PHPMailer/src/OAuth.php
@@ -0,0 +1,139 @@
+
+ * @author Jim Jagielski (jimjag)
+ * @author Andy Prevost (codeworxtech)
+ * @author Brent R. Matzelle (original founder)
+ * @copyright 2012 - 2020 Marcus Bointon
+ * @copyright 2010 - 2012 Jim Jagielski
+ * @copyright 2004 - 2009 Andy Prevost
+ * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
+ * @note This program is distributed in the hope that it will be useful - WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+namespace PHPMailer\PHPMailer;
+
+use League\OAuth2\Client\Grant\RefreshToken;
+use League\OAuth2\Client\Provider\AbstractProvider;
+use League\OAuth2\Client\Token\AccessToken;
+
+/**
+ * OAuth - OAuth2 authentication wrapper class.
+ * Uses the oauth2-client package from the League of Extraordinary Packages.
+ *
+ * @see https://oauth2-client.thephpleague.com
+ *
+ * @author Marcus Bointon (Synchro/coolbru)
+ */
+class OAuth implements OAuthTokenProvider
+{
+ /**
+ * An instance of the League OAuth Client Provider.
+ *
+ * @var AbstractProvider
+ */
+ protected $provider;
+
+ /**
+ * The current OAuth access token.
+ *
+ * @var AccessToken
+ */
+ protected $oauthToken;
+
+ /**
+ * The user's email address, usually used as the login ID
+ * and also the from address when sending email.
+ *
+ * @var string
+ */
+ protected $oauthUserEmail = '';
+
+ /**
+ * The client secret, generated in the app definition of the service you're connecting to.
+ *
+ * @var string
+ */
+ protected $oauthClientSecret = '';
+
+ /**
+ * The client ID, generated in the app definition of the service you're connecting to.
+ *
+ * @var string
+ */
+ protected $oauthClientId = '';
+
+ /**
+ * The refresh token, used to obtain new AccessTokens.
+ *
+ * @var string
+ */
+ protected $oauthRefreshToken = '';
+
+ /**
+ * OAuth constructor.
+ *
+ * @param array $options Associative array containing
+ * `provider`, `userName`, `clientSecret`, `clientId` and `refreshToken` elements
+ */
+ public function __construct($options)
+ {
+ $this->provider = $options['provider'];
+ $this->oauthUserEmail = $options['userName'];
+ $this->oauthClientSecret = $options['clientSecret'];
+ $this->oauthClientId = $options['clientId'];
+ $this->oauthRefreshToken = $options['refreshToken'];
+ }
+
+ /**
+ * Get a new RefreshToken.
+ *
+ * @return RefreshToken
+ */
+ protected function getGrant()
+ {
+ return new RefreshToken();
+ }
+
+ /**
+ * Get a new AccessToken.
+ *
+ * @return AccessToken
+ */
+ protected function getToken()
+ {
+ return $this->provider->getAccessToken(
+ $this->getGrant(),
+ ['refresh_token' => $this->oauthRefreshToken]
+ );
+ }
+
+ /**
+ * Generate a base64-encoded OAuth token.
+ *
+ * @return string
+ */
+ public function getOauth64()
+ {
+ //Get a new token if it's not available or has expired
+ if (null === $this->oauthToken || $this->oauthToken->hasExpired()) {
+ $this->oauthToken = $this->getToken();
+ }
+
+ return base64_encode(
+ 'user=' .
+ $this->oauthUserEmail .
+ "\001auth=Bearer " .
+ $this->oauthToken .
+ "\001\001"
+ );
+ }
+}
diff --git a/Website/assets/vendors/PHPMailer/src/OAuthTokenProvider.php b/Website/assets/vendors/PHPMailer/src/OAuthTokenProvider.php
new file mode 100644
index 0000000..cbda1a1
--- /dev/null
+++ b/Website/assets/vendors/PHPMailer/src/OAuthTokenProvider.php
@@ -0,0 +1,44 @@
+
+ * @author Jim Jagielski (jimjag)
+ * @author Andy Prevost (codeworxtech)
+ * @author Brent R. Matzelle (original founder)
+ * @copyright 2012 - 2020 Marcus Bointon
+ * @copyright 2010 - 2012 Jim Jagielski
+ * @copyright 2004 - 2009 Andy Prevost
+ * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
+ * @note This program is distributed in the hope that it will be useful - WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+namespace PHPMailer\PHPMailer;
+
+/**
+ * OAuthTokenProvider - OAuth2 token provider interface.
+ * Provides base64 encoded OAuth2 auth strings for SMTP authentication.
+ *
+ * @see OAuth
+ * @see SMTP::authenticate()
+ *
+ * @author Peter Scopes (pdscopes)
+ * @author Marcus Bointon (Synchro/coolbru)
+ */
+interface OAuthTokenProvider
+{
+ /**
+ * Generate a base64-encoded OAuth token ensuring that the access token has not expired.
+ * The string to be base 64 encoded should be in the form:
+ * "user=\001auth=Bearer \001\001"
+ *
+ * @return string
+ */
+ public function getOauth64();
+}
diff --git a/Website/assets/vendors/PHPMailer/src/PHPMailer.php b/Website/assets/vendors/PHPMailer/src/PHPMailer.php
new file mode 100644
index 0000000..11a0a68
--- /dev/null
+++ b/Website/assets/vendors/PHPMailer/src/PHPMailer.php
@@ -0,0 +1,5248 @@
+
+ * @author Jim Jagielski (jimjag)
+ * @author Andy Prevost (codeworxtech)
+ * @author Brent R. Matzelle (original founder)
+ * @copyright 2012 - 2020 Marcus Bointon
+ * @copyright 2010 - 2012 Jim Jagielski
+ * @copyright 2004 - 2009 Andy Prevost
+ * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
+ * @note This program is distributed in the hope that it will be useful - WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+namespace PHPMailer\PHPMailer;
+
+/**
+ * PHPMailer - PHP email creation and transport class.
+ *
+ * @author Marcus Bointon (Synchro/coolbru)
+ * @author Jim Jagielski (jimjag)
+ * @author Andy Prevost (codeworxtech)
+ * @author Brent R. Matzelle (original founder)
+ */
+class PHPMailer
+{
+ const CHARSET_ASCII = 'us-ascii';
+ const CHARSET_ISO88591 = 'iso-8859-1';
+ const CHARSET_UTF8 = 'utf-8';
+
+ const CONTENT_TYPE_PLAINTEXT = 'text/plain';
+ const CONTENT_TYPE_TEXT_CALENDAR = 'text/calendar';
+ const CONTENT_TYPE_TEXT_HTML = 'text/html';
+ const CONTENT_TYPE_MULTIPART_ALTERNATIVE = 'multipart/alternative';
+ const CONTENT_TYPE_MULTIPART_MIXED = 'multipart/mixed';
+ const CONTENT_TYPE_MULTIPART_RELATED = 'multipart/related';
+
+ const ENCODING_7BIT = '7bit';
+ const ENCODING_8BIT = '8bit';
+ const ENCODING_BASE64 = 'base64';
+ const ENCODING_BINARY = 'binary';
+ const ENCODING_QUOTED_PRINTABLE = 'quoted-printable';
+
+ const ENCRYPTION_STARTTLS = 'tls';
+ const ENCRYPTION_SMTPS = 'ssl';
+
+ const ICAL_METHOD_REQUEST = 'REQUEST';
+ const ICAL_METHOD_PUBLISH = 'PUBLISH';
+ const ICAL_METHOD_REPLY = 'REPLY';
+ const ICAL_METHOD_ADD = 'ADD';
+ const ICAL_METHOD_CANCEL = 'CANCEL';
+ const ICAL_METHOD_REFRESH = 'REFRESH';
+ const ICAL_METHOD_COUNTER = 'COUNTER';
+ const ICAL_METHOD_DECLINECOUNTER = 'DECLINECOUNTER';
+
+ /**
+ * Email priority.
+ * Options: null (default), 1 = High, 3 = Normal, 5 = low.
+ * When null, the header is not set at all.
+ *
+ * @var int|null
+ */
+ public $Priority;
+
+ /**
+ * The character set of the message.
+ *
+ * @var string
+ */
+ public $CharSet = self::CHARSET_ISO88591;
+
+ /**
+ * The MIME Content-type of the message.
+ *
+ * @var string
+ */
+ public $ContentType = self::CONTENT_TYPE_PLAINTEXT;
+
+ /**
+ * The message encoding.
+ * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
+ *
+ * @var string
+ */
+ public $Encoding = self::ENCODING_8BIT;
+
+ /**
+ * Holds the most recent mailer error message.
+ *
+ * @var string
+ */
+ public $ErrorInfo = '';
+
+ /**
+ * The From email address for the message.
+ *
+ * @var string
+ */
+ public $From = '';
+
+ /**
+ * The From name of the message.
+ *
+ * @var string
+ */
+ public $FromName = '';
+
+ /**
+ * The envelope sender of the message.
+ * This will usually be turned into a Return-Path header by the receiver,
+ * and is the address that bounces will be sent to.
+ * If not empty, will be passed via `-f` to sendmail or as the 'MAIL FROM' value over SMTP.
+ *
+ * @var string
+ */
+ public $Sender = '';
+
+ /**
+ * The Subject of the message.
+ *
+ * @var string
+ */
+ public $Subject = '';
+
+ /**
+ * An HTML or plain text message body.
+ * If HTML then call isHTML(true).
+ *
+ * @var string
+ */
+ public $Body = '';
+
+ /**
+ * The plain-text message body.
+ * This body can be read by mail clients that do not have HTML email
+ * capability such as mutt & Eudora.
+ * Clients that can read HTML will view the normal Body.
+ *
+ * @var string
+ */
+ public $AltBody = '';
+
+ /**
+ * An iCal message part body.
+ * Only supported in simple alt or alt_inline message types
+ * To generate iCal event structures, use classes like EasyPeasyICS or iCalcreator.
+ *
+ * @see https://kigkonsult.se/iCalcreator/
+ *
+ * @var string
+ */
+ public $Ical = '';
+
+ /**
+ * Value-array of "method" in Contenttype header "text/calendar"
+ *
+ * @var string[]
+ */
+ protected static $IcalMethods = [
+ self::ICAL_METHOD_REQUEST,
+ self::ICAL_METHOD_PUBLISH,
+ self::ICAL_METHOD_REPLY,
+ self::ICAL_METHOD_ADD,
+ self::ICAL_METHOD_CANCEL,
+ self::ICAL_METHOD_REFRESH,
+ self::ICAL_METHOD_COUNTER,
+ self::ICAL_METHOD_DECLINECOUNTER,
+ ];
+
+ /**
+ * The complete compiled MIME message body.
+ *
+ * @var string
+ */
+ protected $MIMEBody = '';
+
+ /**
+ * The complete compiled MIME message headers.
+ *
+ * @var string
+ */
+ protected $MIMEHeader = '';
+
+ /**
+ * Extra headers that createHeader() doesn't fold in.
+ *
+ * @var string
+ */
+ protected $mailHeader = '';
+
+ /**
+ * Word-wrap the message body to this number of chars.
+ * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
+ *
+ * @see static::STD_LINE_LENGTH
+ *
+ * @var int
+ */
+ public $WordWrap = 0;
+
+ /**
+ * Which method to use to send mail.
+ * Options: "mail", "sendmail", or "smtp".
+ *
+ * @var string
+ */
+ public $Mailer = 'mail';
+
+ /**
+ * The path to the sendmail program.
+ *
+ * @var string
+ */
+ public $Sendmail = '/usr/sbin/sendmail';
+
+ /**
+ * Whether mail() uses a fully sendmail-compatible MTA.
+ * One which supports sendmail's "-oi -f" options.
+ *
+ * @var bool
+ */
+ public $UseSendmailOptions = true;
+
+ /**
+ * The email address that a reading confirmation should be sent to, also known as read receipt.
+ *
+ * @var string
+ */
+ public $ConfirmReadingTo = '';
+
+ /**
+ * The hostname to use in the Message-ID header and as default HELO string.
+ * If empty, PHPMailer attempts to find one with, in order,
+ * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value
+ * 'localhost.localdomain'.
+ *
+ * @see PHPMailer::$Helo
+ *
+ * @var string
+ */
+ public $Hostname = '';
+
+ /**
+ * An ID to be used in the Message-ID header.
+ * If empty, a unique id will be generated.
+ * You can set your own, but it must be in the format "",
+ * as defined in RFC5322 section 3.6.4 or it will be ignored.
+ *
+ * @see https://tools.ietf.org/html/rfc5322#section-3.6.4
+ *
+ * @var string
+ */
+ public $MessageID = '';
+
+ /**
+ * The message Date to be used in the Date header.
+ * If empty, the current date will be added.
+ *
+ * @var string
+ */
+ public $MessageDate = '';
+
+ /**
+ * SMTP hosts.
+ * Either a single hostname or multiple semicolon-delimited hostnames.
+ * You can also specify a different port
+ * for each host by using this format: [hostname:port]
+ * (e.g. "smtp1.example.com:25;smtp2.example.com").
+ * You can also specify encryption type, for example:
+ * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
+ * Hosts will be tried in order.
+ *
+ * @var string
+ */
+ public $Host = 'localhost';
+
+ /**
+ * The default SMTP server port.
+ *
+ * @var int
+ */
+ public $Port = 25;
+
+ /**
+ * The SMTP HELO/EHLO name used for the SMTP connection.
+ * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
+ * one with the same method described above for $Hostname.
+ *
+ * @see PHPMailer::$Hostname
+ *
+ * @var string
+ */
+ public $Helo = '';
+
+ /**
+ * What kind of encryption to use on the SMTP connection.
+ * Options: '', static::ENCRYPTION_STARTTLS, or static::ENCRYPTION_SMTPS.
+ *
+ * @var string
+ */
+ public $SMTPSecure = '';
+
+ /**
+ * Whether to enable TLS encryption automatically if a server supports it,
+ * even if `SMTPSecure` is not set to 'tls'.
+ * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
+ *
+ * @var bool
+ */
+ public $SMTPAutoTLS = true;
+
+ /**
+ * Whether to use SMTP authentication.
+ * Uses the Username and Password properties.
+ *
+ * @see PHPMailer::$Username
+ * @see PHPMailer::$Password
+ *
+ * @var bool
+ */
+ public $SMTPAuth = false;
+
+ /**
+ * Options array passed to stream_context_create when connecting via SMTP.
+ *
+ * @var array
+ */
+ public $SMTPOptions = [];
+
+ /**
+ * SMTP username.
+ *
+ * @var string
+ */
+ public $Username = '';
+
+ /**
+ * SMTP password.
+ *
+ * @var string
+ */
+ public $Password = '';
+
+ /**
+ * SMTP authentication type. Options are CRAM-MD5, LOGIN, PLAIN, XOAUTH2.
+ * If not specified, the first one from that list that the server supports will be selected.
+ *
+ * @var string
+ */
+ public $AuthType = '';
+
+ /**
+ * SMTP SMTPXClient command attibutes
+ *
+ * @var array
+ */
+ protected $SMTPXClient = [];
+
+ /**
+ * An implementation of the PHPMailer OAuthTokenProvider interface.
+ *
+ * @var OAuthTokenProvider
+ */
+ protected $oauth;
+
+ /**
+ * The SMTP server timeout in seconds.
+ * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2.
+ *
+ * @var int
+ */
+ public $Timeout = 300;
+
+ /**
+ * Comma separated list of DSN notifications
+ * 'NEVER' under no circumstances a DSN must be returned to the sender.
+ * If you use NEVER all other notifications will be ignored.
+ * 'SUCCESS' will notify you when your mail has arrived at its destination.
+ * 'FAILURE' will arrive if an error occurred during delivery.
+ * 'DELAY' will notify you if there is an unusual delay in delivery, but the actual
+ * delivery's outcome (success or failure) is not yet decided.
+ *
+ * @see https://tools.ietf.org/html/rfc3461 See section 4.1 for more information about NOTIFY
+ */
+ public $dsn = '';
+
+ /**
+ * SMTP class debug output mode.
+ * Debug output level.
+ * Options:
+ * @see SMTP::DEBUG_OFF: No output
+ * @see SMTP::DEBUG_CLIENT: Client messages
+ * @see SMTP::DEBUG_SERVER: Client and server messages
+ * @see SMTP::DEBUG_CONNECTION: As SERVER plus connection status
+ * @see SMTP::DEBUG_LOWLEVEL: Noisy, low-level data output, rarely needed
+ *
+ * @see SMTP::$do_debug
+ *
+ * @var int
+ */
+ public $SMTPDebug = 0;
+
+ /**
+ * How to handle debug output.
+ * Options:
+ * * `echo` Output plain-text as-is, appropriate for CLI
+ * * `html` Output escaped, line breaks converted to ` `, appropriate for browser output
+ * * `error_log` Output to error log as configured in php.ini
+ * By default PHPMailer will use `echo` if run from a `cli` or `cli-server` SAPI, `html` otherwise.
+ * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
+ *
+ * ```php
+ * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
+ * ```
+ *
+ * Alternatively, you can pass in an instance of a PSR-3 compatible logger, though only `debug`
+ * level output is used:
+ *
+ * ```php
+ * $mail->Debugoutput = new myPsr3Logger;
+ * ```
+ *
+ * @see SMTP::$Debugoutput
+ *
+ * @var string|callable|\Psr\Log\LoggerInterface
+ */
+ public $Debugoutput = 'echo';
+
+ /**
+ * Whether to keep the SMTP connection open after each message.
+ * If this is set to true then the connection will remain open after a send,
+ * and closing the connection will require an explicit call to smtpClose().
+ * It's a good idea to use this if you are sending multiple messages as it reduces overhead.
+ * See the mailing list example for how to use it.
+ *
+ * @var bool
+ */
+ public $SMTPKeepAlive = false;
+
+ /**
+ * Whether to split multiple to addresses into multiple messages
+ * or send them all in one message.
+ * Only supported in `mail` and `sendmail` transports, not in SMTP.
+ *
+ * @var bool
+ *
+ * @deprecated 6.0.0 PHPMailer isn't a mailing list manager!
+ */
+ public $SingleTo = false;
+
+ /**
+ * Storage for addresses when SingleTo is enabled.
+ *
+ * @var array
+ */
+ protected $SingleToArray = [];
+
+ /**
+ * Whether to generate VERP addresses on send.
+ * Only applicable when sending via SMTP.
+ *
+ * @see https://en.wikipedia.org/wiki/Variable_envelope_return_path
+ * @see https://www.postfix.org/VERP_README.html Postfix VERP info
+ *
+ * @var bool
+ */
+ public $do_verp = false;
+
+ /**
+ * Whether to allow sending messages with an empty body.
+ *
+ * @var bool
+ */
+ public $AllowEmpty = false;
+
+ /**
+ * DKIM selector.
+ *
+ * @var string
+ */
+ public $DKIM_selector = '';
+
+ /**
+ * DKIM Identity.
+ * Usually the email address used as the source of the email.
+ *
+ * @var string
+ */
+ public $DKIM_identity = '';
+
+ /**
+ * DKIM passphrase.
+ * Used if your key is encrypted.
+ *
+ * @var string
+ */
+ public $DKIM_passphrase = '';
+
+ /**
+ * DKIM signing domain name.
+ *
+ * @example 'example.com'
+ *
+ * @var string
+ */
+ public $DKIM_domain = '';
+
+ /**
+ * DKIM Copy header field values for diagnostic use.
+ *
+ * @var bool
+ */
+ public $DKIM_copyHeaderFields = true;
+
+ /**
+ * DKIM Extra signing headers.
+ *
+ * @example ['List-Unsubscribe', 'List-Help']
+ *
+ * @var array
+ */
+ public $DKIM_extraHeaders = [];
+
+ /**
+ * DKIM private key file path.
+ *
+ * @var string
+ */
+ public $DKIM_private = '';
+
+ /**
+ * DKIM private key string.
+ *
+ * If set, takes precedence over `$DKIM_private`.
+ *
+ * @var string
+ */
+ public $DKIM_private_string = '';
+
+ /**
+ * Callback Action function name.
+ *
+ * The function that handles the result of the send email action.
+ * It is called out by send() for each email sent.
+ *
+ * Value can be any php callable: https://www.php.net/is_callable
+ *
+ * Parameters:
+ * bool $result result of the send action
+ * array $to email addresses of the recipients
+ * array $cc cc email addresses
+ * array $bcc bcc email addresses
+ * string $subject the subject
+ * string $body the email body
+ * string $from email address of sender
+ * string $extra extra information of possible use
+ * "smtp_transaction_id' => last smtp transaction id
+ *
+ * @var string
+ */
+ public $action_function = '';
+
+ /**
+ * What to put in the X-Mailer header.
+ * Options: An empty string for PHPMailer default, whitespace/null for none, or a string to use.
+ *
+ * @var string|null
+ */
+ public $XMailer = '';
+
+ /**
+ * Which validator to use by default when validating email addresses.
+ * May be a callable to inject your own validator, but there are several built-in validators.
+ * The default validator uses PHP's FILTER_VALIDATE_EMAIL filter_var option.
+ *
+ * @see PHPMailer::validateAddress()
+ *
+ * @var string|callable
+ */
+ public static $validator = 'php';
+
+ /**
+ * An instance of the SMTP sender class.
+ *
+ * @var SMTP
+ */
+ protected $smtp;
+
+ /**
+ * The array of 'to' names and addresses.
+ *
+ * @var array
+ */
+ protected $to = [];
+
+ /**
+ * The array of 'cc' names and addresses.
+ *
+ * @var array
+ */
+ protected $cc = [];
+
+ /**
+ * The array of 'bcc' names and addresses.
+ *
+ * @var array
+ */
+ protected $bcc = [];
+
+ /**
+ * The array of reply-to names and addresses.
+ *
+ * @var array
+ */
+ protected $ReplyTo = [];
+
+ /**
+ * An array of all kinds of addresses.
+ * Includes all of $to, $cc, $bcc.
+ *
+ * @see PHPMailer::$to
+ * @see PHPMailer::$cc
+ * @see PHPMailer::$bcc
+ *
+ * @var array
+ */
+ protected $all_recipients = [];
+
+ /**
+ * An array of names and addresses queued for validation.
+ * In send(), valid and non duplicate entries are moved to $all_recipients
+ * and one of $to, $cc, or $bcc.
+ * This array is used only for addresses with IDN.
+ *
+ * @see PHPMailer::$to
+ * @see PHPMailer::$cc
+ * @see PHPMailer::$bcc
+ * @see PHPMailer::$all_recipients
+ *
+ * @var array
+ */
+ protected $RecipientsQueue = [];
+
+ /**
+ * An array of reply-to names and addresses queued for validation.
+ * In send(), valid and non duplicate entries are moved to $ReplyTo.
+ * This array is used only for addresses with IDN.
+ *
+ * @see PHPMailer::$ReplyTo
+ *
+ * @var array
+ */
+ protected $ReplyToQueue = [];
+
+ /**
+ * The array of attachments.
+ *
+ * @var array
+ */
+ protected $attachment = [];
+
+ /**
+ * The array of custom headers.
+ *
+ * @var array
+ */
+ protected $CustomHeader = [];
+
+ /**
+ * The most recent Message-ID (including angular brackets).
+ *
+ * @var string
+ */
+ protected $lastMessageID = '';
+
+ /**
+ * The message's MIME type.
+ *
+ * @var string
+ */
+ protected $message_type = '';
+
+ /**
+ * The array of MIME boundary strings.
+ *
+ * @var array
+ */
+ protected $boundary = [];
+
+ /**
+ * The array of available text strings for the current language.
+ *
+ * @var array
+ */
+ protected $language = [];
+
+ /**
+ * The number of errors encountered.
+ *
+ * @var int
+ */
+ protected $error_count = 0;
+
+ /**
+ * The S/MIME certificate file path.
+ *
+ * @var string
+ */
+ protected $sign_cert_file = '';
+
+ /**
+ * The S/MIME key file path.
+ *
+ * @var string
+ */
+ protected $sign_key_file = '';
+
+ /**
+ * The optional S/MIME extra certificates ("CA Chain") file path.
+ *
+ * @var string
+ */
+ protected $sign_extracerts_file = '';
+
+ /**
+ * The S/MIME password for the key.
+ * Used only if the key is encrypted.
+ *
+ * @var string
+ */
+ protected $sign_key_pass = '';
+
+ /**
+ * Whether to throw exceptions for errors.
+ *
+ * @var bool
+ */
+ protected $exceptions = false;
+
+ /**
+ * Unique ID used for message ID and boundaries.
+ *
+ * @var string
+ */
+ protected $uniqueid = '';
+
+ /**
+ * The PHPMailer Version number.
+ *
+ * @var string
+ */
+ const VERSION = '6.9.1';
+
+ /**
+ * Error severity: message only, continue processing.
+ *
+ * @var int
+ */
+ const STOP_MESSAGE = 0;
+
+ /**
+ * Error severity: message, likely ok to continue processing.
+ *
+ * @var int
+ */
+ const STOP_CONTINUE = 1;
+
+ /**
+ * Error severity: message, plus full stop, critical error reached.
+ *
+ * @var int
+ */
+ const STOP_CRITICAL = 2;
+
+ /**
+ * The SMTP standard CRLF line break.
+ * If you want to change line break format, change static::$LE, not this.
+ */
+ const CRLF = "\r\n";
+
+ /**
+ * "Folding White Space" a white space string used for line folding.
+ */
+ const FWS = ' ';
+
+ /**
+ * SMTP RFC standard line ending; Carriage Return, Line Feed.
+ *
+ * @var string
+ */
+ protected static $LE = self::CRLF;
+
+ /**
+ * The maximum line length supported by mail().
+ *
+ * Background: mail() will sometimes corrupt messages
+ * with headers longer than 65 chars, see #818.
+ *
+ * @var int
+ */
+ const MAIL_MAX_LINE_LENGTH = 63;
+
+ /**
+ * The maximum line length allowed by RFC 2822 section 2.1.1.
+ *
+ * @var int
+ */
+ const MAX_LINE_LENGTH = 998;
+
+ /**
+ * The lower maximum line length allowed by RFC 2822 section 2.1.1.
+ * This length does NOT include the line break
+ * 76 means that lines will be 77 or 78 chars depending on whether
+ * the line break format is LF or CRLF; both are valid.
+ *
+ * @var int
+ */
+ const STD_LINE_LENGTH = 76;
+
+ /**
+ * Constructor.
+ *
+ * @param bool $exceptions Should we throw external exceptions?
+ */
+ public function __construct($exceptions = null)
+ {
+ if (null !== $exceptions) {
+ $this->exceptions = (bool) $exceptions;
+ }
+ //Pick an appropriate debug output format automatically
+ $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html');
+ }
+
+ /**
+ * Destructor.
+ */
+ public function __destruct()
+ {
+ //Close any open SMTP connection nicely
+ $this->smtpClose();
+ }
+
+ /**
+ * Call mail() in a safe_mode-aware fashion.
+ * Also, unless sendmail_path points to sendmail (or something that
+ * claims to be sendmail), don't pass params (not a perfect fix,
+ * but it will do).
+ *
+ * @param string $to To
+ * @param string $subject Subject
+ * @param string $body Message Body
+ * @param string $header Additional Header(s)
+ * @param string|null $params Params
+ *
+ * @return bool
+ */
+ private function mailPassthru($to, $subject, $body, $header, $params)
+ {
+ //Check overloading of mail function to avoid double-encoding
+ if ((int)ini_get('mbstring.func_overload') & 1) {
+ $subject = $this->secureHeader($subject);
+ } else {
+ $subject = $this->encodeHeader($this->secureHeader($subject));
+ }
+ //Calling mail() with null params breaks
+ $this->edebug('Sending with mail()');
+ $this->edebug('Sendmail path: ' . ini_get('sendmail_path'));
+ $this->edebug("Envelope sender: {$this->Sender}");
+ $this->edebug("To: {$to}");
+ $this->edebug("Subject: {$subject}");
+ $this->edebug("Headers: {$header}");
+ if (!$this->UseSendmailOptions || null === $params) {
+ $result = @mail($to, $subject, $body, $header);
+ } else {
+ $this->edebug("Additional params: {$params}");
+ $result = @mail($to, $subject, $body, $header, $params);
+ }
+ $this->edebug('Result: ' . ($result ? 'true' : 'false'));
+ return $result;
+ }
+
+ /**
+ * Output debugging info via a user-defined method.
+ * Only generates output if debug output is enabled.
+ *
+ * @see PHPMailer::$Debugoutput
+ * @see PHPMailer::$SMTPDebug
+ *
+ * @param string $str
+ */
+ protected function edebug($str)
+ {
+ if ($this->SMTPDebug <= 0) {
+ return;
+ }
+ //Is this a PSR-3 logger?
+ if ($this->Debugoutput instanceof \Psr\Log\LoggerInterface) {
+ $this->Debugoutput->debug(rtrim($str, "\r\n"));
+
+ return;
+ }
+ //Avoid clash with built-in function names
+ if (is_callable($this->Debugoutput) && !in_array($this->Debugoutput, ['error_log', 'html', 'echo'])) {
+ call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
+
+ return;
+ }
+ switch ($this->Debugoutput) {
+ case 'error_log':
+ //Don't output, just log
+ /** @noinspection ForgottenDebugOutputInspection */
+ error_log($str);
+ break;
+ case 'html':
+ //Cleans up output a bit for a better looking, HTML-safe output
+ echo htmlentities(
+ preg_replace('/[\r\n]+/', '', $str),
+ ENT_QUOTES,
+ 'UTF-8'
+ ), " \n";
+ break;
+ case 'echo':
+ default:
+ //Normalize line breaks
+ $str = preg_replace('/\r\n|\r/m', "\n", $str);
+ echo gmdate('Y-m-d H:i:s'),
+ "\t",
+ //Trim trailing space
+ trim(
+ //Indent for readability, except for trailing break
+ str_replace(
+ "\n",
+ "\n \t ",
+ trim($str)
+ )
+ ),
+ "\n";
+ }
+ }
+
+ /**
+ * Sets message type to HTML or plain.
+ *
+ * @param bool $isHtml True for HTML mode
+ */
+ public function isHTML($isHtml = true)
+ {
+ if ($isHtml) {
+ $this->ContentType = static::CONTENT_TYPE_TEXT_HTML;
+ } else {
+ $this->ContentType = static::CONTENT_TYPE_PLAINTEXT;
+ }
+ }
+
+ /**
+ * Send messages using SMTP.
+ */
+ public function isSMTP()
+ {
+ $this->Mailer = 'smtp';
+ }
+
+ /**
+ * Send messages using PHP's mail() function.
+ */
+ public function isMail()
+ {
+ $this->Mailer = 'mail';
+ }
+
+ /**
+ * Send messages using $Sendmail.
+ */
+ public function isSendmail()
+ {
+ $ini_sendmail_path = ini_get('sendmail_path');
+
+ if (false === stripos($ini_sendmail_path, 'sendmail')) {
+ $this->Sendmail = '/usr/sbin/sendmail';
+ } else {
+ $this->Sendmail = $ini_sendmail_path;
+ }
+ $this->Mailer = 'sendmail';
+ }
+
+ /**
+ * Send messages using qmail.
+ */
+ public function isQmail()
+ {
+ $ini_sendmail_path = ini_get('sendmail_path');
+
+ if (false === stripos($ini_sendmail_path, 'qmail')) {
+ $this->Sendmail = '/var/qmail/bin/qmail-inject';
+ } else {
+ $this->Sendmail = $ini_sendmail_path;
+ }
+ $this->Mailer = 'qmail';
+ }
+
+ /**
+ * Add a "To" address.
+ *
+ * @param string $address The email address to send to
+ * @param string $name
+ *
+ * @throws Exception
+ *
+ * @return bool true on success, false if address already used or invalid in some way
+ */
+ public function addAddress($address, $name = '')
+ {
+ return $this->addOrEnqueueAnAddress('to', $address, $name);
+ }
+
+ /**
+ * Add a "CC" address.
+ *
+ * @param string $address The email address to send to
+ * @param string $name
+ *
+ * @throws Exception
+ *
+ * @return bool true on success, false if address already used or invalid in some way
+ */
+ public function addCC($address, $name = '')
+ {
+ return $this->addOrEnqueueAnAddress('cc', $address, $name);
+ }
+
+ /**
+ * Add a "BCC" address.
+ *
+ * @param string $address The email address to send to
+ * @param string $name
+ *
+ * @throws Exception
+ *
+ * @return bool true on success, false if address already used or invalid in some way
+ */
+ public function addBCC($address, $name = '')
+ {
+ return $this->addOrEnqueueAnAddress('bcc', $address, $name);
+ }
+
+ /**
+ * Add a "Reply-To" address.
+ *
+ * @param string $address The email address to reply to
+ * @param string $name
+ *
+ * @throws Exception
+ *
+ * @return bool true on success, false if address already used or invalid in some way
+ */
+ public function addReplyTo($address, $name = '')
+ {
+ return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
+ }
+
+ /**
+ * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
+ * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
+ * be modified after calling this function), addition of such addresses is delayed until send().
+ * Addresses that have been added already return false, but do not throw exceptions.
+ *
+ * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
+ * @param string $address The email address
+ * @param string $name An optional username associated with the address
+ *
+ * @throws Exception
+ *
+ * @return bool true on success, false if address already used or invalid in some way
+ */
+ protected function addOrEnqueueAnAddress($kind, $address, $name)
+ {
+ $pos = false;
+ if ($address !== null) {
+ $address = trim($address);
+ $pos = strrpos($address, '@');
+ }
+ if (false === $pos) {
+ //At-sign is missing.
+ $error_message = sprintf(
+ '%s (%s): %s',
+ $this->lang('invalid_address'),
+ $kind,
+ $address
+ );
+ $this->setError($error_message);
+ $this->edebug($error_message);
+ if ($this->exceptions) {
+ throw new Exception($error_message);
+ }
+
+ return false;
+ }
+ if ($name !== null && is_string($name)) {
+ $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
+ } else {
+ $name = '';
+ }
+ $params = [$kind, $address, $name];
+ //Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
+ //Domain is assumed to be whatever is after the last @ symbol in the address
+ if (static::idnSupported() && $this->has8bitChars(substr($address, ++$pos))) {
+ if ('Reply-To' !== $kind) {
+ if (!array_key_exists($address, $this->RecipientsQueue)) {
+ $this->RecipientsQueue[$address] = $params;
+
+ return true;
+ }
+ } elseif (!array_key_exists($address, $this->ReplyToQueue)) {
+ $this->ReplyToQueue[$address] = $params;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ //Immediately add standard addresses without IDN.
+ return call_user_func_array([$this, 'addAnAddress'], $params);
+ }
+
+ /**
+ * Set the boundaries to use for delimiting MIME parts.
+ * If you override this, ensure you set all 3 boundaries to unique values.
+ * The default boundaries include a "=_" sequence which cannot occur in quoted-printable bodies,
+ * as suggested by https://www.rfc-editor.org/rfc/rfc2045#section-6.7
+ *
+ * @return void
+ */
+ public function setBoundaries()
+ {
+ $this->uniqueid = $this->generateId();
+ $this->boundary[1] = 'b1=_' . $this->uniqueid;
+ $this->boundary[2] = 'b2=_' . $this->uniqueid;
+ $this->boundary[3] = 'b3=_' . $this->uniqueid;
+ }
+
+ /**
+ * Add an address to one of the recipient arrays or to the ReplyTo array.
+ * Addresses that have been added already return false, but do not throw exceptions.
+ *
+ * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
+ * @param string $address The email address to send, resp. to reply to
+ * @param string $name
+ *
+ * @throws Exception
+ *
+ * @return bool true on success, false if address already used or invalid in some way
+ */
+ protected function addAnAddress($kind, $address, $name = '')
+ {
+ if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) {
+ $error_message = sprintf(
+ '%s: %s',
+ $this->lang('Invalid recipient kind'),
+ $kind
+ );
+ $this->setError($error_message);
+ $this->edebug($error_message);
+ if ($this->exceptions) {
+ throw new Exception($error_message);
+ }
+
+ return false;
+ }
+ if (!static::validateAddress($address)) {
+ $error_message = sprintf(
+ '%s (%s): %s',
+ $this->lang('invalid_address'),
+ $kind,
+ $address
+ );
+ $this->setError($error_message);
+ $this->edebug($error_message);
+ if ($this->exceptions) {
+ throw new Exception($error_message);
+ }
+
+ return false;
+ }
+ if ('Reply-To' !== $kind) {
+ if (!array_key_exists(strtolower($address), $this->all_recipients)) {
+ $this->{$kind}[] = [$address, $name];
+ $this->all_recipients[strtolower($address)] = true;
+
+ return true;
+ }
+ } elseif (!array_key_exists(strtolower($address), $this->ReplyTo)) {
+ $this->ReplyTo[strtolower($address)] = [$address, $name];
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
+ * of the form "display name " into an array of name/address pairs.
+ * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
+ * Note that quotes in the name part are removed.
+ *
+ * @see https://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
+ *
+ * @param string $addrstr The address list string
+ * @param bool $useimap Whether to use the IMAP extension to parse the list
+ * @param string $charset The charset to use when decoding the address list string.
+ *
+ * @return array
+ */
+ public static function parseAddresses($addrstr, $useimap = true, $charset = self::CHARSET_ISO88591)
+ {
+ $addresses = [];
+ if ($useimap && function_exists('imap_rfc822_parse_adrlist')) {
+ //Use this built-in parser if it's available
+ $list = imap_rfc822_parse_adrlist($addrstr, '');
+ // Clear any potential IMAP errors to get rid of notices being thrown at end of script.
+ imap_errors();
+ foreach ($list as $address) {
+ if (
+ '.SYNTAX-ERROR.' !== $address->host &&
+ static::validateAddress($address->mailbox . '@' . $address->host)
+ ) {
+ //Decode the name part if it's present and encoded
+ if (
+ property_exists($address, 'personal') &&
+ //Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled
+ defined('MB_CASE_UPPER') &&
+ preg_match('/^=\?.*\?=$/s', $address->personal)
+ ) {
+ $origCharset = mb_internal_encoding();
+ mb_internal_encoding($charset);
+ //Undo any RFC2047-encoded spaces-as-underscores
+ $address->personal = str_replace('_', '=20', $address->personal);
+ //Decode the name
+ $address->personal = mb_decode_mimeheader($address->personal);
+ mb_internal_encoding($origCharset);
+ }
+
+ $addresses[] = [
+ 'name' => (property_exists($address, 'personal') ? $address->personal : ''),
+ 'address' => $address->mailbox . '@' . $address->host,
+ ];
+ }
+ }
+ } else {
+ //Use this simpler parser
+ $list = explode(',', $addrstr);
+ foreach ($list as $address) {
+ $address = trim($address);
+ //Is there a separate name part?
+ if (strpos($address, '<') === false) {
+ //No separate name, just use the whole thing
+ if (static::validateAddress($address)) {
+ $addresses[] = [
+ 'name' => '',
+ 'address' => $address,
+ ];
+ }
+ } else {
+ list($name, $email) = explode('<', $address);
+ $email = trim(str_replace('>', '', $email));
+ $name = trim($name);
+ if (static::validateAddress($email)) {
+ //Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled
+ //If this name is encoded, decode it
+ if (defined('MB_CASE_UPPER') && preg_match('/^=\?.*\?=$/s', $name)) {
+ $origCharset = mb_internal_encoding();
+ mb_internal_encoding($charset);
+ //Undo any RFC2047-encoded spaces-as-underscores
+ $name = str_replace('_', '=20', $name);
+ //Decode the name
+ $name = mb_decode_mimeheader($name);
+ mb_internal_encoding($origCharset);
+ }
+ $addresses[] = [
+ //Remove any surrounding quotes and spaces from the name
+ 'name' => trim($name, '\'" '),
+ 'address' => $email,
+ ];
+ }
+ }
+ }
+ }
+
+ return $addresses;
+ }
+
+ /**
+ * Set the From and FromName properties.
+ *
+ * @param string $address
+ * @param string $name
+ * @param bool $auto Whether to also set the Sender address, defaults to true
+ *
+ * @throws Exception
+ *
+ * @return bool
+ */
+ public function setFrom($address, $name = '', $auto = true)
+ {
+ $address = trim((string)$address);
+ $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
+ //Don't validate now addresses with IDN. Will be done in send().
+ $pos = strrpos($address, '@');
+ if (
+ (false === $pos)
+ || ((!$this->has8bitChars(substr($address, ++$pos)) || !static::idnSupported())
+ && !static::validateAddress($address))
+ ) {
+ $error_message = sprintf(
+ '%s (From): %s',
+ $this->lang('invalid_address'),
+ $address
+ );
+ $this->setError($error_message);
+ $this->edebug($error_message);
+ if ($this->exceptions) {
+ throw new Exception($error_message);
+ }
+
+ return false;
+ }
+ $this->From = $address;
+ $this->FromName = $name;
+ if ($auto && empty($this->Sender)) {
+ $this->Sender = $address;
+ }
+
+ return true;
+ }
+
+ /**
+ * Return the Message-ID header of the last email.
+ * Technically this is the value from the last time the headers were created,
+ * but it's also the message ID of the last sent message except in
+ * pathological cases.
+ *
+ * @return string
+ */
+ public function getLastMessageID()
+ {
+ return $this->lastMessageID;
+ }
+
+ /**
+ * Check that a string looks like an email address.
+ * Validation patterns supported:
+ * * `auto` Pick best pattern automatically;
+ * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0;
+ * * `pcre` Use old PCRE implementation;
+ * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
+ * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
+ * * `noregex` Don't use a regex: super fast, really dumb.
+ * Alternatively you may pass in a callable to inject your own validator, for example:
+ *
+ * ```php
+ * PHPMailer::validateAddress('user@example.com', function($address) {
+ * return (strpos($address, '@') !== false);
+ * });
+ * ```
+ *
+ * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
+ *
+ * @param string $address The email address to check
+ * @param string|callable $patternselect Which pattern to use
+ *
+ * @return bool
+ */
+ public static function validateAddress($address, $patternselect = null)
+ {
+ if (null === $patternselect) {
+ $patternselect = static::$validator;
+ }
+ //Don't allow strings as callables, see SECURITY.md and CVE-2021-3603
+ if (is_callable($patternselect) && !is_string($patternselect)) {
+ return call_user_func($patternselect, $address);
+ }
+ //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
+ if (strpos($address, "\n") !== false || strpos($address, "\r") !== false) {
+ return false;
+ }
+ switch ($patternselect) {
+ case 'pcre': //Kept for BC
+ case 'pcre8':
+ /*
+ * A more complex and more permissive version of the RFC5322 regex on which FILTER_VALIDATE_EMAIL
+ * is based.
+ * In addition to the addresses allowed by filter_var, also permits:
+ * * dotless domains: `a@b`
+ * * comments: `1234 @ local(blah) .machine .example`
+ * * quoted elements: `'"test blah"@example.org'`
+ * * numeric TLDs: `a@b.123`
+ * * unbracketed IPv4 literals: `a@192.168.0.1`
+ * * IPv6 literals: 'first.last@[IPv6:a1::]'
+ * Not all of these will necessarily work for sending!
+ *
+ * @copyright 2009-2010 Michael Rushton
+ * Feel free to use and redistribute this code. But please keep this copyright notice.
+ */
+ return (bool) preg_match(
+ '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
+ '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
+ '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
+ '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
+ '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
+ '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
+ '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
+ '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
+ '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
+ $address
+ );
+ case 'html5':
+ /*
+ * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
+ *
+ * @see https://html.spec.whatwg.org/#e-mail-state-(type=email)
+ */
+ return (bool) preg_match(
+ '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
+ '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
+ $address
+ );
+ case 'php':
+ default:
+ return filter_var($address, FILTER_VALIDATE_EMAIL) !== false;
+ }
+ }
+
+ /**
+ * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
+ * `intl` and `mbstring` PHP extensions.
+ *
+ * @return bool `true` if required functions for IDN support are present
+ */
+ public static function idnSupported()
+ {
+ return function_exists('idn_to_ascii') && function_exists('mb_convert_encoding');
+ }
+
+ /**
+ * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
+ * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
+ * This function silently returns unmodified address if:
+ * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
+ * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
+ * or fails for any reason (e.g. domain contains characters not allowed in an IDN).
+ *
+ * @see PHPMailer::$CharSet
+ *
+ * @param string $address The email address to convert
+ *
+ * @return string The encoded address in ASCII form
+ */
+ public function punyencodeAddress($address)
+ {
+ //Verify we have required functions, CharSet, and at-sign.
+ $pos = strrpos($address, '@');
+ if (
+ !empty($this->CharSet) &&
+ false !== $pos &&
+ static::idnSupported()
+ ) {
+ $domain = substr($address, ++$pos);
+ //Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
+ if ($this->has8bitChars($domain) && @mb_check_encoding($domain, $this->CharSet)) {
+ //Convert the domain from whatever charset it's in to UTF-8
+ $domain = mb_convert_encoding($domain, self::CHARSET_UTF8, $this->CharSet);
+ //Ignore IDE complaints about this line - method signature changed in PHP 5.4
+ $errorcode = 0;
+ if (defined('INTL_IDNA_VARIANT_UTS46')) {
+ //Use the current punycode standard (appeared in PHP 7.2)
+ $punycode = idn_to_ascii(
+ $domain,
+ \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI |
+ \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII,
+ \INTL_IDNA_VARIANT_UTS46
+ );
+ } elseif (defined('INTL_IDNA_VARIANT_2003')) {
+ //Fall back to this old, deprecated/removed encoding
+ $punycode = idn_to_ascii($domain, $errorcode, \INTL_IDNA_VARIANT_2003);
+ } else {
+ //Fall back to a default we don't know about
+ $punycode = idn_to_ascii($domain, $errorcode);
+ }
+ if (false !== $punycode) {
+ return substr($address, 0, $pos) . $punycode;
+ }
+ }
+ }
+
+ return $address;
+ }
+
+ /**
+ * Create a message and send it.
+ * Uses the sending method specified by $Mailer.
+ *
+ * @throws Exception
+ *
+ * @return bool false on error - See the ErrorInfo property for details of the error
+ */
+ public function send()
+ {
+ try {
+ if (!$this->preSend()) {
+ return false;
+ }
+
+ return $this->postSend();
+ } catch (Exception $exc) {
+ $this->mailHeader = '';
+ $this->setError($exc->getMessage());
+ if ($this->exceptions) {
+ throw $exc;
+ }
+
+ return false;
+ }
+ }
+
+ /**
+ * Prepare a message for sending.
+ *
+ * @throws Exception
+ *
+ * @return bool
+ */
+ public function preSend()
+ {
+ if (
+ 'smtp' === $this->Mailer
+ || ('mail' === $this->Mailer && (\PHP_VERSION_ID >= 80000 || stripos(PHP_OS, 'WIN') === 0))
+ ) {
+ //SMTP mandates RFC-compliant line endings
+ //and it's also used with mail() on Windows
+ static::setLE(self::CRLF);
+ } else {
+ //Maintain backward compatibility with legacy Linux command line mailers
+ static::setLE(PHP_EOL);
+ }
+ //Check for buggy PHP versions that add a header with an incorrect line break
+ if (
+ 'mail' === $this->Mailer
+ && ((\PHP_VERSION_ID >= 70000 && \PHP_VERSION_ID < 70017)
+ || (\PHP_VERSION_ID >= 70100 && \PHP_VERSION_ID < 70103))
+ && ini_get('mail.add_x_header') === '1'
+ && stripos(PHP_OS, 'WIN') === 0
+ ) {
+ trigger_error($this->lang('buggy_php'), E_USER_WARNING);
+ }
+
+ try {
+ $this->error_count = 0; //Reset errors
+ $this->mailHeader = '';
+
+ //Dequeue recipient and Reply-To addresses with IDN
+ foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
+ $params[1] = $this->punyencodeAddress($params[1]);
+ call_user_func_array([$this, 'addAnAddress'], $params);
+ }
+ if (count($this->to) + count($this->cc) + count($this->bcc) < 1) {
+ throw new Exception($this->lang('provide_address'), self::STOP_CRITICAL);
+ }
+
+ //Validate From, Sender, and ConfirmReadingTo addresses
+ foreach (['From', 'Sender', 'ConfirmReadingTo'] as $address_kind) {
+ if ($this->{$address_kind} === null) {
+ $this->{$address_kind} = '';
+ continue;
+ }
+ $this->{$address_kind} = trim($this->{$address_kind});
+ if (empty($this->{$address_kind})) {
+ continue;
+ }
+ $this->{$address_kind} = $this->punyencodeAddress($this->{$address_kind});
+ if (!static::validateAddress($this->{$address_kind})) {
+ $error_message = sprintf(
+ '%s (%s): %s',
+ $this->lang('invalid_address'),
+ $address_kind,
+ $this->{$address_kind}
+ );
+ $this->setError($error_message);
+ $this->edebug($error_message);
+ if ($this->exceptions) {
+ throw new Exception($error_message);
+ }
+
+ return false;
+ }
+ }
+
+ //Set whether the message is multipart/alternative
+ if ($this->alternativeExists()) {
+ $this->ContentType = static::CONTENT_TYPE_MULTIPART_ALTERNATIVE;
+ }
+
+ $this->setMessageType();
+ //Refuse to send an empty message unless we are specifically allowing it
+ if (!$this->AllowEmpty && empty($this->Body)) {
+ throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
+ }
+
+ //Trim subject consistently
+ $this->Subject = trim($this->Subject);
+ //Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
+ $this->MIMEHeader = '';
+ $this->MIMEBody = $this->createBody();
+ //createBody may have added some headers, so retain them
+ $tempheaders = $this->MIMEHeader;
+ $this->MIMEHeader = $this->createHeader();
+ $this->MIMEHeader .= $tempheaders;
+
+ //To capture the complete message when using mail(), create
+ //an extra header list which createHeader() doesn't fold in
+ if ('mail' === $this->Mailer) {
+ if (count($this->to) > 0) {
+ $this->mailHeader .= $this->addrAppend('To', $this->to);
+ } else {
+ $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
+ }
+ $this->mailHeader .= $this->headerLine(
+ 'Subject',
+ $this->encodeHeader($this->secureHeader($this->Subject))
+ );
+ }
+
+ //Sign with DKIM if enabled
+ if (
+ !empty($this->DKIM_domain)
+ && !empty($this->DKIM_selector)
+ && (!empty($this->DKIM_private_string)
+ || (!empty($this->DKIM_private)
+ && static::isPermittedPath($this->DKIM_private)
+ && file_exists($this->DKIM_private)
+ )
+ )
+ ) {
+ $header_dkim = $this->DKIM_Add(
+ $this->MIMEHeader . $this->mailHeader,
+ $this->encodeHeader($this->secureHeader($this->Subject)),
+ $this->MIMEBody
+ );
+ $this->MIMEHeader = static::stripTrailingWSP($this->MIMEHeader) . static::$LE .
+ static::normalizeBreaks($header_dkim) . static::$LE;
+ }
+
+ return true;
+ } catch (Exception $exc) {
+ $this->setError($exc->getMessage());
+ if ($this->exceptions) {
+ throw $exc;
+ }
+
+ return false;
+ }
+ }
+
+ /**
+ * Actually send a message via the selected mechanism.
+ *
+ * @throws Exception
+ *
+ * @return bool
+ */
+ public function postSend()
+ {
+ try {
+ //Choose the mailer and send through it
+ switch ($this->Mailer) {
+ case 'sendmail':
+ case 'qmail':
+ return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
+ case 'smtp':
+ return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
+ case 'mail':
+ return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
+ default:
+ $sendMethod = $this->Mailer . 'Send';
+ if (method_exists($this, $sendMethod)) {
+ return $this->{$sendMethod}($this->MIMEHeader, $this->MIMEBody);
+ }
+
+ return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
+ }
+ } catch (Exception $exc) {
+ $this->setError($exc->getMessage());
+ $this->edebug($exc->getMessage());
+ if ($this->Mailer === 'smtp' && $this->SMTPKeepAlive == true && $this->smtp->connected()) {
+ $this->smtp->reset();
+ }
+ if ($this->exceptions) {
+ throw $exc;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Send mail using the $Sendmail program.
+ *
+ * @see PHPMailer::$Sendmail
+ *
+ * @param string $header The message headers
+ * @param string $body The message body
+ *
+ * @throws Exception
+ *
+ * @return bool
+ */
+ protected function sendmailSend($header, $body)
+ {
+ if ($this->Mailer === 'qmail') {
+ $this->edebug('Sending with qmail');
+ } else {
+ $this->edebug('Sending with sendmail');
+ }
+ $header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
+ //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
+ //A space after `-f` is optional, but there is a long history of its presence
+ //causing problems, so we don't use one
+ //Exim docs: https://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
+ //Sendmail docs: https://www.sendmail.org/~ca/email/man/sendmail.html
+ //Example problem: https://www.drupal.org/node/1057954
+
+ //PHP 5.6 workaround
+ $sendmail_from_value = ini_get('sendmail_from');
+ if (empty($this->Sender) && !empty($sendmail_from_value)) {
+ //PHP config has a sender address we can use
+ $this->Sender = ini_get('sendmail_from');
+ }
+ //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
+ if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) {
+ if ($this->Mailer === 'qmail') {
+ $sendmailFmt = '%s -f%s';
+ } else {
+ $sendmailFmt = '%s -oi -f%s -t';
+ }
+ } else {
+ //allow sendmail to choose a default envelope sender. It may
+ //seem preferable to force it to use the From header as with
+ //SMTP, but that introduces new problems (see
+ //), and
+ //it has historically worked this way.
+ $sendmailFmt = '%s -oi -t';
+ }
+
+ $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
+ $this->edebug('Sendmail path: ' . $this->Sendmail);
+ $this->edebug('Sendmail command: ' . $sendmail);
+ $this->edebug('Envelope sender: ' . $this->Sender);
+ $this->edebug("Headers: {$header}");
+
+ if ($this->SingleTo) {
+ foreach ($this->SingleToArray as $toAddr) {
+ $mail = @popen($sendmail, 'w');
+ if (!$mail) {
+ throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ $this->edebug("To: {$toAddr}");
+ fwrite($mail, 'To: ' . $toAddr . "\n");
+ fwrite($mail, $header);
+ fwrite($mail, $body);
+ $result = pclose($mail);
+ $addrinfo = static::parseAddresses($toAddr, true, $this->CharSet);
+ $this->doCallback(
+ ($result === 0),
+ [[$addrinfo['address'], $addrinfo['name']]],
+ $this->cc,
+ $this->bcc,
+ $this->Subject,
+ $body,
+ $this->From,
+ []
+ );
+ $this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
+ if (0 !== $result) {
+ throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ }
+ } else {
+ $mail = @popen($sendmail, 'w');
+ if (!$mail) {
+ throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ fwrite($mail, $header);
+ fwrite($mail, $body);
+ $result = pclose($mail);
+ $this->doCallback(
+ ($result === 0),
+ $this->to,
+ $this->cc,
+ $this->bcc,
+ $this->Subject,
+ $body,
+ $this->From,
+ []
+ );
+ $this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
+ if (0 !== $result) {
+ throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
+ * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
+ *
+ * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
+ *
+ * @param string $string The string to be validated
+ *
+ * @return bool
+ */
+ protected static function isShellSafe($string)
+ {
+ //It's not possible to use shell commands safely (which includes the mail() function) without escapeshellarg,
+ //but some hosting providers disable it, creating a security problem that we don't want to have to deal with,
+ //so we don't.
+ if (!function_exists('escapeshellarg') || !function_exists('escapeshellcmd')) {
+ return false;
+ }
+
+ if (
+ escapeshellcmd($string) !== $string
+ || !in_array(escapeshellarg($string), ["'$string'", "\"$string\""])
+ ) {
+ return false;
+ }
+
+ $length = strlen($string);
+
+ for ($i = 0; $i < $length; ++$i) {
+ $c = $string[$i];
+
+ //All other characters have a special meaning in at least one common shell, including = and +.
+ //Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
+ //Note that this does permit non-Latin alphanumeric characters based on the current locale.
+ if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Check whether a file path is of a permitted type.
+ * Used to reject URLs and phar files from functions that access local file paths,
+ * such as addAttachment.
+ *
+ * @param string $path A relative or absolute path to a file
+ *
+ * @return bool
+ */
+ protected static function isPermittedPath($path)
+ {
+ //Matches scheme definition from https://tools.ietf.org/html/rfc3986#section-3.1
+ return !preg_match('#^[a-z][a-z\d+.-]*://#i', $path);
+ }
+
+ /**
+ * Check whether a file path is safe, accessible, and readable.
+ *
+ * @param string $path A relative or absolute path to a file
+ *
+ * @return bool
+ */
+ protected static function fileIsAccessible($path)
+ {
+ if (!static::isPermittedPath($path)) {
+ return false;
+ }
+ $readable = is_file($path);
+ //If not a UNC path (expected to start with \\), check read permission, see #2069
+ if (strpos($path, '\\\\') !== 0) {
+ $readable = $readable && is_readable($path);
+ }
+ return $readable;
+ }
+
+ /**
+ * Send mail using the PHP mail() function.
+ *
+ * @see https://www.php.net/manual/en/book.mail.php
+ *
+ * @param string $header The message headers
+ * @param string $body The message body
+ *
+ * @throws Exception
+ *
+ * @return bool
+ */
+ protected function mailSend($header, $body)
+ {
+ $header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
+
+ $toArr = [];
+ foreach ($this->to as $toaddr) {
+ $toArr[] = $this->addrFormat($toaddr);
+ }
+ $to = trim(implode(', ', $toArr));
+
+ //If there are no To-addresses (e.g. when sending only to BCC-addresses)
+ //the following should be added to get a correct DKIM-signature.
+ //Compare with $this->preSend()
+ if ($to === '') {
+ $to = 'undisclosed-recipients:;';
+ }
+
+ $params = null;
+ //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
+ //A space after `-f` is optional, but there is a long history of its presence
+ //causing problems, so we don't use one
+ //Exim docs: https://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
+ //Sendmail docs: https://www.sendmail.org/~ca/email/man/sendmail.html
+ //Example problem: https://www.drupal.org/node/1057954
+ //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
+
+ //PHP 5.6 workaround
+ $sendmail_from_value = ini_get('sendmail_from');
+ if (empty($this->Sender) && !empty($sendmail_from_value)) {
+ //PHP config has a sender address we can use
+ $this->Sender = ini_get('sendmail_from');
+ }
+ if (!empty($this->Sender) && static::validateAddress($this->Sender)) {
+ if (self::isShellSafe($this->Sender)) {
+ $params = sprintf('-f%s', $this->Sender);
+ }
+ $old_from = ini_get('sendmail_from');
+ ini_set('sendmail_from', $this->Sender);
+ }
+ $result = false;
+ if ($this->SingleTo && count($toArr) > 1) {
+ foreach ($toArr as $toAddr) {
+ $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
+ $addrinfo = static::parseAddresses($toAddr, true, $this->CharSet);
+ $this->doCallback(
+ $result,
+ [[$addrinfo['address'], $addrinfo['name']]],
+ $this->cc,
+ $this->bcc,
+ $this->Subject,
+ $body,
+ $this->From,
+ []
+ );
+ }
+ } else {
+ $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
+ $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From, []);
+ }
+ if (isset($old_from)) {
+ ini_set('sendmail_from', $old_from);
+ }
+ if (!$result) {
+ throw new Exception($this->lang('instantiate'), self::STOP_CRITICAL);
+ }
+
+ return true;
+ }
+
+ /**
+ * Get an instance to use for SMTP operations.
+ * Override this function to load your own SMTP implementation,
+ * or set one with setSMTPInstance.
+ *
+ * @return SMTP
+ */
+ public function getSMTPInstance()
+ {
+ if (!is_object($this->smtp)) {
+ $this->smtp = new SMTP();
+ }
+
+ return $this->smtp;
+ }
+
+ /**
+ * Provide an instance to use for SMTP operations.
+ *
+ * @return SMTP
+ */
+ public function setSMTPInstance(SMTP $smtp)
+ {
+ $this->smtp = $smtp;
+
+ return $this->smtp;
+ }
+
+ /**
+ * Provide SMTP XCLIENT attributes
+ *
+ * @param string $name Attribute name
+ * @param ?string $value Attribute value
+ *
+ * @return bool
+ */
+ public function setSMTPXclientAttribute($name, $value)
+ {
+ if (!in_array($name, SMTP::$xclient_allowed_attributes)) {
+ return false;
+ }
+ if (isset($this->SMTPXClient[$name]) && $value === null) {
+ unset($this->SMTPXClient[$name]);
+ } elseif ($value !== null) {
+ $this->SMTPXClient[$name] = $value;
+ }
+
+ return true;
+ }
+
+ /**
+ * Get SMTP XCLIENT attributes
+ *
+ * @return array
+ */
+ public function getSMTPXclientAttributes()
+ {
+ return $this->SMTPXClient;
+ }
+
+ /**
+ * Send mail via SMTP.
+ * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
+ *
+ * @see PHPMailer::setSMTPInstance() to use a different class.
+ *
+ * @uses \PHPMailer\PHPMailer\SMTP
+ *
+ * @param string $header The message headers
+ * @param string $body The message body
+ *
+ * @throws Exception
+ *
+ * @return bool
+ */
+ protected function smtpSend($header, $body)
+ {
+ $header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
+ $bad_rcpt = [];
+ if (!$this->smtpConnect($this->SMTPOptions)) {
+ throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
+ }
+ //Sender already validated in preSend()
+ if ('' === $this->Sender) {
+ $smtp_from = $this->From;
+ } else {
+ $smtp_from = $this->Sender;
+ }
+ if (count($this->SMTPXClient)) {
+ $this->smtp->xclient($this->SMTPXClient);
+ }
+ if (!$this->smtp->mail($smtp_from)) {
+ $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
+ throw new Exception($this->ErrorInfo, self::STOP_CRITICAL);
+ }
+
+ $callbacks = [];
+ //Attempt to send to all recipients
+ foreach ([$this->to, $this->cc, $this->bcc] as $togroup) {
+ foreach ($togroup as $to) {
+ if (!$this->smtp->recipient($to[0], $this->dsn)) {
+ $error = $this->smtp->getError();
+ $bad_rcpt[] = ['to' => $to[0], 'error' => $error['detail']];
+ $isSent = false;
+ } else {
+ $isSent = true;
+ }
+
+ $callbacks[] = ['issent' => $isSent, 'to' => $to[0], 'name' => $to[1]];
+ }
+ }
+
+ //Only send the DATA command if we have viable recipients
+ if ((count($this->all_recipients) > count($bad_rcpt)) && !$this->smtp->data($header . $body)) {
+ throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL);
+ }
+
+ $smtp_transaction_id = $this->smtp->getLastTransactionID();
+
+ if ($this->SMTPKeepAlive) {
+ $this->smtp->reset();
+ } else {
+ $this->smtp->quit();
+ $this->smtp->close();
+ }
+
+ foreach ($callbacks as $cb) {
+ $this->doCallback(
+ $cb['issent'],
+ [[$cb['to'], $cb['name']]],
+ [],
+ [],
+ $this->Subject,
+ $body,
+ $this->From,
+ ['smtp_transaction_id' => $smtp_transaction_id]
+ );
+ }
+
+ //Create error message for any bad addresses
+ if (count($bad_rcpt) > 0) {
+ $errstr = '';
+ foreach ($bad_rcpt as $bad) {
+ $errstr .= $bad['to'] . ': ' . $bad['error'];
+ }
+ throw new Exception($this->lang('recipients_failed') . $errstr, self::STOP_CONTINUE);
+ }
+
+ return true;
+ }
+
+ /**
+ * Initiate a connection to an SMTP server.
+ * Returns false if the operation failed.
+ *
+ * @param array $options An array of options compatible with stream_context_create()
+ *
+ * @throws Exception
+ *
+ * @uses \PHPMailer\PHPMailer\SMTP
+ *
+ * @return bool
+ */
+ public function smtpConnect($options = null)
+ {
+ if (null === $this->smtp) {
+ $this->smtp = $this->getSMTPInstance();
+ }
+
+ //If no options are provided, use whatever is set in the instance
+ if (null === $options) {
+ $options = $this->SMTPOptions;
+ }
+
+ //Already connected?
+ if ($this->smtp->connected()) {
+ return true;
+ }
+
+ $this->smtp->setTimeout($this->Timeout);
+ $this->smtp->setDebugLevel($this->SMTPDebug);
+ $this->smtp->setDebugOutput($this->Debugoutput);
+ $this->smtp->setVerp($this->do_verp);
+ if ($this->Host === null) {
+ $this->Host = 'localhost';
+ }
+ $hosts = explode(';', $this->Host);
+ $lastexception = null;
+
+ foreach ($hosts as $hostentry) {
+ $hostinfo = [];
+ if (
+ !preg_match(
+ '/^(?:(ssl|tls):\/\/)?(.+?)(?::(\d+))?$/',
+ trim($hostentry),
+ $hostinfo
+ )
+ ) {
+ $this->edebug($this->lang('invalid_hostentry') . ' ' . trim($hostentry));
+ //Not a valid host entry
+ continue;
+ }
+ //$hostinfo[1]: optional ssl or tls prefix
+ //$hostinfo[2]: the hostname
+ //$hostinfo[3]: optional port number
+ //The host string prefix can temporarily override the current setting for SMTPSecure
+ //If it's not specified, the default value is used
+
+ //Check the host name is a valid name or IP address before trying to use it
+ if (!static::isValidHost($hostinfo[2])) {
+ $this->edebug($this->lang('invalid_host') . ' ' . $hostinfo[2]);
+ continue;
+ }
+ $prefix = '';
+ $secure = $this->SMTPSecure;
+ $tls = (static::ENCRYPTION_STARTTLS === $this->SMTPSecure);
+ if ('ssl' === $hostinfo[1] || ('' === $hostinfo[1] && static::ENCRYPTION_SMTPS === $this->SMTPSecure)) {
+ $prefix = 'ssl://';
+ $tls = false; //Can't have SSL and TLS at the same time
+ $secure = static::ENCRYPTION_SMTPS;
+ } elseif ('tls' === $hostinfo[1]) {
+ $tls = true;
+ //TLS doesn't use a prefix
+ $secure = static::ENCRYPTION_STARTTLS;
+ }
+ //Do we need the OpenSSL extension?
+ $sslext = defined('OPENSSL_ALGO_SHA256');
+ if (static::ENCRYPTION_STARTTLS === $secure || static::ENCRYPTION_SMTPS === $secure) {
+ //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
+ if (!$sslext) {
+ throw new Exception($this->lang('extension_missing') . 'openssl', self::STOP_CRITICAL);
+ }
+ }
+ $host = $hostinfo[2];
+ $port = $this->Port;
+ if (
+ array_key_exists(3, $hostinfo) &&
+ is_numeric($hostinfo[3]) &&
+ $hostinfo[3] > 0 &&
+ $hostinfo[3] < 65536
+ ) {
+ $port = (int) $hostinfo[3];
+ }
+ if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
+ try {
+ if ($this->Helo) {
+ $hello = $this->Helo;
+ } else {
+ $hello = $this->serverHostname();
+ }
+ $this->smtp->hello($hello);
+ //Automatically enable TLS encryption if:
+ //* it's not disabled
+ //* we are not connecting to localhost
+ //* we have openssl extension
+ //* we are not already using SSL
+ //* the server offers STARTTLS
+ if (
+ $this->SMTPAutoTLS &&
+ $this->Host !== 'localhost' &&
+ $sslext &&
+ $secure !== 'ssl' &&
+ $this->smtp->getServerExt('STARTTLS')
+ ) {
+ $tls = true;
+ }
+ if ($tls) {
+ if (!$this->smtp->startTLS()) {
+ $message = $this->getSmtpErrorMessage('connect_host');
+ throw new Exception($message);
+ }
+ //We must resend EHLO after TLS negotiation
+ $this->smtp->hello($hello);
+ }
+ if (
+ $this->SMTPAuth && !$this->smtp->authenticate(
+ $this->Username,
+ $this->Password,
+ $this->AuthType,
+ $this->oauth
+ )
+ ) {
+ throw new Exception($this->lang('authenticate'));
+ }
+
+ return true;
+ } catch (Exception $exc) {
+ $lastexception = $exc;
+ $this->edebug($exc->getMessage());
+ //We must have connected, but then failed TLS or Auth, so close connection nicely
+ $this->smtp->quit();
+ }
+ }
+ }
+ //If we get here, all connection attempts have failed, so close connection hard
+ $this->smtp->close();
+ //As we've caught all exceptions, just report whatever the last one was
+ if ($this->exceptions && null !== $lastexception) {
+ throw $lastexception;
+ }
+ if ($this->exceptions) {
+ // no exception was thrown, likely $this->smtp->connect() failed
+ $message = $this->getSmtpErrorMessage('connect_host');
+ throw new Exception($message);
+ }
+
+ return false;
+ }
+
+ /**
+ * Close the active SMTP session if one exists.
+ */
+ public function smtpClose()
+ {
+ if ((null !== $this->smtp) && $this->smtp->connected()) {
+ $this->smtp->quit();
+ $this->smtp->close();
+ }
+ }
+
+ /**
+ * Set the language for error messages.
+ * The default language is English.
+ *
+ * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
+ * Optionally, the language code can be enhanced with a 4-character
+ * script annotation and/or a 2-character country annotation.
+ * @param string $lang_path Path to the language file directory, with trailing separator (slash)
+ * Do not set this from user input!
+ *
+ * @return bool Returns true if the requested language was loaded, false otherwise.
+ */
+ public function setLanguage($langcode = 'en', $lang_path = '')
+ {
+ //Backwards compatibility for renamed language codes
+ $renamed_langcodes = [
+ 'br' => 'pt_br',
+ 'cz' => 'cs',
+ 'dk' => 'da',
+ 'no' => 'nb',
+ 'se' => 'sv',
+ 'rs' => 'sr',
+ 'tg' => 'tl',
+ 'am' => 'hy',
+ ];
+
+ if (array_key_exists($langcode, $renamed_langcodes)) {
+ $langcode = $renamed_langcodes[$langcode];
+ }
+
+ //Define full set of translatable strings in English
+ $PHPMAILER_LANG = [
+ 'authenticate' => 'SMTP Error: Could not authenticate.',
+ 'buggy_php' => 'Your version of PHP is affected by a bug that may result in corrupted messages.' .
+ ' To fix it, switch to sending using SMTP, disable the mail.add_x_header option in' .
+ ' your php.ini, switch to MacOS or Linux, or upgrade your PHP to version 7.0.17+ or 7.1.3+.',
+ 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
+ 'data_not_accepted' => 'SMTP Error: data not accepted.',
+ 'empty_message' => 'Message body empty',
+ 'encoding' => 'Unknown encoding: ',
+ 'execute' => 'Could not execute: ',
+ 'extension_missing' => 'Extension missing: ',
+ 'file_access' => 'Could not access file: ',
+ 'file_open' => 'File Error: Could not open file: ',
+ 'from_failed' => 'The following From address failed: ',
+ 'instantiate' => 'Could not instantiate mail function.',
+ 'invalid_address' => 'Invalid address: ',
+ 'invalid_header' => 'Invalid header name or value',
+ 'invalid_hostentry' => 'Invalid hostentry: ',
+ 'invalid_host' => 'Invalid host: ',
+ 'mailer_not_supported' => ' mailer is not supported.',
+ 'provide_address' => 'You must provide at least one recipient email address.',
+ 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
+ 'signing' => 'Signing Error: ',
+ 'smtp_code' => 'SMTP code: ',
+ 'smtp_code_ex' => 'Additional SMTP info: ',
+ 'smtp_connect_failed' => 'SMTP connect() failed.',
+ 'smtp_detail' => 'Detail: ',
+ 'smtp_error' => 'SMTP server error: ',
+ 'variable_set' => 'Cannot set or reset variable: ',
+ ];
+ if (empty($lang_path)) {
+ //Calculate an absolute path so it can work if CWD is not here
+ $lang_path = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR;
+ }
+
+ //Validate $langcode
+ $foundlang = true;
+ $langcode = strtolower($langcode);
+ if (
+ !preg_match('/^(?P[a-z]{2})(?P
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Aproximando médicos e pacientes
+
Segurança, Confiabilidade e
+ Rapidez
+
Experimente o futuro
+ dos agendamentos. Encontre profissionais capacitados e marque já sua consulta.
+
+
+
+ 📄 Laudos digitais e padronizados
+ 🔔 Notificações automáticas ao paciente
+
+
+
+
+
+
+
+
+
+
🔒 LGPD: controle de acesso e consentimento
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Sobre nós
+
Experimente o futuro do gerenciamento dos
+ seus atendimentos médicos
+
+
Somos uma plataforma inovadora que conecta pacientes e médicos de forma prática, segura e
+ humanizada. Nosso objetivo é simplificar o processo de emissão e acompanhamento de laudos médicos,
+ oferecendo um ambiente online confiável e acessível.
+
+
Aqui, os pacientes podem registrar suas informações de saúde e solicitar laudos de forma rápida,
+ enquanto os médicos têm acesso a ferramentas que facilitam a análise, validação e emissão dos
+ documentos.
+
+
Nossos valores
+
+ Inovação
+ Segurança
+ Discrição
+ Transparência
+ Agilidade
+
+
+
+
+
+
+
+
+
+
Nosso objetivo
+
Nosso compromisso é garantir qualidade, segurança e sigilo em cada atendimento,
+ unindo tecnologia à responsabilidade médica.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+